// 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); } } }