Связаться по:
vkarabedyants Telegram Viber
+7 (499) 350-10-69

Блог о системном администрировании серверов и сайтов

Установка, настройка программного обеспечения Linux, Windows операционных систем

Кастомизация гостевых ОС

Описание методов модификации

Итак, чтобы модифицировать средствами хоста виртуализации параметры гостевой ОС, необходимо каким-либо образом ей передать некую команду, которая должна вы-полниться в ее среде. Наиболее простой способ – исполь-зование штатных средств, в качестве таковых обычно вы-ступают средства интеграции, установленные в гостевой ОС. Анализ показывает, что это возможно только при ис-пользовании платформы виртуализации VMware, при ус-ловии, что в гостевой ОС установлены средства интегра-ции – VMware Tools. Данный способ действительно прост и удобен, не предполагает каких-либо трудностей при реа-лизации, и пример действий будет приведен в конце статьи для сравнения. Однако по причине указанных выше ограни-чений – имеющаяся платформа виртуализации VMware и на-личие установленных VMware Tools – часто мы вынуждены прибегать к другому способу.

Второй способ носит более изощренный характер и за-ключается в монтировании виртуального диска ВМ в среде ОС хоста, модификации скриптов инициализации и запус-ке виртуальной машины с выполнением подготовленных скриптов. Детальный список действий и используемые средства будут определяться типом платформы виртуа-лизации и типом гостевой ОС, общими будут следующие шаги.

>    Монтирование виртуального диска ВМ. Средства хоста должны позволять выполнение такой операции, должны присутствовать необходимые драйверы и утили-ты. Также на этом этапе определяется местоположение скриптов инициализации, поскольку виртуальный диск может содержать более одного раздела, и заранее неиз-вестно, какой именно раздел является системным.

>    Модификация скриптов инициализации. Для реализа-ции этого этапа необходима поддержка файловой сис-темы дисков гостевой ОС в среде хоста виртуализации. Модифицированный скрипт должен обеспечить одно-кратность выполнения кода и остановку гостевой ОС после выполнения скрипта. Этап завершается размонти-рованием виртуального диска. 

>    Старт ВМ с выполнением подготовленных скриптов.

 Результатом этого этапа будет неактивная ВМ, парамет-ры гостевой ОС которой изменены согласно намеченно-му плану.

 >    Опциональный этап – создание снимка ВМ в случае не-обходимости.

Проверка на практике. Подготовительный этап

Далее в качестве конкретного примера рассмотрим автоматизацию импорта и модификацию параметров сетевого адаптера одного из оценочных образов ОС Windows, предоставляемых фирмой Microsoft.

Для тестов удобно выбрать образ минимального объема – Windows Server 2008 R2 Enterprise Edition x64 (Базовая версия). В качестве платформы виртуализации выберем Windows Server 2008 R2, поскольку это позволит наиболее полно проиллюстрировать все возникающие задачи и их ре-шения.

Для выбранного образа и платформы виртуализации логично использовать Windows PowerShell в качестве языка сценариев. К сожалению, в Windows PowerShell из состава Windows Server 2008 R2 отсутствуют командлеты управления виртуальной средой, поэтому воспользуемся сторон-ним свободно распространяемым решением – модулем pshyperv, доступным на сайте CodePlex. Загруженный модуль необходимо установить в соответствии с прилагае-мыми инструкциями.

Для удобства представления тестовый скрипт разчленен на отдельные части в соответствии с описанными ранее этапами.

Первый фрагмент (см. листинг 1) выполняет импорт ВМ и монтирование виртуального жесткого диска. Для им-порта и монтирования используются командлеты модуля pshyperv, поэтому в начале скрипта предусмотрена про-верка установки данного модуля, а также проверка наличия и корректности аргументов скрипта. В качестве аргумента необходимо предоставить путь к папке с файлами ВМ. По-скольку заранее неизвестно, на каком из разделов вирту-ального жесткого диска расположен системный диск ОС, в скрипте выполняется поиск системного раздела среди вновь смонтированных томов по критерию максимального объема. В реальных условиях, возможно, понадобится ис-пользовать более значимые критерии, например, имя тома, либо наличие определенных элементов (например, каталога %systemroot%) в файловой структуре. Завершается данный фрагмент присвоением переменной значения, соответству-ющего системному диску гостевой ОС. Дополнительные пояснения представлены в комментариях в листинге скрипта.

