Hyper-V群集 - 通过WMI

时间:2018-04-16 10:26:28

标签: c# wmi

首先,我要感谢这个令人敬畏的网站,让我的生命节省了一百多次。

为了介绍一下我们遇到的问题,我将开始解释我们的基础设施。

实际上,我们在Windows 2016上有一个使用故障转移群集功能的4个Hyper-V主机的客户端。

微软在发行版中指出,共享磁盘复制只能通过WMI类Msvm_ReplicationCollectionService获得,所以我们开始研究它。

- Msvm_CollectionReplicationService Class

https://msdn.microsoft.com/en-us/library/mt167787(v=vs.85).aspx

我们已经按照同一类的旧模型实现了这个类。

旧命名空间:" root / virtualization / v2" (这很好用,但没有共享磁盘复制)

新命名空间:" root / HyperVCluster / v2" (失败)

作为第一步,我们尝试使用先前创建的集合(ReplicaTestGroup)在共享磁盘的两个虚拟机之间创建关系,然后我们尝试调用" CreateReplicationRelationship"班级的方法。

发出命令:PS C:\ REPLICA \ 1 \ 1> 。\ ReplicaSamples.exe CreateReplicationRelationship REPLICA1 REPLICA2 7ccff3fe-da17-436a-8f38-8a34833b31e6 hypervdrhost.mydom.local

Method fails with: "The method call failed.", without more details.

有没有人知道发生了什么?有什么方法可以调试WMI,这样我就可以看出它出了什么问题?

错误:

  

未处理的异常:System.Management.ManagementException:方法   呼叫失败。在   Microsoft.Samples.HyperV.Common.WmiUtilities.ValidateOutput(ManagementBaseObject   outputParameters,ManagementScope scope,Boolean throwIfFailed,   布尔打印错误)   C:\ Users \ isarria \ Documents \ Replica \ cs \ WmiUtilities.cs:第136行   Microsoft.Samples.HyperV.Common.WmiUtilities.ValidateOutput(ManagementBaseObject   outputParameters,ManagementScope scope)in   C:\ Users \ isarria \ Documents \ Replica \ cs \ WmiUtilities.cs:第59行   Microsoft.Samples.HyperV.Replica.ManageReplication.CreateReplicationRelationship(字符串   name,String name2,String CollectionID,String recoveryServerName)in   C:\ Users \ isarria \ Documents \ Replica \ cs \ ManageReplication.cs:第85行   Microsoft.Samples.HyperV.Replica.Program.Main(String [] args)in   C:\ Users \ isarria \ Documents \ Replica \ cs \ Program.cs:第107行

