【问题标题】:Casting parameters inside CIMInstance在 CIMInstance 中转换参数
【发布时间】:2019-01-24 11:31:29
【问题描述】:

我正在使用 Hyper-V WMI 界面,并尝试使用 C# 创建我的一个本地 Hyper-V VM 的快照。我试图在不使用 System.Management 的情况下做到这一点。相反,我使用的是 Microsoft.Management.Infrastructure。原因是 .NET Core 支持它。此外,System.Management.Infrastructure 似乎是 System.Management 的预期替代品。

我在将正确的参数传递给 CIM_VirtualSystemSnapshotService 类的“CreateSnapshot”方法时遇到问题。

这里记录了: https://docs.microsoft.com/en-us/windows/desktop/hyperv_v2/cim-virtualsystemsnapshotservice-createsnapshot

列出的输入参数:

uint32 CreateSnapshot( [in] CIM_ComputerSystem REF AffectedSystem, [in] 字符串
SnapshotSettings,[in] uint16
SnapshotType, [in, out] CIM_VirtualSystemSettingData REF ResultingSnapshot, [out] CIM_ConcreteJob REF Job );

但是,这并没有指定哪些是强制性的,是否可以传递NULL值等等。

我正在尝试使用的 C# 方法:

    public static void CreateSnapshot()
    {
        const string hvNamespace = @"root\virtualization\v2";

        var sessionOptions = new DComSessionOptions
        {
            Timeout = TimeSpan.FromSeconds(30)
        };

        var cimSession = CimSession.Create("localhost", sessionOptions);

        var vmSnapshotService = new CimInstance(cimSession.GetClass(hvNamespace, "CIM_VirtualSystemSnapshotService"));

        // CimInstance of CIM_ComputerSystem. QueryInstances returns Msvm_ComputerSystem
        var vm = cimSession.QueryInstances(hvNamespace, "WQL", $"SELECT * FROM CIM_ComputerSystem WHERE ElementName = 'Android'").First();

        var snapshotSettingDataClass = cimSession.GetClass(hvNamespace, "CIM_VirtualSystemSettingData");
        var snapshotSettingData = new CimInstance(snapshotSettingDataClass);

        var snapshotParameters = new CimMethodParametersCollection();
        snapshotParameters.Add(CimMethodParameter.Create("AffectedSystem", vm, CimFlags.In));
        snapshotParameters.Add(CimMethodParameter.Create("SnapshotSettings", "", CimFlags.In));
        snapshotParameters.Add(CimMethodParameter.Create("SnapshotType", 2, CimFlags.In));
        snapshotParameters.Add(CimMethodParameter.Create("ResultingSnapshot", snapshotSettingData, CimFlags.Out));

        cimSession.InvokeMethod(namespaceName: hvNamespace, instance: vmSnapshotService, methodName: "CreateSnapshot", methodParameters: snapshotParameters);
//Microsoft.Management.Infrastructure.CimException: 'Invalid parameter '

        Console.WriteLine($"Snapshot created!");
    }

这会给出错误“无效参数”。不太具体。

我尝试在 Powershell 中重建它:

$session = New-CimSession
$hvNamespace = "root\virtualization\v2"
$snapshotservice = Get-CimClass -ClassName "CIM_VirtualSystemSnapshotService" -Namespace $hvNamespace
$vm = Get-CimInstance -Namespace $hvNamespace -Query "SELECT * FROM CIM_ComputerSystem WHERE ElementName = 'Android'" -QueryDialect WQL
Invoke-CimMethod -ClassName "Msvm_VirtualSystemSnapshotService" -MethodName "CreateSnapshot" -Namespace $hvNamespace -Arguments @{ "AffectedSystem" = $vm ; "SnapshotSettings" = "" ; "SnapshotType" = 2 }

这给出了这个错误:

Invoke-CimMethod:参数“AffectedSystem”的类型不匹配 行:1 字符:1 + 调用-CimMethod -ClassName "Msvm_VirtualSystemSnapshotService" -Meth ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidType: (root\virtualiza...SnapshotService :String) [Invoke-CimMethod], 异常 + FullyQualifiedErrorId:HRESULT 0x80041005,Microsoft.Management.Infrast
ructure.CimCmdlets.InvokeCimMethodCommand