Листинг 1
# Проверка аргумента
if (-not ($args) -or ($args).count -gt 1) {
Write-host "Usage: AutoDeploy.ps1 ↵
<drive:\virtualmachinefolder> "
Write-host " where 'virtualmachinefolder' ↵
- folder with virtulal machine files config.xml."
Exit
}
# Проверка установки модуля pshyperv
if (-not(Get-Module hyperv)) {import-module hyperv}
if (-not(Get-Module hyperv)) {
Write-Host "Install module 'HyperV'"
Exit}
#Проверка корректности аргумента – наличие каталога
$vmPath = $args[0]
if (Test-Path $vmPath){
$VMFolder = Get-Item -Path $vmPath\
}
else
{
Write-Host "Virtual Machine Folder not found"
Exit
}
if(-not ($VMFolder.PSisContainer))
{
Write-Host "Virtual Machine's item is not folder."
Exit
}
$savedir=$pwd
#Импорт ВМ
Write-Host "Import VM in folder " $VMFolder.FullName
$Exists = Get-VM -name ([string] $VMFolder.Name) ↵
-ErrorAction SilentlyContinue
If (!($Exists)){
Write-Host ("Importing virtual machine : ") -noNewLine
Write-Host ([string] $VMFolder.Name) -foreground Green
Write-Host Virtual Machine path: ↵
([string] $VMFolder.FullName)
Import-VM -path ([string] $VMFolder.FullName) -Wait
Write-Host
} Else {
Write-Host ('Virtual machine "') -noNewLine
Write-Host ([string] $VMFolder.Name) -noNewLine ↵
-foreground Yellow
Write-Host ('" does already exist.')
}
#Создание виртуального сетевого коммутатора и подключение
#к нему виртуального сетевого адаптера
$tswitch = Get-VMSwitch -VirtualSwitchName "testswitch"
if (-not $tswitch) {
$tswitch = New-VMPrivateSwitch -VirtualSwitchName ↵
"TestSwitch" | Out-Null
}
Get-VM -name ([string] $VMFolder.Name) | Get-VMNIC | ↵
Set-VMNICSwitch -VirtualSwitch $tswitch.elementname
#Получение файлов виртуальных дисков в каталоге
$VHDs = get-childitem "$VMFolder\virtual hard disks\*.vhd"
foreach ($VHD in $VHDs) {
if ($vhd -and ($vhd.length -ne 0)) {
Write-Host "Mounting for modification VHD " ↵
$VHD.FullName
#Монтирование виртуального диска и поиск
#системного раздела
$volbefore = gwmi -Namespace root\cimv2 ↵
-Class win32_volume
Mount-VHD -VHDPaths $VHD.FullName | Out-Null
$volafter = gwmi -Namespace root\cimv2 ↵
-Class win32_volume
# Поиск системного тома (критерий – максимальный
# размер, вновь подключенный диск)
$volsel = $null
foreach ($vol in $volafter) {
$cont = $false
foreach ($volb in $volbefore) {
if ($volb.deviceid -eq $vol.deviceid){
$cont = $true

}
}
if (-not ($cont)) {
if ($volsel) {
if ($vol.capacity -gt $volsel.capacity) {
$volsel = $vol
}
}
else
{
$volsel = $vol
}
}
}
$sysdrive=$volsel.driveletter

 

Проверка на практике. Основные действия

В следующем фрагменте (см. листинг 2) выполняется модификация стартовых скриптов, которые при запуске ВМ про-изведут необходимые изменения.

В       качестве скриптов инициализации выбраны стартап-скрипты групповых политик Windows. Это возможно для серверных ОС Windows, а также для профессиональных  и   корпоративных редакций клиентских Windows. Для других редакций клиентских систем Windows также возможна ор-ганизация стартап-скриптов, сделать это можно путем нас-тройки автоматической регистрации пользователя и моди-фикации логин-скрипта для этого пользователя. Реализация этого варианта выполняется без особого труда на основе представленных листингов.

Предлагаемый вариант имеет некоторые особенности, связанные с тем, что при монтировании диска отсутствует активная среда гостевой ОС, поэтому нет возможности кон-фигурировать стартовые скрипты штатными средствами. Проведенный анализ позволил сделать вывод, что редакти-рование стартовых скриптов групповых политик и задание связанных с ними конфигурационных параметров возможно выполнить путем прямого редактирования файлов в файло-вой системе виртуального диска и редактирования ключей реестра гостевой ОС.

В    представленном фрагменте для организации стартовых скриптов в первую очередь создается структура папок в файловой системе системного диска, затем создаются необходимые конфигурационные файлы. После этого соз-дается стартовый скрипт групповой политики, в котором собственно и предусмотрено выполнение команд модифи-кации параметров активного сетевого адаптера.

Далее для того, чтобы данная процедура выполнилась только один раз, создается скрипт выключения, в котором стартовый скрипт удаляется из конфигурационных файлов. Кроме этого, необходимо модифицировать ключи реестра гостевой ОС для задействования клиентских расширений (CSE) групповых политик, обеспечивающих выполнение стартовых скриптов.

Завершается фрагмент размонтированием виртуально-го жесткого диска.

Листинг 2.
if ($sysdrive) {
Write-Host "Drive letter for SysDrive is " $sysdrive
Write-Host "This volume on the one of partitions ↵
of VHD " $VHD.FullName
if (Test-Path $sysdrive\windows\system32) {
#Создание структуры папок для стартовых скриптов
#и конфигурационных файлов
new-item $sysdrive\windows\system32\grouppolicy ↵
-itemtype directory -ErrorAction ↵
SilentlyContinue | Out-Null
new-item $sysdrive\windows\system32\grouppolicy\ ↵
machine -itemtype directory -ErrorAction ↵
SilentlyContinue | Out-Null
new-item $sysdrive\windows\system32\grouppolicy\ ↵
user -itemtype directory -ErrorAction ↵
SilentlyContinue | Out-Null
new-item $sysdrive\windows\system32\grouppolicy\ ↵
machine\scripts -itemtype directory↵
-ErrorAction SilentlyContinue | Out-Null
new-item $sysdrive\windows\system32\grouppolicy\ ↵
machine\scripts\startup –itemtype ↵
directory -ErrorAction SilentlyContinue ↵
| Out-Null
new-item $sysdrive\windows\system32\grouppolicy\ ↵
machine\scripts\shutdown -itemtype ↵
directory -ErrorAction SilentlyContinue | ↵
Out-Null
#Создание конфигурационных файлов групповых политик
$StrGptIni = '[General]' + "`r`n" + ↵
'gPCMachineExtensionNames=[ ↵
{42B5FAAE-6536-11D2-AE5A-0000F87571E3} ↵
{40B6664F-4972-11D1-A7CA-0000F87571E3}]' ↵
+ "`r`n" + 'Version=5'
out-file -filepath "$sysdrive\windows\system32\ ↵
grouppolicy\gpt.ini" -InputObject ↵
$StrGptIni -encoding ascii | Out-Null
$StrScriptsIni= "`r`n" + '[Startup]' + "`r`n" + ↵
'0CmdLine=c:\windows\system32\ ↵
grouppolicy\machine\scripts\startup\ ↵
startup.cmd' + "`r`n" + '0Parameters=' ↵
+ "`r`n" + '[Shutdown]' + "`r`n" + ↵
'0CmdLine=c:\windows\system32\ ↵
grouppolicy\machine\scripts\shutdown\ ↵
remove.cmd' + "`r`n" + '0Parameters='
out-file -filepath "$sysdrive\windows\system32\ ↵
grouppolicy\machine\scripts\scripts.ini" ↵
-inputobject $StrScriptsIni -encoding ↵
ascii | Out-Null
#Создание стартового скрипта
$StrStartupCmd = 'For /f "skip=3 tokens=4*" ↵
%%a In (' + "'NetSh Interface IPv4 Show ↵
Interfaces'" + ') Do (Call ↵
:UseNetworkAdapter %%a "%%b") ' + "`r`n" ↵
+ 'c:\windows\system32\shutdown.exe -f ↵
-s -t 30' + "`r`n" + 'Exit /B' + "`r`n" ↵
+ ':UseNetworkAdapter' + "`r`n" + 'If ↵
%1==connected (@if %2 neq "Loopback ↵
Pseudo-Interface 1" ( netsh int ipv4 ↵
set addr %2 static 10.10.0.33 ↵
255.255.0.0 10.10.0.1))' + "`r`n" + ↵
'Exit /B' + "`r`n"
out-file –filepath "$sysdrive\windows\system32\ ↵
grouppolicy\machine\scripts\startup\ ↵
startup.cmd" -InputObject ↵
$StrStartupCmd -encoding ascii | Out-Null
#Создание скрипта выключения гостевой ОС
$StrRemoveCmd = 'del /q c:\windows\system32\ ↵
grouppolicy\machine\scripts\startup\ ↵
startup.cmd' + "`r`n" + 'del /q ↵
c:\windows\system32\grouppolicy\machine\ ↵
scripts\scripts.ini' + "`r`n" + 'del /q ↵
c:\windows\system32\grouppolicy\gpt.ini' ↵
+ "`r`n" + 'c:\windows\system32\reg.exe ↵
delete "HKLM\software\microsoft\windows\ ↵
currentversion\group policy\Status\ ↵
GPExtensions\{42B5FAAE-6536-11D2-AE5A- ↵
0000F87571E3}" /f '+ "`r`n" + 'del /q ↵
c:\windows\system32\grouppolicy\machine\ ↵
scripts\shutdown\remove.cmd'
out-file -filepath "$sysdrive\windows\system32\ ↵
grouppolicy\machine\scripts\shutdown\ ↵
remove.cmd" -InputObject $StrRemoveCmd ↵
-encoding ascii | Out-Null

#Модификация ключей реестра для задействования CSE
cd C:\Windows\System32
C:\Windows\System32\reg.exe load HKLM\onvhd ↵
$sysdrive\Windows\System32\config\ ↵
SOFTWARE | out-null
reg add "HKLM\onvhd\microsoft\windows\ ↵
currentversion\group policy\Status\↵
GPExtensions\{42B5FAAE-6536-11D2-AE5A-↵
0000F87571E3}" /f | out-null
reg add "HKLM\onvhd\microsoft\windows\ ↵
currentversion\group policy\Status\↵
GPExtensions\{42B5FAAE-6536-11D2-AE5A- ↵
0000F87571E3}" /v ForceRefreshFG ↵
/t REG_DWORD /d 0 /f | out-null
reg add "HKLM\onvhd\microsoft\windows\ ↵
currentversion\group policy\Status\ ↵
GPExtensions\{42B5FAAE-6536-11D2-AE5A-↵
0000F87571E3}" /v LastPolicyTime ↵
/t REG_DWORD /d 0 /f | out-null
reg add "HKLM\onvhd\microsoft\windows\ ↵
currentversion\group policy\Status\ ↵
GPExtensions\{42B5FAAE-6536-11D2-AE5A-↵
0000F87571E3}" /v PrevRsopLogging ↵
/t REG_DWORD /d 0 /f | out-null
reg add "HKLM\onvhd\microsoft\windows\ ↵
currentversion\group policy\Status\ ↵
GPExtensions\{42B5FAAE-6536-11D2-AE5A-↵
0000F87571E3}" /v PrevSlowLink ↵
/t REG_DWORD /d 0 /f | out-null
reg add "HKLM\onvhd\microsoft\windows\ ↵
currentversion\group policy\Status\ ↵
GPExtensions\{42B5FAAE-6536-11D2-AE5A-↵
0000F87571E3}" /v RsopStatus ↵
/t REG_DWORD /d 0 /f | out-null
reg add "HKLM\onvhd\microsoft\windows\ ↵
currentversion\group policy\Status\ ↵
GPExtensions\{42B5FAAE-6536-11D2-AE5A-↵
0000F87571E3}" /v Status /t REG_DWORD ↵
/d 0 /f | out-null
reg unload HKLM\onvhd | out-null
}
}
else
{
Write-Host "Drive letter not assigned for " $VHD.FullName
}
Dismount-VHD -VHDPaths $VHD.FullName -Force
}
}
cd $saveDir

 

