MikeBaz - MSFT
MikeBaz - MSFT

Reputation: 3258

Confused about WMI in .NET synchronous/asynchronous execution and results

I am trying to load the Hyper-V system definition from an export on a Windows 8 system using WMI. So far, I have this:

var managementScope = new ManagementScope(@"root\virtualization\v2");
var invokeMethodOptions = new InvokeMethodOptions();
invokeMethodOptions.Timeout = new TimeSpan(0, 0, 10);
using (var managementService = WmiUtilities.GetVirtualMachineManagementService(managementScope)) {
    var inParameters = managementService.GetMethodParameters(@"ImportSystemDefinition");
    inParameters["SystemDefinitionFile"] = filePath;
    inParameters["SnapshotFolder"] = snapshotPath;
    inParameters["GenerateNewSystemIdentifier"] = false;
    ManagementBaseObject outParameters = managementService.InvokeMethod(@"ImportSystemDefinition", inParameters, invokeMethodOptions);
    foreach (var value in outParameters.Properties) {
        Console.WriteLine("{0}: {1}", value.Name, value.Value);
    }
    return (ManagementBaseObject) outParameters["ImportedSystem"];
}

When I run this, the return code is 4096, indicating a job has started successfully, and I get a job value back - for example:

ImportedSystem: 
Job: \\COREI7\root\virtualization\v2:Msvm_ConcreteJob.InstanceID="B1DC90B6-14A1-42C0-924E-225660E6EC98"
ReturnValue: 4096

I have the following questions:

  1. Is it possible to execute this method synchronously? How can I tell that? The MSDN documentation at http://msdn.microsoft.com/en-us/library/hh850082(v=vs.85).aspx suggests it is possible ("If the operation completes synchronously") but I don't see how. My guess is this is a general WMI question about how to execute methods synchronously, which I can't seem to find how to do.
  2. If I am force to do asynchronous, how to I watch that specific job? Everything I'm finding is on watching process events or event log events, but those both seem to be specific WQL events I'm targeting and not general job events.

I apologize if these questions are too basic - I'm just having no luck finding the answers.

Thanks!

[Edit] I'm looking into adding a ManagementOperationObserver to tell me when it's done, although it's not clear why I need to force it asynchronous when it seems to be doing that anyway.

Upvotes: 0

Views: 1160

Answers (1)

MikeBaz - MSFT
MikeBaz - MSFT

Reputation: 3258

OK, so I worked this out, sort of.

First, the job was completing with an error. The 4096 was telling me that it had started but hadn't finished because it had failed. I still don't know how to quickly get that out from that code above, but experimenting in PowerShell made it clear that's what was happening.

Second, I completely revamped the code. It's possible to have Visual Studio generate strongly-typed WMI classes from Server Explorer: http://msdn.microsoft.com/en-us/library/ms257357.aspx. Doing this twice to get ROOT.virtualization.v2.Msvm_PlannedComputerSystem.cs and ROOT.virtualization.v2.Msvm_VirtualSystemManagementService.cs lets me do the following code, which is much clearer:

var managementScope = new ManagementScope(@"root\virtualization\v2");
using (var managementService = new VirtualSystemManagementService(WmiUtilities.GetVirtualMachineManagementService(managementScope))) {
    PlannedComputerSystem importedSystem;
    ConcreteJob job;
    var importResults = managementService.ImportSystemDefinition(
        GenerateNewSystemIdentifier: false,
        SystemDefinitionFile: filePath,
        SnapshotFolder: snapshotPath,
        ImportedSystem: out importedSystem,
        Job: out job
    );
    if (importResults != 0) {
        MessageBox.Show(String.Format("Error on import of {0}: {1}", filePath, job.ErrorDescription));
    }
}

Note that the generated code has to be changed a bit to get the nicer strongly typed objects back from the ImportSystemDefinition call:

ImportedSystem = null;
Job = null;
if (outParams == null) {
    return 0;
} else {
    if (outParams.Properties["ImportedSystem"].Value != null) {
        ImportedSystem = new PlannedComputerSystem(new ManagementObject(outParams.Properties["ImportedSystem"].Value.ToString()));
    }
    if (outParams.Properties["Job"].Value != null) {
        Job = new ConcreteJob(new ManagementObject(outParams.Properties["Job"].Value.ToString;
    }
    return Convert.ToUInt32(outParams.Properties["ReturnValue"].Value);
}

Upvotes: 1

Related Questions