已使用的代码

    /// <summary>
    /// Enables replication for a collection of virtual machines to a specified DRserver using 
    /// integrated authentication.
    /// </summary>
    /// <param name="name">Name of VM 1</param>
    /// <param name="name2">Name of VM 2</param>
    /// <param name="CollectionID">CollectionID to enable replication.</param>
    /// <param name="recoveryServerName">The name of the recovery server.</param>
    internal static void
    CreateReplicationRelationship(
        string name,
        string name2,
        string CollectionID,
        string recoveryServerName)
    {
        ManagementScope scope = new ManagementScope(@"root\HyperVCluster\v2");
        ManagementScope oldScope = new ManagementScope(@"root\virtualization\v2");

        //
        // Retrieve the Msvm_VirtualSystemCollection.
        //
        using (ManagementObject vm = WmiUtilities.GetVirtualMachine(name, oldScope))
        {
            using (ManagementObject vm2 = WmiUtilities.GetVirtualMachine(name2, oldScope))
            {
                string vmPath = vm.Path.Path;
                string vmPath2 = vm2.Path.Path;
                using (ManagementObject collection = WmiUtilities.GetVMGroup(CollectionID, scope))
                {
                    using (ManagementObject replicationSettingData =
                        ReplicaUtilities.GetReplicationSettings(vm))
                    {
                        replicationSettingData["RecoveryConnectionPoint"] = recoveryServerName;
                        replicationSettingData["AuthenticationType"] = 1;
                        replicationSettingData["RecoveryServerPortNumber"] = 80;
                        replicationSettingData["CompressionEnabled"] = 1;

                        // Keep 24 recovery points.
                        replicationSettingData["RecoveryHistory"] = 24;

                        // Replicate changes after every 300 seconds.
                        replicationSettingData["ReplicationInterval"] = 300;

                        // Take VSS snapshot every one hour.
                        replicationSettingData["ApplicationConsistentSnapshotInterval"] = 1;

                        // Include all disks for replication.
                        replicationSettingData["IncludedDisks"] = WmiUtilities.GetVhdSettings(vm);
                        //replicationSettingData["IncludedDisks"] = WmiUtilities.GetVhdSettings(vm2);

                        Console.WriteLine(replicationSettingData["IncludedDisks"].ToString());

                        string settingDataEmbedded =
                            replicationSettingData.GetText(TextFormat.WmiDtd20);

                        using (ManagementObject replicationService =
                            ReplicaUtilities.GetVirtualMachineReplicationService(scope))
                        {
                            using (ManagementBaseObject inParams =
                                replicationService.GetMethodParameters("CreateReplicationRelationship"))
                            {
                                inParams["Collection"] = collection;
                                inParams["CollectionReplicationSettingData"] = settingDataEmbedded;

                                using (ManagementBaseObject outParams =
                                    replicationService.InvokeMethod("CreateReplicationRelationship",
                                        inParams,
                                        null))
                                {
                                    WmiUtilities.ValidateOutput(outParams, scope);
                                }
                            }
                        }

                        Console.WriteLine(string.Format(CultureInfo.CurrentCulture,
                            "Replication is successfully enabled for vmGroup: \"{0}\"", CollectionID));
                    }
                }
            }
        }
    }       


    /// <summary>
    /// Gets the Msvm_VirtualSystemCollection instance that matches the requested VMGroup name.
    /// </summary>
    /// <param name="CollectionID">The CollectionID to retrieve the path for.</param>
    /// <param name="scope">The ManagementScope to use to connect to WMI.</param>
    /// <returns>The Msvm_VirtualSystemCollection instance.</returns>
    public static ManagementObject
    GetVMGroup(
        string CollectionID,
        ManagementScope scope)
    {
        return GetCollectionObject(CollectionID, "Msvm_VirtualSystemCollection", scope);
    }

    /// <summary>
    /// Gets the Msvm_ComputerSystem instance that matches the requested virtual machine name.
    /// </summary>
    /// <param name="name">The name of the virtual machine to retrieve the path for.</param>
    /// <param name="scope">The ManagementScope to use to connect to WMI.</param>
    /// <returns>The Msvm_ComputerSystem instance.</returns>
    public static ManagementObject
    GetVirtualMachine(
        string name,
        ManagementScope scope)
    {
        return GetVmObject(name, "Msvm_ComputerSystem", scope);
    }

    /// <summary>
    /// Gets the first virtual machine object of the given class with the given name.
    /// </summary>
    /// <param name="name">The name of the virtual machine to retrieve the path for.</param>
    /// <param name="className">The class of virtual machine to search for.</param>
    /// <param name="scope">The ManagementScope to use to connect to WMI.</param>
    /// <returns>The instance representing the virtual machine.</returns>
    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;
        }
    }

    /// <summary>
    /// Gets the replication settings object for a collection.
    /// </summary>
    /// <param name="systemCollection">The Msvm_VirtualSystemCollection mache object.</param>
    /// <returns>The replication settings object.</returns>
    internal static ManagementObject
    GetReplicationSettings(
        ManagementObject systemCollection)
    {
        using (ManagementObjectCollection settingsCollection =
                systemCollection.GetRelated("Msvm_ReplicationSettingData"))
        {
            ManagementObject replicationSettings = 
                WmiUtilities.GetFirstObjectFromCollection(settingsCollection);

            return replicationSettings;
        }
    }



    /// <summary>
    /// Gets the first virtual machine object of the given class with the given name.
    /// </summary>
    /// <param CollectionID="CollectionID">The name of the virtual machine to retrieve the path for.</param>
    /// <param name="className">The class of virtual machine to search for.</param>
    /// <param name="scope">The ManagementScope to use to connect to WMI.</param>
    /// <returns>The instance representing the virtual machine.</returns>
    private static ManagementObject
    GetCollectionObject(
        string CollectionID,
        string className,
        ManagementScope scope)
    {
        string vmQueryWql = string.Format(CultureInfo.InvariantCulture,
            "SELECT * FROM {0} WHERE CollectionID=\"{1}\"", className, CollectionID);

        SelectQuery vmQuery = new SelectQuery(vmQueryWql);

        using (ManagementObjectSearcher vmSearcher = new ManagementObjectSearcher(scope, vmQuery))
        using (ManagementObjectCollection vmCollection = vmSearcher.Get())
        {
            ManagementObject CollectionObject = null;
            if (vmCollection.Count == 1)
            {
                foreach (ManagementObject managementObject in vmCollection)
                {
                    CollectionObject = managementObject; 
                }
            }
            else
            {
                throw new ManagementException(string.Format(CultureInfo.CurrentCulture,
                    "No {0} could be found with ID \"{1}\"",
                    className,
                    CollectionID));
            }
            return CollectionObject;
        }

    }



    /// <summary>
    /// Gets the virtual system replication service.
    /// </summary>
    /// <param name="scope">The scope to use when connecting to WMI.</param>
    /// <returns>The collection virtual machine replication service.</returns>
    public static ManagementObject
    GetVirtualMachineReplicationService(
        ManagementScope scope)
    {
        ManagementScope scope2 = new ManagementScope(@"root\HyperVCluster\v2");
        SelectQuery query = new SelectQuery("select * from Msvm_CollectionReplicationService");

        using (ManagementObjectSearcher queryExecute = new ManagementObjectSearcher(scope2, query))
        using (ManagementObjectCollection serviceCollection = queryExecute.Get())
        {
            if (serviceCollection.Count == 0)
            {
                throw new ManagementException("Cannot find the collection replication service object. " +
                    "Please check that the Hyper-V Virtual Machine Management service is running.");
            }

            return WmiUtilities.GetFirstObjectFromCollection(serviceCollection);
        }
    }

此外,这是ValidateOutput方法。

    /// <summary>
    /// Validates the output parameters of a method call and prints errors, if any.
    /// </summary>
    /// <param name="outputParameters">The output parameters of a WMI method call.</param>
    /// <param name="scope">The ManagementScope to use to connect to WMI.</param>
    /// <returns><c>true</c> if successful and not firing an alert; otherwise, <c>false</c>.</returns>
    public static bool
    ValidateOutput(
        ManagementBaseObject outputParameters,
        ManagementScope scope)
    {
        return ValidateOutput(outputParameters, scope, true, false);
    }

    /// <summary>
    /// Validates the output parameters of a method call and prints errors, if any.
    /// </summary>
    /// <param name="outputParameters">The output parameters of a WMI method call.</param>
    /// <param name="scope">The ManagementScope to use to connect to WMI.</param>
    /// <param name="throwIfFailed"> If true, the method throws on failure.</param>
    /// <param name="printErrors">If true, Msvm_Error messages are displayed.</param>
    /// <returns><c>true</c> if successful and not firing an alert; otherwise, <c>false</c>.</returns>
    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;
    }

0 个答案:

没有答案