Проверка на практике. Исполнение

Наконец остается запустить ВМ, дождаться завершения ее работы и создать снимок ВМ. Эти действия выполняет оставшийся фрагмент скрипта (см. листинг 3).

Листинг 3.
#Запуск ВМ
$Exists = get-vm -name ([string] $VMFolder.Name) ↵
-ErrorAction SilentlyContinue
If ($Exists){
Write-Host ("Starting virtual machine : ") -noNewLine
Write-Host ([string] $VMFolder.Name) -foreground Green
$exists | start-vm -wait
#Ожидание завершения работы ВМ с проверкой 6-минутного
#тайм-аута
$checktime = (get-date).addminutes(6)
while ((($exists | Get-VMState).enabledstate ↵
-eq "running") ↵
-and ((get-date).compareto($checktime) -lt 0)){
start-sleep 5
}
#Если ВМ еще работает, запускается принудительное
#выключение

if (($exists | Get-VMState).enabledstate -eq "running") {
Write-Host "Forced shutdown VM " $exist.elementname
$exists | Invoke-VMShutdown ↵
-force -ShutdownTimeOut 2
}
while (-not (($exists | Get-VMState).enabledstate ↵
-eq "stopped")){
start-sleep 1
}
if (($exists | Get-VMState).enabledstate -eq "stopped") {
# Создание снимка виртуальной машины
Write-Host "Create snapshot for virtual machine " ↵
$exists.elementname
$exists | New-VMSnapshot -Wait -Force -Note ↵
"StartImage" | Out-Null
}
Write-Host
}
Else
{
Write-Host ('Virtual machine "') -noNewLine
Write-Host ([string] $DriveDstFolder.Name) ↵
-noNewLine -foreground magenta
Write-Host ('" does not exist. Skip.')
}

