Параметры приведения внутри CIMInstance

Я играю с интерфейсом Hyper-V WMI и пытаюсь создать снимок одной из моих локальных виртуальных машин Hyper-V, используя C#. Я пытаюсь сделать это без использования System.Management. Вместо этого я использую Microsoft.Management.Infrastructure. Причина этого заключается в том, что он поддерживается в.NET Core. Кроме того, System.Management.Infrastructure, по-видимому, является предполагаемой заменой System.Management.

У меня проблемы с передачей правильных параметров в правильный параметр в метод "CreateSnapshot" в классе CIM_VirtualSystemSnapshotService.

Это задокументировано здесь: https://docs.microsoft.com/en-us/windows/desktop/hyperv_v2/cim-virtualsystemsnapshotservice-createsnapshot

Входные параметры перечислены:

uint32 CreateSnapshot ([in] CIM_ComputerSystem REF ActedSystem, [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: Несоответствие типов для параметра "ActedSystem". В строке: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 ответов

Хорошо, мне потребовалось некоторое время, прежде чем я снова нашел время поработать над этим.

Я наконец-то решил это.

В инфраструктуре CIM / WMI есть некоторые вещи, которые, кажется, работают несколько иначе, чем вы ожидаете.

Решение, в конце концов, "простое". В вызове CimMethodParameter.Create можно указать CimType. Установите правильное значение, и метод будет работать. Любое отклонение немедленно приведет к "Неверный параметр" или "Не найден". Например, передача int вместо uint8 приводит к ошибке.

Кроме того, нет необходимости предварительно определять выходные переменные. Выходные данные возвращаются объектом CimMethodResult, возвращаемым из InvokeMethod.

Я включил полную программу ниже. Установите Microsoft.Management.Infrastructure из Nuget перед запуском.

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();
        }
    }
}
Другие вопросы по тегам