Подключение файлов VHD в Hyper-V

Многие знают, что в Virtual Server 2005 существовала утилита vhdmount.exe. Она позволяла подключать образы жестких дисков формата VHD в виде каталога на разделе NTFS или отдельного диска.

В Hyper-V такой возможности нет. В связи с чем возникают больные вопросы — «доколе?» и «что делать?».

Выход из этой ситуации, конечно, есть. Точнее несколько выходов. Все они основаны на богатых возможностях управления Hyper-V через репозиторий WMI. Я приведу примеры подключения образов VHD для C#, VBScript и PowerShell. Если тема программного управления VM интересна, могу привести другие примеры.

PowerShell

#Specify the VHD to be mounted

$VHDName = "F:\Windows.vhd"

   

#Get the MSVM_ImageManagementService

$VHDService = get-wmiobject -class "Msvm_ImageManagementService" -namespace "root\virtualization" -computername "."

   

#Mount the VHD

$Result = $VHDService.Mount($VHDName)

Это, конечно, очень простой пример. Он использует готовый объект MSVM_ImageManagementService, который создается при установке роли Hyper-V, и вызывает для него метод Mount. Для отключения, что логично, используется метод UnMount.

Обратите внимание, что для успешного подключения образа виртуального диска требуется, чтобы он в данный момент не использовался запущенными виртуальными машинами. Иначе попытка подключения завершится ошибкой.

Более того — диск просто подключится к системе, но будет находиться в отключенном состоянии (offline). Перевести его в состояние online можно из оснастки Disk Management, которая входит в Server Manager. Затем там же потребуется присвоить диску букву или подключить в пустой каталог.

VBScript

Option Explicit

   

Dim WMIService

Dim VHDService

Dim VHD

   

'Specify the VHD to be mounted

VHD = "F:\Windows.vhd"

   

'Get instance of 'virtualization' WMI service on the local computer

Set WMIService = GetObject("winmgmts:\\.\root\virtualization")

   

'Get the MSVM_ImageManagementService

Set VHDService = WMIService.ExecQuery("SELECT * FROM Msvm_ImageManagementService").ItemIndex(0)

   

'Mount the VHD

VHDService.Mount(VHD)

Приведу также пример на C#. Но это немного сложнее, так что не обессудьте за большой объем кода. Я и так для облегчения восприятия убрал всевозможные необходимые в реальной жизни проверки ошибок.

C#

using System;

using System.Collections.Generic;

using System.Text;

using System.Management;

using System.IO;

using System.Security.AccessControl;

using Microsoft.Virtualization.Test.Utilities.CommandLineParser;

 

public static class Class1

{

    private static ManagementClass mVhdSvc;

    public static void Main(string[] args)

    {

        OpenVirtualization("localhost");

        MountVHD("F:\\Windows.vhd");

    }

    static void OpenVirtualization(string ComputerName)

    {

        ManagementPath path = new ManagementPath();

        path.Server = mHostName;

        path.NamespacePath = @"root\virtualization";

        path.ClassName = "Msvm_VirtualSystemManagementService";

        ManagementClass vsManagementService = new ManagementClass(path);

        foreach (ManagementObject vs in vsManagementService.GetInstances())

        {

            mVirtualization = vs;

            break;

        }

        path.ClassName = "Msvm_ImageManagementService";

        ManagementClass vhdSvc = new ManagementClass(path);

        foreach (ManagementObject vhdsvc in vhdSvc.GetInstances())

        {

            mVhdSvc = vhdsvc;

            break;

        }

    }

    static void WaitForWmiComplete(string Task, string ErrorDescription, uint Result)

    {

        if (Result != 0 && Result != 4096)

        {

            throw new ManagementException(ErrorDescription + " Error=" + Result);

        }

        else if (Result == 4096)

        {

            VMTask task = new VMTask(new ManagementObject(Task));

            task.WaitForCompletion(-1);

            if (task.Status != VMTaskStatus.CompletedSuccessfully)

            {

                throw new ManagementException(

                ErrorDescription + " Error Code: " + task.ErrorCode + "." +

                "Error Description: " + task.ErrorDescription + "."

                );

            }

        }

    }

    static void MountVHD(String VHDPath)

    {

        object[] arguments = new object[] { vhdPathInfo.FullName, null };

        uint result = 0;

        result = (uint)mVhdSvc.InvokeMethod("Mount", arguments);

        WaitForWmiComplete((string)arguments[1], "Failed to mount VHD", result);

    }

}