Click here to Skip to main content
Click here to Skip to main content

Working With Windows Management Instrumentation (WMI) - Part 3

, 15 Feb 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
In this article, we move on and explore topics like Exporting and Importing Virtual Machines.

Introduction

In this article, I will continue from where I had left off in Part 2 of this series. The main objective of this article is to continue to build up over the Hyper-V management WMI class and methods. In this part, I basically focus on how to do some advanced operations such as Export and Import operations. These operations essentially help you to build an implicit "clone" functionality within your application.

Background

In the previous article, my focus was mainly on showing how a basic operation on Hyper-V works. I went through the steps that will help us change the state of the VM, essentially setting up the context for some more operations. In this article, we move on to some more advanced topics with respect to VM management, like Import and Export operations. Hopefully, these concepts will help you build more functionality into your applications. I am not saying that Import and Export operations complete all the operations that are supported by the VM, but essentially, it gives you a head start into writing other routines. This is just the tip of the iceberg, and once you start exploring the root\virtualization namespace, you will find several new routines to build into your own custom application.

VM management routines and support routines

The best part about using Virtual Machines is the ability to manipulate them like applications or processes running within the context of an Operating System. Extending what I explained in Part 2, I will now move on to explaining how to Import and Export a VM and essentially provide the functionally for cloning Virtual Machines.

Exporting a VM

Exporting a VM allows users to select a specific VM and then export the state and virtual hard-disk (VHD) files along with configuration information of the VM. This makes it possible to transport the exported VM to another system and import it, and essentially create a clone of the parent Virtual Machine.

In the snippet below, I have a generic function that allows you to export a VM. Most of WMI usage semantics are the same as we had discussed in Part 1 and 2. The only difference is that this method uses the VirtualSystemManagementService class which consists of the bulk of methods that enable efficient VM management.

static void ExportVM(string vmName, string exportDirectory, string Node)
{
     String ConnectionString = 
       @"\\" + Node + @"\" + 
       @"root\virtualization";

     ManagementScope scope = 
       new ManagementScope(ConnectionString, null);
     ManagementObject virtualSystemService = 
       Utility.GetServiceObject(scope, 
       "Msvm_VirtualSystemManagementService");

     ManagementObject vm = Utility.GetTargetComputer(vmName, scope);

     ManagementBaseObject inParams = 
       virtualSystemService.GetMethodParameters(
       "ExportVirtualSystem");
     inParams["ComputerSystem"] = vm.Path.Path;

    //(below)Setting CopyVmState = true 
    //will export the entire VM along with 
    //its state files and Virtual Harddisk files (VHD). 
    //Setting it false will export the VM without 
    //the state files and VHD files

    inParams["CopyVmState"] = true; 
    if (!Directory.Exists(exportDirectory))
     {
        Directory.CreateDirectory(exportDirectory);
     }
    inParams["ExportDirectory"] = exportDirectory;

    ManagementBaseObject outParams = 
      virtualSystemService.InvokeMethod(
      "ExportVirtualSystem", inParams, null);

     if ((UInt32)outParams["ReturnValue"] == ReturnCode.Started)
      {
          if (Utility.JobCompleted(outParams, scope))
           {
             Console.WriteLine("VM '{0}' were " + 
                     "exported successfully.", 
                     vm["ElementName"]);
            }
          else
           {
             Console.WriteLine("Failed to export VM");
           }
      }

     else if ((UInt32)outParams["ReturnValue"] == ReturnCode.Completed)
     {
       Console.WriteLine("VM '{0}' were exported successfully.", 
                         vm["ElementName"]);
     }
     else
     {
       Console.WriteLine("Export virtual system failed " + 
         "with error {0}", outParams["ReturnValue"]);
     }

     //cleanup
     inParams.Dispose();
     outParams.Dispose();
     vm.Dispose();
     virtualSystemService.Dispose();
}

In the above snippet, I have defined the ExportVM function as static. When you use it in a specific class, you may choose to change it in any way that suits your class design. If you notice, the initial parts of the method is an exact copy of any other piece of WMI routine. As usual, we connect to the scope with our connection object. We connect to the namespace root\virtualization, which is the standard namespace for all Hyper-V Virtual Machine management routines. The class that we need to initialize and use is the Msvm_VirtualSystemManagementService class. This provides us with several useful methods that allow us to do several operations with a VM, including exporting and importing (which is what we will focus here).

Once we have the object that represents the class, we then need to get the parameters needed for the ExportVirtualSystem method. Remember at this point, we have already initialized all the management infrastructure and connected to the specific VM instance (based on the VM name provided). There are three parameters that need to be passed to the VM - one is a CIM reference that represents this virtual machine object, this we can get from the Management object we had created previously; the second parameter is whether one wants to do a full or a partial export (I will discuss that just after this); and finally, the last input parameter is the path to the export directory where we want the exported files to be placed. Now, coming back to the parameter CopyVmState - this basically tells the system whether a full export or a partial export needs to be done. A full export would mean that all the files associated with the VM - the state files, Virtual Hard disk files, and snapshots - would be exported. A partial export will just create a container file with configuration information for export, and not export the state and VHD files. Since we have provided an export directory, this function first validates if there is a valid directory path, and then creates one if it does not exist. This is then passed to the ExportDirectory parameter.

Once we InvokeMethod and execute this method, we get the return value in outParam. As we have done in Part 2, we will use our utility function to track the completion of the ExportVirtualSystem method. You can find the code for this utility function in Part 2, or I have provided it at the end of this article.