因此,该方法看起来需要一个 CIM_ComputerSystem。但是,我将它传递给 Msvm_ComputerSystem。 在 C# 中,它“只是”另一个 CIMInstance。所以,我不能像使用“普通”课程那样从一个课程转换到另一个课程。

我有什么方法可以将 Msvm_ComputerSystem“转换”为 CIM_ComputerSystem?或者,我是在追逐一条大红鲱鱼?

【问题讨论】:

    标签: c# wmi hyper-v cim


    【解决方案1】:

    好的,我花了一段时间才找到时间再次处理这个问题。

    我终于解决了。

    CIM / WMI 框架中的某些内容似乎与您的预期有些不同。

    最终,解决方案是“简单的”。在对 CimMethodParameter.Create 的调用中,可以提供 CimType。将此设置为正确的值,该方法将起作用。任何偏差都会立即导致“无效参数”或“未找到”。例如,传递 int 而不是 uint8 会导致错误。

    此外,似乎没有必要预先定义输出变量。输出由 InvokeMethod 返回的 CimMethodResult 对象返回。

    我在下面包含了完整的程序。在运行之前从 Nuget 安装 Microsoft.Management.Infrastructure。

    using System;
    using System.Linq;
    using Microsoft.Management.Infrastructure;
    using Microsoft.Management.Infrastructure.Options;
    
    namespace TestApp
    {
        class Program
        {
            public static void CreateSnapshot()
            {
                const string hvNamespace = @"root\virtualization\v2";
    
                var sessionOptions = new DComSessionOptions
                {
                    Timeout = TimeSpan.FromSeconds(30)
                };
    
                var cimSession = CimSession.Create("localhost", sessionOptions);
    
                // Get an instance of the VM to snapshot
                var vm = cimSession.QueryInstances(hvNamespace, "WQL", $"SELECT * FROM CIM_ComputerSystem WHERE ElementName = 'MyTestVM'").First();
    
                // Get the instance of Msvm_VirtualSystemSnapshotService. There is only one.
                var vmSnapshotService = cimSession.EnumerateInstances(hvNamespace, "Msvm_VirtualSystemSnapshotService").First();
    
                // Set the snapshot parameters by creating a Msvm_VirtualSystemSnapshotSettingData
                var snapshotSettings = new CimInstance("Msvm_VirtualSystemSnapshotSettingData");
                snapshotSettings.CimInstanceProperties.Add(CimProperty.Create("ConsistencyLevel", 1, CimType.UInt8, CimFlags.ReadOnly));
                snapshotSettings.CimInstanceProperties.Add(CimProperty.Create("IgnoreNonSnapshottableDisks", true, CimFlags.ReadOnly));
    
                // Put all of these things into a CimMethodParametersCollection.
                // Note; no need to specify the "Out" parameters. They will be returned by the call to InvokeMethod.
                var methodParameters = new CimMethodParametersCollection
                {
                    CimMethodParameter.Create("AffectedSystem", vm, CimType.Reference, CimFlags.In),
                    CimMethodParameter.Create("SnapshotSettings", snapshotSettings.ToString(), CimType.String, CimFlags.In),
                    CimMethodParameter.Create("SnapshotType", 2, CimType.UInt16, CimFlags.In),
                };
    
                cimSession.InvokeMethod(hvNamespace, vmSnapshotService, "CreateSnapshot", methodParameters);
    
                Console.WriteLine($"Snapshot created!");
            }
    
            static void Main(string[] args)
            {
                CreateSnapshot();
                Console.ReadLine();
            }
        }
    }
    

    【讨论】:

    • 嘿,谢谢。你知道如何查询现有的快照吗?
    • 快照是虚拟机的关联实例。因此,要查询它们,您可以使用类似 cimSession.EnumerateAssociatedInstances(hvNameSpace, vm, ...) 之类的东西,其中“vm”是持有您的 VM 的 CimInstance。
    • 您找到设置快照名称的方法了吗?
    • 老实说,没有。我试过了,但它似乎不起作用。作为一种解决方法,您可以在创建后立即获取生成的快照并重命名它。
    猜你喜欢
    • 2020-08-27
    • 1970-01-01
    • 2015-03-17
    • 1970-01-01
    • 1970-01-01
    • 2015-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多