Резюме: Microsoft Scripting Guy, Ed Wilson показывает как автоматически создать виртуальные машины для имеющихся жестких виртуальных жестких дисков (VHD).
Microsoft Scripting Guy, Ed Wilson на связи. Так как я и Scripting Wife готовимся к европейскому скриптинг-туру, я решил убедиться, что мой ноутбук находится в подходящем состоянии здоровья. И хорошо, что я это сделал. У меня оставалось очень мало места на жестком диске моего ноутбука, но, к мы остановились около отличного компьютерного магазина по дорогое домой с Windows PowerShell Saturday в Атланте и приобрели флеш-диск USB 3.0. Дополнительное хранилище на USB 3.0 – это вполне подходящий выбор с точки зрения производительности.
Я экспортировал все мои виртуальные машины на этот диск, чтобы освободить место на внутреннем жестком диске ноутбука. Но, как оказалось, тут была одна проблема – перед этим я отформатировал диск в EXFAT. Когда сегодня я это проверил – ничего не работало. Я получил нелепую ошибку, вроде «Невозможно ничего сделать», и ни одна из моих виртуальных машин не запускалась.
Поиск по BING показал, что Hyper-V не поддерживает файловую систему EXFAT. Я скопировал все 50 гигабайт виртуальных машин обратно на жесткий диск ноутбука, отформатировал флешку в NTFS и скопировал все обратно. И ничего. В итоге я решил просто скопировать виртуальные жесткие диски в их папку и заново создать виртуальные машины при помощи PowerShell.
Используем модуль Hyper-V для создания виртуальных машин
Первое, что потребовалось сделать – это импортировать модуль Hyper-V и создать 3 переменные. Первая – это путь к VHD-файлам, вторая – путь, где я буду хранить созданные виртуальные машины, и третья переменная будет использоваться для хранения объекта внутреннего виртуального свитча.
Значения двух первых переменных – это обычные строки. Третья же, $InternalSwitch – хранит значение, полученное от использования командлета Get-VMSwitch с параметром, указывающим вывод внутреннего виртуального свитча. У меня настроен только один внутренний свитч, так что это несложно.
Import-Module hyper-V
$VHDPath = «E:\vhd»
$VMPath = «E:\VM»
$InternalSwitch = Get-VMSwitch -SwitchType Internal
Теперь мне нужно запустить командлет Get-СhildItem для получения всех файлов виртуальных жестких дисков в папке. Поскольку я называю виртуальные жесткие так же как и виртуальные машины, это несколько облегчает мне задачу. Например, виртуальная машина, созданная на основе DC1.VHDX будет называться DC1. Это не обязательно, но в некоторой степени упрощает скрипт.
После получения списка VHD-файлов, я использую командлет Foreach-Object для создания виртуальной машины на основе каждого из дисков. Для указания имени виртуальной машины я использую свойство BaseName виртуального жесткого диска. Кроме того, я указываю объем памяти в MB (требуется), имя свитча, путь для виртуальной машины и путь к VHD-файлу.
Get-ChildItem $VHDPath |
ForEach-Object {
new-vm -Name $_.BaseName -MemoryStartupBytes 512MB `
-SwitchName $InternalSwitch.name -VHDPath $_.FullName -Path $VMPath}
Теперь я хочу включить динамическую память для каждой из виртуальных машин. Я получаю список всех виртуальных машин командлетом Get-VM и передаю это командлету Set-VMMemory. Я устанавливаю значение параметра DynamicMemoryEnabled в $true и задаю минимальный и максимальный объем памяти. Не забудьте в конце каждого значения объема памяти указать MB, в ином случае командлет вернет ошибку. Кроме того, я указал значение буфера, равное 20%.
Get-VM | Set-VMMemory -DynamicMemoryEnabled $true `
-MinimumBytes 512MB -MaximumBytes 2048MB -Buffer 20
Весь скрипт целиком:
CreateVMfromVHD.ps1
Import-Module hyper-V
$VHDPath = «E:\vhd»
$VMPath = «E:\VM»
$InternalSwitch = Get-VMSwitch -SwitchType Internal
Get-ChildItem $VHDPath |
ForEach-Object {
new-vm -Name $_.BaseName -MemoryStartupBytes 512MB `
-SwitchName $InternalSwitch.name -VHDPath $_.FullName -Path $VMPath}
Get-VM | Set-VMMemory -DynamicMemoryEnabled $true `
-MinimumBytes 512MB -MaximumBytes 2048MB -Buffer 20
Включение Integration Services для виртуальных машин.
Для включения служб интеграции для виртуальных машин я использую командлет Enable-VMIntegrationService. К сожалению, каждый сервис должен быть указан – в командлете отсутствует параметр -all. Но немного креатива, и эта проблема быстро решается. Я получаю список всех виртуальных машин командлетом Get-VM и сохраняю их в переменной $vm. Затем для обработки каждой виртуальной машины из списка я указываю команду Foreach.
$vm = get-vm
Foreach($v in $vm)
{
Для получения статуса всех сервисов интеграции я указываю командлет Get-VMIntegrationServices. Результаты я передаю командлету Foreach-Object, и затем использую выражение if для проверки, включен ли определенный сервис интеграции, или нет. Если он выключен, я включаю его командой Enable-VMIntegrationService.
Get-VMIntegrationService -VM $v |
Foreach-object {
if(!($_.enabled))
{Enable-VMIntegrationService -Name $_.name -VM $v}} }
Ниже приведен скрипт целиком.
EnableAllVMIntegrationServices.ps1
$vm = get-vm
Foreach($v in $vm)
{
Get-VMIntegrationService -VM $v |
Foreach-object {
if(!($_.enabled))
{Enable-VMIntegrationService -Name $_.name -VM $v}} }
Отлично. Пара несложных скриптов и я восстановил систему после довольно серьезного происшествия. Решение этой проблемы с использованием стандартных средств заняло бы гораздо больше времени. Как вы можете видеть на приведенном скриншоте, все виртуальные машины запущены и прекрасно себя чувствуют.
Это могло стать действительно большой проблемой на следующей неделе, когда я стал бы показывать презентации по Windows PowerShell в Европе.
Автор:
Ed Wilson, Microsoft Scripting Guy
Оригинал:
Страницы в социальных сетях:
Twitter: https://twitter.com/vsseth
Facebook: https://fb.com/inpowershell
VKontakte: https://vk.com/inpowershell