In this article, we examined the Microsoft Hyper-V control problems when managing the hypervisor with the help of the C++ language and WMI technology.
The attached example represents a small library of classes for managing Microsoft Hyper-V hypervisor and a test application, which uses the part of the library functionality.
Contents:
1. Introduction
1.1. The notion of hypervisor. Brief survey of existing products
Hypervisor, also called virtual machine monitor (VMM), is the special software that allows running several operating systems (OS) on the single physical computer. For each of these operating systems, the hypervisor creates an illusion of functioning on its own physical computer, which is called the virtual machine (VM).
The operating system, on which the hypervisor works, is called the host OS, and operating systems that are launched on virtual machines are called guest OS. The hypervisor monitors the work of guest OS and influences the process of their launching (unnoticeably for these OS) in that way to eliminate conflicts between them and the host OS.
There are two types of hypervisors:
- Native or bare-metal hypervisors, which work directly with the computer hardware and do not require the presence of the conventional OS (such hypervisors are the operating systems in some way or they can be implemented on the basis of some cut universal OS).
- Hosted hypervisors, which are the software that is running within a conventional OS (such as Windows or Linux).
Examples of hypervisors of the first type are the Microsoft Hyper-V (as a part of Windows Server 2008 (R2) and the self-contained version โ Microsoft Hyper-V Server 2008 (R2)), VMware ESX(i), Citrix XenServer and others. The hypervisors of the second type are the VMware Workstation, Oracle (the former Sun) VirtualBox, Microsoft Virtual PC and others.
1.2. Microsoft Hyper-V hypervisor
Microsoft Hyper-V hypervisor was introduced in 2008 as a part of Windows Server 2008 and also was released as a free stand-alone version โ Microsoft Hyper-V Server 2008. It is also included into the R2 (Release 2) version of these products. Hyper-V functions only on x86-64-compatible processors (the IA-64 architecture is not supported) with the AMD64/EM64T technology, which support the virtualization technology (AMD-V or Intel VT).
For Windows Server 2008 (R2), the hypervisor is installed as a separate role. It is managed through the standard management console. Also the program control of the hypervisor is possible by means of Microsoft WMI technology.
2. The Microsoft Hyper-V program control
2.1. WMI technology
WMItechnology (Windows Management Instrumentation) is Microsoft’s implementation of the Web-Based Enterprise Management (WBEM) and Common Information Model (CIM) standards from the Distributed Management Task Force (DMTF). WMI is a program infrastructure for managing various Windows OS components and also third-party products. The WMI technology is designed with taking into account its possible usage with different programming language: C/C++, Visual Basic, scripting languages (such as VBScript or JScript) and languages that belong to .NET family (for example, C#). Thus, developers can use WMI in their programs for performing specific tasks and administrators can use it in their scripts to optimize their chores. WMI allows managing both local and remote computers.
COM/DCOM technologies are the basis of WMI technology, so it is useful to know them well before studying WMI. WMI uses object-oriented model, where managed components are represented as the set of connected objects with their own properties and methods. All objects form the object database, which is called the CIM repository. A special SQL-like query language โ WQL (WMI Query Language) โ is used for managing the repository.
Special program component (called WMI provider) is required if some Windows component or application should support WMI management interface. Microsoft supplies the Windows OS with the set of standard WMI providers, such as Active Directory Provider, DNS Provider, Event Log Provider, Security Provider, System Registry Provider, Virtualization Provider, Windows Installer Provider, and others. Besides, such products as SQL Server, Exchange Server also install their own WMI providers.
Virtualization Provider is designed for managing Microsoft Hyper-V hypervisor and will be examined in detail in the article.
I recommend you to acquaint yourselves with the WMI fundamentals before using this technology for interaction with Virtualization Provider or any other provider.
2.2. Description of main WMI objects for Hyper-V management
Letโs briefly examine some WMI classes provided by the virtualization provider.
The Msvm_ComputerSystem
WMI class is the basis of the Hyper-V object model. This class represents either a physical, or a virtual machine. The class has a lot of properties but letโs examine some of them:
Caption
contains “Virtual Machine” string if the class represents a virtual machine or “Hosting Computer System” string if it is a physical machine. We can distinguish virtual and physical machines by this property value when we write WQL queries to the provider.ElementName
contains the display name of the virtual machine (it is displayed in the list of virtual machines in the manager console) or its NETBIOS name if it is a physical machine.Name
contains a unique identifier (GUID) of virtual machine.EnabledState
defines the state of the virtual machine (stopped, running, paused, etc.).
The RequestStateChange
method of the Msvm_ComputerSystem
class allows modifying the state of the virtual machine (for example, to launch or to stop it).
The Msvm_VirtualSystemManagementService
class represents a virtualization service and is used for creating, deleting, and modifying virtual machines, and also for creating virtual machine snapshots, exporting and importing VMs. Letโs examine some methods of this class:
DefineVirtualSystem
,DestroyVirtualSystem
,ModifyVirtualSystem
methods are used for creating, deleting, and modifying VMs, respectively.CreateVirtualSystemSnapshot
,ApplyVirtualSystemSnapshot(Ex)
,RemoveVirtualSystemSnapshot
methods aim at snapshots creation, rollback to a snapshot, and snapshot deletion, respectively.ExportVirtualSystem(Ex)
andImportVirtualSystem(Ex)
methods aim at VM export and import.
The Msvm_VirtualSystemSettingData
class provides a set of properties, which represent the low-level settings of the VM, for example:
AutoActivate
โ it defines if the VM should start automatically at the hypervisor startup.BIOSNumLock
โ it defines the state of the Num Lock key during the VM starting.BootOrder
โ it defines the order of boot devices (hard drive, CD-ROM, etc.).
Each instance of the Msvm_VirtualSystemSettingData
class corresponds either to the VM itself, or to one of its snapshots. It is defined by the value of the SettingType
property (value 3 corresponds to a VM, 5 corresponds to a snapshot). The SystemName
property contains the GUID of the VM, which corresponds to the given instance of the Msvm_VirtualSystemSettingData
class. Thus, we can find all snapshots of the given VM by means of filtering all instances of the Msvm_VirtualSystemSettingData
class by the values of SystemName
and SettingType
properties.
The Msvm_ResourceAllocationSettingData
class represents virtual resources, which are associated with some VM, for example, virtual hard drive, IDE controller, network adapter, COM port, etc. The ResourceType
property defines the type of this resource and the Connection
property defines which โphysical entityโ corresponds to this resource. Thus, for the virtual drive, this property contains the path to the corresponding VHD file (disk image).
For more information about these and other classes, see MSDN.
2.3. Connecting to a hypervisor
Letโs examine how we can implement basic Hyper-V management operations using C++. As the WMI technology is based on COM, we will use the ATL
library (ATL โ Active Template Library โ is a part of the Microsoft Visual Studio and contains a large toolset, which can be used to solve typical development tasks within the bounds of COM development)). Actually, we will use only some simple wrapper classes for the COM types, such as CComPtr
(a โsmartโ pointer to COM interfaces, which automatically calls the AddRef
and Release
methods of the interfaces) and CComBSTR
(a wrapper for the BSTR string type).
Also we will define the auxiliary CHK_HRES
macro (from โcheck HRESULTโ), which is intended for COM errors checking. Each COM method must return the special status of the HRESULT
type. We could analyze this status after each call of the COM method and perform the corresponding handling. But for the code facilitation, it is better to use the macro, which automatically analyzes the status and throws an exception in case of an error. The CHK_HRES
macro is defined in the following way:
#define CHK_HRES(op)
{
HRESULT tmp_hresult___ = op;
if (FAILED(tmp_hresult___))
throw CAtlException(tmp_hresult___);
}
CAtlException
exception class, which just stores the corresponding HRESULT
status. We can process thrown exception in any suitable place. We will use the CHK_HRES
macro in the following way:
CHK_HRES(pObject->Method());
So, letโs proceed to the first task, namely, connecting to a hypervisor:
CComBSTR namespacePath = L"";
namespacePath += pServer;
namespacePath += L"rootvirtualization";
CComPtr<IWbemLocator> pWbemLocator;
CHK_HRES(pWbemLocator.CoCreateInstance(CLSID_WbemLocator,
NULL,
CLSCTX_INPROC_SERVER));
CComPtr<IWbemServices> pWbemServices;
CHK_HRES(pWbemLocator->ConnectServer(
namespacePath,
CComBSTR(pUserName),
CComBSTR(pPassword),
NULL,
0,
NULL,
NULL,
&pWbemServices
));
In this very example, the pServer
is a string containing the network address of the Hyper-V server. It can be the IP address or the name of the computer in the network. pUserName
is the user name and pPassword
is the user password, which are used to connect to the server. The user name can be of the โDOMAINUSERโ form. If we pass NULL
to the ConnectServer
method as the user name and the user password, then current user will be used for the connection.
The ConnectServer
method returns the pointer (pWbemServices
) to the IWbemServices
WMI interface, which represents the WMI services that are provided by the given Hyper-V server.
To disconnect from the server, we should release the pointer to the IWbemServices
interface by calling the Release
method (the CComPtr
class performs it automatically in its destructor).
2.4. Obtaining the list of virtual machines
To obtain the list of all virtual machines of the server, it is necessary to form the corresponding WQL query. As it was mentioned in the section 2.2, the Msvm_ComputerSystem
WMI class corresponds to virtual machines. But as this class can represent not only the virtual machine but also the Hyper-V server itself, we should filter objects by the value of the Caption
property:
CComPtr<IEnumWbemClassObject> pEnumWbemClassObject;
CHK_HRES(m_pWbemServices->ExecQuery(
CComBSTR(L"WQL"),
CComBSTR(L"select * from Msvm_ComputerSystem where Caption="Virtual Machine""),
WBEM_FLAG_FORWARD_ONLY,
NULL,
&pEnumWbemClassObject
));
while (true)
{
CComPtr<IWbemClassObject> pCurVM;
ULONG returnCount = 0;
CHK_HRES(pEnumWbemClassObject->Next(WBEM_INFINITE,
1,
&pCurVM,
&returnCount));
if (returnCount == 0)
break;
// Do something with pCurVM
// ...
}
In this example, we use the ExecQuery
method of the IWbemServices
interface, which allows performing some WQL query and returns the result in the form of enumerator object. The last implements the IEnumWbemClassObject
WMI interface. We can receive the list of objects, which implement the IWbemClassObject
WMI interface, by using this enumerator. In our case, these will be the objects that represent the virtual machines.
2.5. Obtaining the properties of the virtual machine
The IWbemClassObject
interface has the Get
method, which allows obtaining the values of the corresponding object properties. The properties can be of different types (for example, string or number) but there is a single method for all of them. So, the method returns the values of properties in the form of VARIANT COM
type, which allows representing the values of different types. We will use the CComVariant
class โ the ATL wrapper for the VARIANT
type.
CComPtr<IWbemClassObject> pVmObject;
...
CComVariant name;
CHK_HRES(pVmObject->Get(L"Name", 0, &name, NULL, NULL));
if (name.vt == VT_BSTR)
{
// Use virtual machineโs UUID
// ...
}
else
{
// Invalid property type
// ...
}
In the example above, we get the value of the Name
property (the unique identifier) of the pVmObject
virtual machine. We expect that the value of this property will be returned as a string. That is why it is better to check if we got the value of the required type in the Name
variable to ensure the code reliability.
This code can be used for obtaining the properties of other objects that are represented by the IWbemClassObject
interface (not only for virtual machines).
2.6. Start, stop and status check of the virtual machine
Now we can read the properties of the virtual machine and know its state. The Msvm_ComputerSystem
class has the EnabledState
property. Its value is some number, which characterizes the current state of the virtual machine. There is a set of reserved constants describing different states of the VM. For example, 2 means that the VM is launched, 3 means that it is shut down (for more information, see MSDN).
That is why, it is enough to read the EnabledState
property of the VM (the Get
method must return the VT_14 VARIANT
type value) and to compare it with 2 in order to check if the virtual machine is launched at the moment.
Letโs move to more difficult things. You cannot change the value of the EnabledState
property to launch or stop the VM, because this property is read only. The Msvm_ComputerSystem
class has the RequestStateChange
method for changing the VM state.
The call of the WMI method is more complicated task than obtaining the property. To call the method, we should do the following:
- Get the object that represents the input parameters of the method.
- Set the values of the input parameters by setting the values of the corresponding properties of this object.
- Call the method and receive the object that represents the output parameters of the method if necessary.
- Obtain the values of the output parameters by reading the values of corresponding properties of this object.
So, letโs obtain the object that represents the input parameters of the RequestStateChange
method.
CComPtr<IWbemClassObject> pClass;
CComPtr<IWbemClassObject> pInParamsDefinition;
CComPtr<IWbemClassObject> pInParams;
CHK_HRES(pWbemServices->GetObject(CComBSTR(L"Msvm_ComputerSystem"),
0, NULL, &pClass, NULL));
CHK_HRES(pClass->GetMethod(pMethodName, 0, &pInParamsDefinition, NULL));
CHK_HRES(pInParamsDefinition->SpawnInstance(0, &pInParams));
First, we obtain the pointer to the object, which represents the Msvm_ComputerSystem
class, with the help of the GetObject
method. This object does not correspond to some definite virtual machine or server but represents the class itself.
Then, with the help of the GetMethod
, we obtain the information about the input parameters of the required method. This information is contained in the object, to which the pInParamsDefinition
pointer refers (we do not obtain the information about the output parameters in this example because we are not interested in them).
And finally, with the help of the SpawnInstance
method, we create an object that represents the values of the input parameters.
Now we can set the values of the input parameters of the RequestStateChange
method. We have only one such parameter. This is the RequestState
parameter. It can possess the same values as the EnabledState
property of the Msvm_ComputerSystem
class does.
CHK_HRES(pInParams->Put(L"RequestedState", 0, &CComVariant(state), 0));
Here state
is the state code of the VM, which we are going to set. Now almost everything is ready for the call of the method:
CComVariant path;
CHK_HRES(pVmObject->Get(L"__PATH&, 0, &path, NULL, NULL));
CComPtr<IWbemClassObject> pOutParams;
CHK_HRES(m_pWbemServices->ExecMethod(path.bstrVal,
CComBSTR(L"RequestStateChange"),
0,
NULL,
pInParams,
&pOutParams,
NULL));
We use the ExecMethod
method of the IWbemServices
interface to call the method of the Msvm_ComputerSystem
class. ExecMethod
receives such parameters: repository path to the object, whose method should be called (we receive the object path of the VM by reading its __PATH
property); the method name; and the pointer to the object, which stores the values of the input parameters. After performing, the ExecMethod
returns the pointer to the object, which stores the values of the output parameters. We can obtain the values of the output parameters by reading the corresponding properties of this object.
RequestStateChange
has the Job
output parameter. It contains the reference to the object, with the help of which you can track the task execution if the method is performed asynchronously. But we will not dwell on it. The example of using this parameter is in the file attached to the article.
It is worth mentioning that by changing the state of the VM to Disabled (3), we will shut it down without saving any data (as if we unplugged the power cable of the physical computer). In most cases, we would like to shut down the VM in a more delicate way, for example, by means of the guest OS (as if we clicked Start โ Shut Down
in the guest OS). Luckily, Hyper-V gives such opportunity and provides the special Msvm_ShutdownComponent
class for these purposes.
The Msvm_ShutdownComponent
class has the InitiateShutdown
method, which initiates the VM shutdown (as it follows from its name). But in order to use it, we must find the instance of the Msvm_ShutdownComponent
class, which corresponds to our virtual machine. The instances of the Msvm_ComputerSystem
and Msvm_ShutdownComponent
classes do not refer one to another but they are connected via the special Msvm_SystemDevice
class. In the WMI terminology, the instance of the Msvm_ShutdownComponent
class is associated with the instance of the Msvm_ComputerSystem
class. There is a special ASSOCIATORS OF
operator in the WQL language for searching the associated objects (for more information, see MSDN). Letโs examine how we can find the required instance of the Msvm_ShutdownComponent
class:
CComVariant path;
CHK_HRES(pVmObject-"Get(L"__RELPATH", 0, &path, NULL, NULL));
CStringW query;
query.Format(L"associators of {%s} where AssocClass=Msvm_SystemDevice"
L" ResultClass=Msvm_ShutdownComponent",
path.bstrVal);
CComPtr<IEnumWbemClassObject> pEnum;
CHK_HRES(m_pWbemServices->ExecQuery(
CComBSTR(L"WQL"),
CComBSTR(query),
WBEM_FLAG_FORWARD_ONLY,
NULL,
&pEnum
));
CComPtr<IWbemClassObject> pShutdownComponent;
ULONG returnCount = 0;
CHK_HRES(pEnumWbemClassObject->Next(WBEM_INFINITE,
1,
&pShutdownComponent,
&returnCount));
if (returnCount == 0)
{
// Msvm_ShutdownComponent not found
// ...
}
First, we get the path in the repository to our VM. Then we form the WQL query for obtaining the associated instance of the Msvm_ShutdownComponent
class and call the ExecQuery
method for performing the query. Finally, we receive the pointer to Msvm_ShutdownComponent
from the enumerator object.
Now we can shut the VM down.
CComVariant shutdownComponentPath;
CHK_HRES(pShutdownComponent->Get(L"__RELPATH", 0, &shutdownComponentPath,
NULL, NULL));
CComPtr<IWbemClassObject> pShutdownComponentClass;
CComPtr<IWbemClassObject> pInParamsDefinition;
CComPtr<IWbemClassObject> pInParams;
CHK_HRES(m_pWbemServices->GetObject(
CComBSTR(L"Msvm_ShutdownComponent"),
0,
NULL,
&pShutdownComponentClass,
NULL
));
CHK_HRES(pShutdownComponentClass->GetMethod(L"InitiateShutdown", 0,
&pInParamsDefinition, NULL));
CHK_HRES(pInParamsDefinition->SpawnInstance(0, &pInParams));
CHK_HRES(pInParams->Put(L"Force", 0, &CComVariant(true), 0));
CHK_HRES(pInParams->Put(L"Reason", 0, &CComVariant(L"Shutdown"), 0));
CHK_HRES(m_pWbemServices->ExecMethod(
shutdownComponentPath.bstrVal,
CComBSTR(L"InitiateShutdown"),
0,
NULL,
pInParams,
NULL,
NULL
));
3. Conclusion
In this article, we examined the problems of Microsoft Hyper-V program control with the help of the C++ language and WMI technology. Examples that were given in the article will help you to get the common idea of solving the typical tasks on Hyper-V management by the programs written in C++ language and Microsoft Hyper-V management trobleshooting. Of course, we could not examine many more complicated tasks (such as managing devices of the VM) within the limits of the introductory article. But the WMI interface of Hyper-V is rather clearly documented in MSDN and you can solve your tasks yourselves with its help. Besides, you can google and find many examples of solving the tasks on Hyper-V management using different programming languages, including scripting languages. As a rule, these examples can be easily translated to the C++ language, if necessary.
4. Useful links
- Hypervisors. http://en.wikipedia.org/wiki/Hypervisor
- Hyper-V. http://en.wikipedia.org/wiki/Hyper-V
- WMI. http://msdn.microsoft.com/en-us/library/aa394582%28VS.85%29.aspx
- WMI. http://en.wikipedia.org/wiki/Windows_Management_Instrumentation
- WMI providers. http://msdn.microsoft.com/en-us/library/aa394570%28VS.85%29.aspx
- Hyper-V WMI Provider. http://msdn.microsoft.com/en-us/library/cc136992%28v=VS.85%29.aspx
- Useful blog on managing Hyper-V with the help of scripts (with code examples). http://dungkhoang.spaces.live.com/?_c11_BlogPart_pagedir=Next&_c11_BlogPart_handle=cns!31A50D02D661C816!192&_c11_BlogPart_BlogPart=blogview&_c=BlogPart
5. Attachment. The source code of the example
The attached example represents a small library of classes for managing the Hyper-V hypervisor and the test application, which uses the part of the library functionality.
The library contains two classes: the CHyperV
class and the CHyperVVirtualMachine
class. The CHyperV
class allows connecting to the Hyper-V server and obtaining the list of all virtual machines or separate virtual machine. The CHyperVVirtualMachine
class represents an individual virtual machine and allows obtaining some of its properties and controlling its state.
The test application allows connecting to the specified server (parameters are set in the command line) and displays the list of all virtual machines. DNS
name and IPv4
address are also defined for the running virtual machines.
The example is designed for the Microsoft Visual Studio 2008.
Download source code (ZIP, 15 KB)
Take a look at the Apriorit Virtualization project experience