Для выполнения скрипта необходимо распаковать ВМ в выбранную папку и запустить скрипт с аргументом, указывающим на путь к этой папке. Результатом выполнения скрипта будет подготовленная ВМ в выключенном состо-янии, с модифицированными параметрами гостевой ОС и снимком состояния.

То же самое штатными средствами

Для сравнения приведу пример управления гостевой ОС штатными средствами хоста виртуализации, что возможно в среде VMware при установленных средствах интеграции VMware Tools и использовании в качестве клиента vSphere PowerCLI . При таких условиях часть скрипта, выполняю-щего модификацию параметров гостевой ОС виртуальной машины VMname будет представлена строками листинга 4.

Листинг 4.
#Подготовка содержимого командного файла
$StrCmd = 'For /f "skip=3 tokens=4*" %%a In ↵
(' + "'NetSh Interface IPv4 Show Interfaces'" ↵
+ ') Do (Call :UseNetworkAdapter %%a "%%b") ' + ↵
"`r`n" + 'c:\windows\system32\shutdown.exe -f -s ↵
-t 30' + "`r`n" + 'Exit /B' + "`r`n" + ↵
':UseNetworkAdapter' + "`r`n" + 'If %1==connected ↵
(@if %2 neq "Loopback Pseudo-Interface 1" ↵
( netsh int ipv4 set addr %2 static 10.10.0.33 ↵
255.255.0.0 10.10.0.1))' + "`r`n" + 'Exit /B' + ↵
"`r`n"
# Сохранение файла в файловой системе хоста виртуализации
out-file –filepath "c:\changeip.cmd" -InputObject $StrCmd ↵
-encoding ascii | Out-Null
#Копирование файла в гостевую операционную систему
Copy-VMGuestFile -Source c:\changeip.cmd -Destination ↵
c:\temp\ -VM "VMname" -LocalToGuest -GuestUser ↵
Administrator -GuestPassword Pa$$w0rd
#Выполнение подготовленного командного файла
Get-VM "VMname" | Invoke-VMscript -ScriptText ↵
"c:\temp\changeip.cmd" -ScriptType Bat -GuestUser ↵
Administrator -GuestPassword Pa$$w0rd

В этом случае нет нужды манипулировать стартовыми скриптами, поскольку команды установки параметров выполняются непосредственно в среде гостевой ОС, при работающей ВМ. Разумеется, что в таком варианте может потребоваться перезагрузка гостевой ОС, если этого требуют выполненные изменения.

Дополнительно отмечу, что, если в качестве гостевой ОС используется Windows Server 2012 R2, скрипт примет еще более простой вид, представленный на листинге 5. (Подраз-умевается, что в гостевой ОС имеется только один активный сетевой адаптер.)

Листинг 5.
Get-VM "VMname" | Invoke-VMscript -ScriptText 'New-NetIPAddress -InterfaceIndex ((Get-NetAdapter).ifindex) -IPAddress 10.10.0.33 -PrefixLength 16’ -GuestUser Administrator -GuestPassword Pa$$w0rd

 

Можно предположить, что в очередных версиях платформы виртуализации Hyper-V будет реализован аналогичный спо-соб управления. Об этом говорит то, что роль виртуализации ОС Windows Server 2012 R2 поддерживает копирование файлов в гостевую ОС (но не из гостевой ОС на хост виртуализации) с помощью командлета Copy-VMFile.

Если клиентское ПО продолжит развитие в этом направлении и будет реализовано не только копирование файлов, но и выполнение произвольных команд, описанные в дан-ной статье манипуляции потеряют актуальность в контексте платформ виртуализации. В настоящее же время описанный способ управления может послужить примером для реализации различных сценариев автоматизации виртуальной инфраструктуры.

Источник «Системный администратор» №156, 2015

Сопровождение систем виртуализации, установка и настройка, [email protected]

Оставить комментарий

Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.