// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft. All rights reserved.
namespace Microsoft.Samples.HyperV.Common
{
using System;
using System.Globalization;
using System.Management;
using System.Threading;
using System.IO;
using System.Xml;
using System.Collections.Generic;
enum JobState
{
New = 2,
Starting = 3,
Running = 4,
Suspended = 5,
ShuttingDown = 6,
Completed = 7,
Terminated = 8,
Killed = 9,
Exception = 10,
CompletedWithWarnings = 32768
}
public static class VirtualSystemTypeNames
{
public const string RealizedVM = "Microsoft:Hyper-V:System:Realized";
public const string PlannedVM = "Microsoft:Hyper-V:System:Planned";
public const string RealizedSnapshot = "Microsoft:Hyper-V:Snapshot:Realized";
public const string RecoverySnapshot = "Microsoft:Hyper-V:Snapshot:Recovery";
public const string PlannedSnapshot = "Microsoft:Hyper-V:Snapshot:Planned";
public const string MissingSnapshot = "Microsoft:Hyper-V:Snapshot:Missing";
public const string ReplicaStandardRecoverySnapshot = "Microsoft:Hyper-V:Snapshot:Replica:Standard";
public const string ReplicaApplicationConsistentRecoverySnapshot = "Microsoft:Hyper-V:Snapshot:Replica:ApplicationConsistent";
public const string ReplicaPlannedRecoverySnapshot = "Microsoft:Hyper-V:Snapshot:Replica:PlannedFailover";
public const string ReplicaSettings = "Microsoft:Hyper-V:Replica";
}
public static class WmiUtilities
{
///
/// Validates the output parameters of a method call and prints errors, if any.
///
/// The output parameters of a WMI method call.
/// The ManagementScope to use to connect to WMI.
/// true if successful and not firing an alert; otherwise, false.
public static bool
ValidateOutput(
ManagementBaseObject outputParameters,
ManagementScope scope)
{
return ValidateOutput(outputParameters, scope, true, false);
}
///
/// Validates the output parameters of a method call and prints errors, if any.
///
/// The output parameters of a WMI method call.
/// The ManagementScope to use to connect to WMI.
/// If true, the method throws on failure.
/// If true, Msvm_Error messages are displayed.
/// true if successful and not firing an alert; otherwise, false.
public static bool
ValidateOutput(
ManagementBaseObject outputParameters,
ManagementScope scope,
bool throwIfFailed,
bool printErrors)
{
bool succeeded = true;
string errorMessage = "The method call failed.";
if ((uint)outputParameters["ReturnValue"] == 4096)
{
//
// The method invoked an asynchronous operation. Get the Job object
// and wait for it to complete. Then we can check its result.
//
using (ManagementObject job = new ManagementObject((string)outputParameters["Job"]))
{
job.Scope = scope;
while (!IsJobComplete(job["JobState"]))
{
Thread.Sleep(TimeSpan.FromSeconds(1));
//
// ManagementObjects are offline objects. Call Get() on the object to have its
// current property state.
//
job.Get();
}
if (!IsJobSuccessful(job["JobState"]))
{
succeeded = false;
//
// In some cases the Job object can contain helpful information about
// why the method call failed. If it did contain such information,
// use it instead of a generic message.
//
if (!string.IsNullOrEmpty((string)job["ErrorDescription"]))
{
errorMessage = (string)job["ErrorDescription"];
}
if (printErrors)
{
PrintMsvmErrors(job);
}
if (throwIfFailed)
{
throw new ManagementException(errorMessage);
}
}
}
}
else if ((uint)outputParameters["ReturnValue"] != 0)
{
succeeded = false;
if (throwIfFailed)
{
throw new ManagementException(errorMessage);
}
}
return succeeded;
}
///
/// Prints the relevant message from embedded instances of Msvm_Error.
///
/// The job from which errors are to be printed.
public static void
PrintMsvmErrors(
ManagementObject job)
{
string[] errorList;
using (ManagementBaseObject inParams = job.GetMethodParameters("GetErrorEx"))
using (ManagementBaseObject outParams = job.InvokeMethod("GetErrorEx", inParams, null))
{
if ((uint)outParams["ReturnValue"] != 0)
{
throw new ManagementException(string.Format(CultureInfo.CurrentCulture,
"GetErrorEx() call on the job failed"));
}
errorList = (string[])outParams["Errors"];
}
if (errorList == null)
{
Console.WriteLine("No errors found.");
return;
}
Console.WriteLine("Detailed errors: \n");
foreach (string error in errorList)
{
string errorSource = string.Empty;
string errorMessage = string.Empty;
int propId = 0;
XmlReader reader = XmlReader.Create(new StringReader(error));
while (reader.Read())
{
if (reader.Name.Equals("PROPERTY", StringComparison.OrdinalIgnoreCase))
{
propId = 0;
if (reader.HasAttributes)
{
string propName = reader.GetAttribute(0);
if (propName.Equals("ErrorSource", StringComparison.OrdinalIgnoreCase))
{
propId = 1;
}
else if (propName.Equals("Message", StringComparison.OrdinalIgnoreCase))
{
propId = 2;
}
}
}
else if (reader.Name.Equals("VALUE", StringComparison.OrdinalIgnoreCase))
{
if (propId == 1)
{
errorSource = reader.ReadElementContentAsString();
}
else if (propId == 2)
{
errorMessage = reader.ReadElementContentAsString();
}
propId = 0;
}
else
{
propId = 0;
}
}
Console.WriteLine("Error Message: {0}", errorMessage);
Console.WriteLine("Error Source: {0}\n", errorSource);
}
}
///
/// Gets the Msvm_ComputerSystem instance that matches the requested virtual machine name.
///
/// The name of the virtual machine to retrieve the path for.
/// The ManagementScope to use to connect to WMI.
/// The Msvm_ComputerSystem instance.
public static ManagementObject
GetVirtualMachine(
string name,
ManagementScope scope)
{
return GetVmObject(name, "Msvm_ComputerSystem", scope);
}
///
/// Gets the Msvm_PlannedComputerSystem instance matching the requested virtual machine name.
///
/// The name of the virtual machine to retrieve the path for.
/// The ManagementScope to use to connect to WMI.
/// The Msvm_PlannedComputerSystem instance.
public static ManagementObject
GetPlannedVirtualMachine(
string name,
ManagementScope scope)
{
return GetVmObject(name, "Msvm_PlannedComputerSystem", scope);
}
///
/// Gets the first virtual machine object of the given class with the given name.
///
/// The name of the virtual machine to retrieve the path for.
/// The class of virtual machine to search for.
/// The ManagementScope to use to connect to WMI.
/// The instance representing the virtual machine.
private static ManagementObject
GetVmObject(
string name,
string className,
ManagementScope scope)
{
string vmQueryWql = string.Format(CultureInfo.InvariantCulture,
"SELECT * FROM {0} WHERE ElementName=\"{1}\"", className, name);
SelectQuery vmQuery = new SelectQuery(vmQueryWql);
using (ManagementObjectSearcher vmSearcher = new ManagementObjectSearcher(scope, vmQuery))
using (ManagementObjectCollection vmCollection = vmSearcher.Get())
{
if (vmCollection.Count == 0)
{
throw new ManagementException(string.Format(CultureInfo.CurrentCulture,
"No {0} could be found with name \"{1}\"",
className,
name));
}
//
// If multiple virtual machines exist with the requested name, return the first
// one.
//
ManagementObject vm = GetFirstObjectFromCollection(vmCollection);
return vm;
}
}
///
/// Gets the virtual machine's configuration settings object.
///
/// The virtual machine.
/// The virtual machine's configuration object.
public static ManagementObject
GetVirtualMachineSettings(
ManagementObject virtualMachine)
{
using (ManagementObjectCollection settingsCollection =
virtualMachine.GetRelated("Msvm_VirtualSystemSettingData", "Msvm_SettingsDefineState",
null, null, null, null, false, null))
{
ManagementObject virtualMachineSettings =
GetFirstObjectFromCollection(settingsCollection);
return virtualMachineSettings;
}
}
///
/// Gets the Msvm_ComputerSystem instance that matches the host computer system.
///
/// The ManagementScope to use to connect to WMI.
/// The Msvm_ComputerSystem instance for the host computer system.
public static ManagementObject
GetHostComputerSystem(
ManagementScope scope)
{
//
// The host computer system uses the same WMI class (Msvm_ComputerSystem) as the
// virtual machines, so we can simply reuse the GetVirtualMachine with the name
// of the host computer system.
//
return GetVirtualMachine(Environment.MachineName, scope);
}
///
/// Gets the Msvm_ComputerSystem instance for the host computer system with name hostName.
///
/// Host computer system name.
/// The ManagementScope to use to connect to WMI.
/// The Msvm_ComputerSystem instance for the host computer system.
public static ManagementObject
GetHostComputerSystem(
string hostName,
ManagementScope scope)
{
//
// The host computer system uses the same WMI class (Msvm_ComputerSystem) as the
// virtual machines, so we can simply reuse the GetVirtualMachine with the name
// of the host computer system.
//
return GetVirtualMachine(hostName, scope);
}
///
/// Gets the CIM_ResourcePool derived instance matching the specified type, subtype and
/// pool id.
///
/// The resource type of the resource pool.
/// The resource subtype of the resource pool.
/// The pool id of the resource pool.
/// The ManagementScope to use to connect to WMI.
/// The CIM_ResourcePool derived instance.
public static ManagementObject
GetResourcePool(
string resourceType,
string resourceSubtype,
string poolId,
ManagementScope scope)
{
string poolQueryWql;
if (resourceType == "1") // OtherResourceType
{
poolQueryWql = string.Format(CultureInfo.InvariantCulture,
"SELECT * FROM CIM_ResourcePool WHERE ResourceType=\"{0}\" AND " +
"OtherResourceType=\"{1}\" AND PoolId=\"{2}\"",
resourceType, resourceSubtype, poolId);
}
else
{
poolQueryWql = string.Format(CultureInfo.InvariantCulture,
"SELECT * FROM CIM_ResourcePool WHERE ResourceType=\"{0}\" AND " +
"ResourceSubType=\"{1}\" AND PoolId=\"{2}\"",
resourceType, resourceSubtype, poolId);
}
SelectQuery poolQuery = new SelectQuery(poolQueryWql);
using (ManagementObjectSearcher poolSearcher = new ManagementObjectSearcher(scope, poolQuery))
using (ManagementObjectCollection poolCollection = poolSearcher.Get())
{
//
// There will always only be one resource pool for a given type, subtype and pool id.
//
if (poolCollection.Count != 1)
{
throw new ManagementException(string.Format(CultureInfo.CurrentCulture,
"A single CIM_ResourcePool derived instance could not be found for " +
"ResourceType \"{0}\", ResourceSubtype \"{1}\" and PoolId \"{2}\"",
resourceType, resourceSubtype, poolId));
}
ManagementObject pool = GetFirstObjectFromCollection(poolCollection);
return pool;
}
}
///
/// Gets the CIM_ResourcePool derived instances matching the specified type, and subtype.
///
/// The resource type of the resource pool.
/// The resource subtype of the resource pool.
/// The ManagementScope to use to connect to WMI.
/// The CIM_ResourcePool derived instance.
public static ManagementObjectCollection
GetResourcePools(
string resourceType,
string resourceSubtype,
ManagementScope scope)
{
string poolQueryWql;
if (resourceType == "1") // OtherResourceType
{
poolQueryWql = string.Format(CultureInfo.InvariantCulture,
"SELECT * FROM CIM_ResourcePool WHERE ResourceType=\"{0}\" AND " +
"OtherResourceType=\"{1}\"",
resourceType, resourceSubtype);
}
else
{
poolQueryWql = string.Format(CultureInfo.InvariantCulture,
"SELECT * FROM CIM_ResourcePool WHERE ResourceType=\"{0}\" AND " +
"ResourceSubType=\"{1}\"",
resourceType, resourceSubtype);
}
SelectQuery poolQuery = new SelectQuery(poolQueryWql);
using (ManagementObjectSearcher poolSearcher = new ManagementObjectSearcher(scope, poolQuery))
{
return poolSearcher.Get();
}
}
///
/// Gets the array of Msvm_StorageAllocationSettingData of VHDs associated with the virtual machine.
///
/// The virtual machine object.
/// Array of Msvm_StorageAllocationSettingData of VHDs associated with the virtual machine.
public static
ManagementObject[]
GetVhdSettings(
ManagementObject virtualMachine)
{
// Get the virtual machine settings (Msvm_VirtualSystemSettingData object).
using (ManagementObject vssd = WmiUtilities.GetVirtualMachineSettings(virtualMachine))
{
return GetVhdSettingsFromVirtualMachineSettings(vssd);
}
}
///
/// Gets the array of Msvm_StorageAllocationSettingData of VHDs associated with the given virtual
/// machine settings.
///
/// A ManagementObject representing the settings of a virtual
/// machine or snapshot.
/// Array of Msvm_StorageAllocationSettingData of VHDs associated with the given settings.
public static
ManagementObject[]
GetVhdSettingsFromVirtualMachineSettings(
ManagementObject virtualMachineSettings)
{
const UInt16 SASDResourceTypeLogicalDisk = 31;
List sasdList = new List();
//
// Get all the SASDs (Msvm_StorageAllocationSettingData)
// and look for VHDs.
//
using (ManagementObjectCollection sasdCollection =
virtualMachineSettings.GetRelated("Msvm_StorageAllocationSettingData",
"Msvm_VirtualSystemSettingDataComponent",
null, null, null, null, false, null))
{
foreach (ManagementObject sasd in sasdCollection)
{
if ((UInt16)sasd["ResourceType"] == SASDResourceTypeLogicalDisk)
{
sasdList.Add(sasd);
}
else
{
sasd.Dispose();
}
}
}
if (sasdList.Count == 0)
{
return null;
}
else
{
return sasdList.ToArray();
}
}
///
/// Gets the virtual system management service.
///
/// The scope to use when connecting to WMI.
/// The virtual system management service.
public static ManagementObject
GetVirtualMachineManagementService(
ManagementScope scope)
{
using (ManagementClass managementServiceClass =
new ManagementClass("Msvm_VirtualSystemManagementService"))
{
managementServiceClass.Scope = scope;
ManagementObject managementService =
GetFirstObjectFromCollection(managementServiceClass.GetInstances());
return managementService;
}
}
///
/// Gets the virtual system management service setting data.
///
/// The scope to use when connecting to WMI.
/// The virtual system management service settings.
public static ManagementObject
GetVirtualMachineManagementServiceSettings(
ManagementScope scope)
{
using (ManagementClass serviceSettingsClass =
new ManagementClass("Msvm_VirtualSystemManagementServiceSettingData"))
{
serviceSettingsClass.Scope = scope;
ManagementObject serviceSettings =
GetFirstObjectFromCollection(serviceSettingsClass.GetInstances());
return serviceSettings;
}
}
///
/// Gets the virtual system snapshot service.
///
/// The scope to use when connecting to WMI.
/// The virtual system snapshot service.
public static ManagementObject
GetVirtualMachineSnapshotService(
ManagementScope scope)
{
using (ManagementClass snapshotServiceClass =
new ManagementClass("Msvm_VirtualSystemSnapshotService"))
{
snapshotServiceClass.Scope = scope;
ManagementObject snapshotService =
GetFirstObjectFromCollection(snapshotServiceClass.GetInstances());
return snapshotService;
}
}
///
/// Gets the first object in a collection of ManagementObject instances.
///
/// The collection of ManagementObject instances.
/// The first object in the collection
public static ManagementObject
GetFirstObjectFromCollection(
ManagementObjectCollection collection)
{
if (collection.Count == 0)
{
throw new ArgumentException("The collection contains no objects", "collection");
}
foreach (ManagementObject managementObject in collection)
{
return managementObject;
}
return null;
}
///
/// Takes a WMI object path and escapes it so that it can be used inside a WQL query WHERE
/// clause. This effectively means replacing '\' and '"' characters so they are treated
/// like any other characters.
///
/// The object management path.
/// The escaped object management path.
public static string
EscapeObjectPath(
string objectPath)
{
string escapedObjectPath = objectPath.Replace("\\", "\\\\");
escapedObjectPath = escapedObjectPath.Replace("\"", "\\\"");
return escapedObjectPath;
}
///
/// Verifies whether a job is completed.
///
/// An object that represents the JobState of the job.
/// True if the job is completed, False otherwise.
private static bool
IsJobComplete(
object jobStateObj)
{
JobState jobState = (JobState)((ushort)jobStateObj);
return (jobState == JobState.Completed) ||
(jobState == JobState.CompletedWithWarnings) ||(jobState == JobState.Terminated) ||
(jobState == JobState.Exception) || (jobState == JobState.Killed);
}
///
/// Verifies whether a job succeeded.
///
/// An object representing the JobState of the job.
/// trueif the job succeeded; otherwise, false.
private static bool
IsJobSuccessful(
object jobStateObj)
{
JobState jobState = (JobState)((ushort)jobStateObj);
return (jobState == JobState.Completed) || (jobState == JobState.CompletedWithWarnings);
}
}
}