Importing a VM

The next part is importing an exported VM. This is just the opposite of the export process. The code flow is almost similar, except for small changes to the parameters passed to the ExportVirtualSystem method. The ImportVirtualSystem takes only two input parameters - the import directory (which is the same as the directory to which we exported), and a boolean value called GenerateNewID. All Virtual Machines are associated with a Virtual Machine Identifier which should be unique per physical system. Two VMs on a single physical system can have the same name, but must have different IDs. However, when you import from one machine to another, you can still retain the same Virtual Machine ID. The code snippet is fairly self-explanatory, and along the same lines as the export method.

One small difference between the export and import functions is that in the Export function I assume that it executes locally and hence do not take a user name and password parameter. However in the Import function I pass the Username and Password parameters also. You can add this piece to the function above to make it more complete.

static void ImportVM(string importDirectory, String Node, 
                     string UserName, string Password)
{
    String ConnectionString = @"\\" + Node + 
      @"\" + @"root\virtualization";
    ConnectionOptions co = new ConnectionOptions();
    co.Username = UserName;
    co.Password = Password;
    ManagementScope scope = new ManagementScope(ConnectionString, co);
    scope.Connect();
    ManagementObject virtualSystemService = 
       Utility.GetServiceObject(scope, 
       "Msvm_VirtualSystemManagementService");

    ManagementBaseObject inParams = 
      virtualSystemService.GetMethodParameters(
      "ImportVirtualSystem");
    //I am overriding any passed params to this call. We need same ID
    inParams["GenerateNewID"] = "false";
    inParams["ImportDirectory"] = importDirectory;

    ManagementBaseObject outParams = 
      virtualSystemService.InvokeMethod(
      "ImportVirtualSystem", inParams, null);

    if ((UInt32)outParams["ReturnValue"] == ReturnCode.Started)
    {
        if (Utility.JobCompleted(outParams, scope))
        {
            Console.WriteLine("VM were imported successfully.");
        }
        else
        {
            Console.WriteLine("Failed to import VM");
        }
    }
    else if ((UInt32)outParams["ReturnValue"] == ReturnCode.Completed)
    {
        Console.WriteLine("VM were imported successfully.");
    }
    else
    {
        Console.WriteLine("Import virtual system failed " + 
          "with error {0}", outParams["ReturnValue"]);
    }

    //Cleanup

    inParams.Dispose();
    outParams.Dispose();
    virtualSystemService.Dispose();
}

For most parts, the above snippet is similar to the export function. I am setting the GenerateNewID input parameter to false - which means that we don't want a new VM ID to be generated. Setting it to true will allow you to create a new machine ID, in which case the exported VM can be imported on the same system as the VM from which it was exported.

This completes this part where we primarily focused on exporting and importing Virtual Machines (either partially or fully). With this, you can implement a clone functionality in your custom application that manages VMs. Just as a note, some of the methods like ImportVirtualSystem and ExportVirtualSystem have been deprecated in Windows 2008 R2 and beyond. They have been replaced with the ImportVirtualSystemEx and ExportVirtualSystemEx methods. I encourage the readers to go through the API documentation in MSDN to see what has changed.

In order for the code here to be complete, I am repeating the JobCcmplete function that we use in all the functions to track the completion of a task. As you are aware, tasks such as import, export, stopping, starting, etc., are not deterministic, as in they do not complete as soon as you execute. In order to track the completion of the task, we have mechanisms available where we wait for the job to be complete. This function just generically enables you to track any such job object returned from executing your WMI method.

//This code demonstrates how the VM state change can be tracked
public static bool JobCompleted(ManagementBaseObject outParams, 
                                ManagementScope scope)
{
    bool jobCompleted = true;

    //Retrieve msvc_StorageJob path. This is a full wmi path
    string JobPath = (string)outParams["Job"];
    ManagementObject Job = new ManagementObject(scope,
    new ManagementPath(JobPath), null);

    //Try to get storage job information
    Job.Get();
    while ((UInt16)Job["JobState"] == JobState.Starting
        || (UInt16)Job["JobState"] == JobState.Running)
    {
        Console.WriteLine("In progress... {0}% completed.", 
            Job["PercentComplete"]);
        System.Threading.Thread.Sleep(1000);
        Job.Get();
    }

    //Figure out if job failed
    UInt16 jobState = (UInt16)Job["JobState"];
    if (jobState != JobState.Completed)
    {
        UInt16 jobErrorCode = (UInt16)Job["ErrorCode"];
        Console.WriteLine("Error Code:{0}", jobErrorCode);
        Console.WriteLine("ErrorDescription: {0}", 
         (string)Job["ErrorDescription"]);
        jobCompleted = false;
    }
    return jobCompleted;
}

References

MSDN Online API Reference and WMI SDK Samples and documentation.

License

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

Share

About the Author

Rajkumar-Kannan
Engineer Hewlett Packard
India India
No Biography provided

Comments and Discussions

 
GeneralCreating templates of virtual machines Pinmemberhuiahuit23-Feb-10 2:43 
GeneralRe: Creating templates of virtual machines PinmemberRajkumar-Kannan23-Feb-10 17:29 
GeneralRe: Creating templates of virtual machines PinmemberRajkumar-Kannan23-Feb-10 17:40 
GeneralRe: Creating templates of virtual machines Pinmemberhuiahuit23-Feb-10 23:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150224.1 | Last Updated 16 Feb 2010
Article Copyright 2010 by Rajkumar-Kannan
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid