我正在使用Hyper-V WMI界面,并试图使用C#创建我的本地Hyper-V VM之一的快照。我正在尝试不使用System.Management来执行此操作。相反,我使用的是Microsoft.Management.Infrastructure。原因是.NET Core支持它。另外,System.Management.Infrastructure似乎是System.Management的预期替代。
我无法将正确的参数传递给CIM_VirtualSystemSnapshotService类的“ CreateSnapshot”方法的正确参数。
列出输入参数:
uint32 CreateSnapshot([in] CIM_ComputerSystem REF AffectedSystem,[输入]字符串
快照设置,[于] uint16
SnapshotType,[输入,输出] 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 + Invoke-CimMethod -ClassName“ Msvm_VirtualSystemSnapshotService” -Meth ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ + CategoryInfo:InvalidType:(root \ virtualiza ... SnapshotService:String)[Invoke-CimMethod], CimException + FullyQualifiedErrorId:HRESULT 0x80041005,Microsoft.Management.Infrast
ructure.CimCmdlets.InvokeCimMethodCommand
因此,该方法似乎期望使用CIM_ComputerSystem。但是,我给它传递了一个Msvm_ComputerSystem。 从C#中,它只是另一个CIMInstance。因此,我不能像使用“普通”类那样从一个类转换为另一个类。
我有什么办法可以将Msvm_ComputerSystem“广播”到CIM_ComputerSystem吗?还是我追着一条大红色的鲱鱼?
答案 0 :(得分:0)
好的,我花了一段时间才找到一些时间来重新进行这项工作。
我终于解决了。
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();
}
}
}