Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / ATL

Programmed Hyper-V Management

4.75/5 (7 votes)
27 May 2010CPOL15 min read 64.9K   1.5K  
In this article, we examine the problems of program control of the Microsoft Hyper-V hypervisor with the help of the C++ language and WMI technology.

Table of Contents

  1. Introduction
    1. The notion of hypervisor. Brief survey of existing products
    2. Microsoft Hyper-V hypervisor
  2. The program control of Hyper-V hypervisor
    1. WMI technology
    2. Description of main WMI objects for Hyper-V controlling
    3. Connecting to a hypervisor
    4. Receiving the list of virtual machines
    5. Receiving the properties of the virtual machine
    6. Launching, stopping, and checking the status of the virtual machine
  3. Conclusion
  4. Useful links
  5. Attachment - The source code of the example, description
  6. History

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:

  1. 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).
  2. Hosted hypervisors, which is 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 was also 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 Program Control of the Hyper-V Hypervisor

2.1. WMI Technology

WMI technology (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 the 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 VM (it is displayed in the list of VM in the manager console) or its NETBIOS name if it is a physical machine.
  • Name contains a unique identifier (GUID) of VM.
  • EnabledState defines the state of the VM (stopped, running, paused, etc.).

The RequestStateChange method of the Msvm_ComputerSystem class allows modifying the state of the VM (for example, to launch or to stop it).

The Msvm_VirtualSystemManagementService class represents a virtualization service and is used for creating, deleting, and modifying VMs, and also for creating VM snapshots, exporting and importing VMs. Let’s examine some methods of this class:

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:

C++
#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:

C++
CHK_HRES(pObject->Method());

So, let’s proceed to the first task, namely, connecting to a hypervisor:

C++
CComBSTR namespacePath = L"\\\\";
namespacePath += pServer;
namespacePath += L"\\root\\virtualization";

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 “DOMAIN\USER” 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:

C++
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.

C++
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:

  1. Get the object that represents the input parameters of the method.
  2. Set the values of the input parameters by setting the values of the corresponding properties of this object.
  3. Call the method and receive the object that represents the output parameters of the method if necessary.
  4. 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.

C++
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.

C++
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:

C++
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:

C++
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.

C++
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 program control of the Microsoft Hyper-V hypervisor 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. 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

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 Microsoft Visual Studio 2008.

6. History

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)