Приведение параметров внутри CIIMstance

Я играю с интерфейсом Hyper-V WMI и пытаюсь создать моментальный снимок одной из моих локальных виртуальных машин Hyper-V, используя С#. Я пытаюсь сделать это БЕЗ использования 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 AffectedSystem, [in] string
SnapshotSettings, [in] uint16
SnapshotType, [in, out] CIM_VirtualSystemSettingData REF ResultingSnapshot, [out] CIM_ConcreteJob REF Job );

Но это не указывает, какие из них являются обязательными, могут ли передаваться значения NULL и т. д.

Метод С#, который я пытаюсь использовать:

    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# это «просто» еще один CIIMstance. Итак, я не могу переходить из одного класса в другой, как мог бы с «обычными» классами.

Есть ли способ «преобразовать» Msvm_ComputerSystem в CIM_ComputerSystem? Или я гоняюсь за большой отвлекающей сельдью?


person Rainmaker    schedule 17.08.2018    source источник


Ответы (1)


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

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

В среде 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();
        }
    }
}
person Rainmaker    schedule 11.12.2018
comment
Эй, спасибо за это. Вы выяснили, как запрашивать существующие снэпшоты? - person Tom Beech; 11.07.2019
comment
Снимки — это экземпляры, связанные с виртуальной машиной. Таким образом, чтобы запросить их, вы должны использовать что-то вроде cimSession.EnumerateAssociatedInstances(hvNameSpace, vm,...), где vm — это CimInstance, содержащий вашу виртуальную машину. - person Rainmaker; 09.08.2019
comment
Вы нашли способ установить имя снимка? - person 3r1c; 25.02.2020
comment
Честно говоря, нет. Я пробовал, но, похоже, это не работает. В качестве обходного пути вы можете взять полученный снимок и переименовать его сразу после его создания. - person Rainmaker; 11.03.2020