Bon, à la demande de deux collègues, je vous livre un petit script qui permet de rapidement créer des machines virtuelles sous Hyper-V v3. Le script original est tiré d’un post de Aidan Finn, MVP Virtual Machine et grand guru à mes yeux (http://www.aidanfinn.com), je l’ai juste enrichi de routines additionnelles trouvées ci et là sur internet de manière à automatiser la personnalisation des VMs créées.
Le but initial étant de pouvoir rapidement créer des machines virtuelles qui soient déjà correctement nommées (même nom dans l’OS que la VM dans Hyper-V) et que l’adhésion au domaine, l’adressage IP et le mot de passe Admin soient positionnés automatiquement.
Le script principal utilise des disques parents, au format VHDX, et des fichiers de réponse contenant les paramètres modifiés sous forme de variables. Les paramètres des VMs sont tirés d’un fichier CSV contenant les valeurs des variables qui sont ensuite insérées dans les fichiers de réponse. Ce fichier est ensuite copié dans le disque enfant, afin d’être pris en compte lors du démarrage de la machine… simple mais il m’a fallu quelques jours de boulot pour que tout fonctionne comme souhaité…et le travail n’est pas encore fini!
Alors, tout d’abord le script principal:
# VMName: The name of the new VM to create
# VMPath: Where to create the VM’s files
# DiskType: Differencing, Fixed, or Dynamic (the default). No value = Dynamic.
# DiffParent: Used when DiskType = Dynamic. Specifies the parent for the differencing disk
# DiskSize: Used if DiskType = Fixed or Dynamic (or blank). Size in GB for the new VHDX
# ProcessorCount: How many vCPUs the VM will have
# StartupRAM: Amount in MB that the VM will boot up with (Dynamic Memory or not)
# DynamicMemory: Yes or No (default). Do you enable DM or not?
# MinRAM: Amount in MB for Minimum RAM if DM is enabled.
# MaxRAM: Amount in MB for Maximum RAM if DM is enabled.
# MemPriority: 0-100 value if for Memory Weight DM is enabled
# MemBuffer: 5-2000 value for Memory Buffer is DM is enabled
#############Write-Host « Name: « $VMName
#############Write-Host « VM location: « $VMBaseLocation = VMPath
#############Write-Host « Memory: « $VMMemory = StartupRam
#############Write-Host « Ref Disk: « $VMRefDisk = = DiffParent
############# »Network: « $VMNetwork = SwitchName
# »Template file: 2 by OS (Domain or WRKGRP): « $UAtpl
# »Password: « $PW
# »IP: « $IP
# »Default Gateway: « $GW
# »DNS Server: « $DNS# Clear the screen
cls$CSVPath = « D:\LabCreator\VMs.csv »
$LogPath = « D:\LabCreator\VMsLog.txt »# Remove the log file
Remove-Item -Path $LogPath -ErrorAction SilentlyContinueImport-Csv $CSVPath | ForEach-Object {
# Construct some paths
$Path = $_.VMPath
$VMName = $_.VMName
$VHDPath = « $Path\$VMName »
$SwitchName = $_.SwitchName#Ajouts pour Unattend.xml basé sur Template
$Unattend = $_.Unattend
$PW = $_.Password
$IP = $_.IP
$GW = $_.GW
$DNS = $_.DNS# Only create the virtual machine if it does not already exist
if ((Get-VM $VMName -ErrorAction SilentlyContinue))
{
Add-Content $LogPath « FAIL: $VMName already existed. »
}
else
{# Create a new folder for the VM if it does not already exist
if (!(Test-Path $VHDPath))
{
New-Item -Path $VHDPath -ItemType « Directory »
}# Create a new folder for the VHD if it does not already exist
if (!(Test-Path « $VHDPath\Virtual Hard Disks »))
{
$VhdDir = New-Item -Path « $VHDPath\Virtual Hard Disks » -ItemType « Directory »
}# Create the VHD if it does not already exist
$NewVHD = « $VhdDir\$VMName-Disk0.vhdx »
if (!(Test-Path $NewVHD))
{
# Have to set these variables because $_.Variables are not available inside the switch.
$ParentDisk = $_.DiffParent
$DiskSize = [int64]$_.DiskSize * 1073741824
switch ($_.DiskType)
{
‘Differencing’ {New-VHD -Differencing -Path $NewVHD -ParentPath $ParentDisk}
‘Fixed’ {New-VHD -Fixed -Path $NewVHD -SizeBytes $DiskSize}
Default {New-VHD -Dynamic -Path $NewVHD -SizeBytes $DiskSize}
}
if (Test-Path $NewVHD)
{
Add-Content $LogPath » Progress: $NewVHD was created. »
}
else
{
Add-Content $LogPath » Error: $NewVHD was not created. »
}
}
else
{
Add-Content $LogPath » Progress: $NewVHD already existed »
}# Mount the disk to insert Unattend.xml if available
# And pushes the variables from CSV in XML.
# Unmount the drive.
#
# $VMLocation = New-Item -Path « $VMBaseLocation\$VMName » -ItemType Directory -Force
# $VMDiskLocation = New-Item -Path « $VMLocation\Virtual Hard Disks » -ItemType Directory -Force
# $VMDisk01 = New-VHD –Path $VMDiskLocation\$VMName-OSDisk.vhdx -Differencing –ParentPath $VMRefDisk
# $VMDisk02 = New-VHD –Path $VMDiskLocation\$VMName-DataDisk01.vhdx -SizeBytes 60GB
# $VM = New-VM –Name $VMname –MemoryStartupBytes $VMMemory –VHDPath $VMDisk01.path -SwitchName $VMNetwork -Path $VMBaseLocation
# Add-VMHardDiskDrive -VM $VM -Path $VMDisk02.path –ControllerType SCSI -ControllerNumber 0
# Set-VM -VM $VM -DynamicMemory
$TEMPVHD = « $VhdDir\$VMName-Disk0.vhdx »Mount-DiskImage -ImagePath $TEMPVHD
$VHDImage = Get-DiskImage -ImagePath $TEMPVHD | Get-Disk | Get-Partition | Get-Volume | Where-Object { $_.FileSystemLabel -ne « Réservé au système » } | Where-Object { $_.FileSystemLabel -ne « System » }
$VHDDrive = [string]$VHDImage.DriveLetter+ »: »$UAXml = « $VHDDrive\unattend.xml »
copy $unattend $UAXmlforeach ($str in $UAxml)
{
$content = Get-Content -path $str
$content | foreach {$_ -replace « OSDComputerName », $VMNAME} | Set-Content $str
}foreach ($str in $UAxml)
{
$content = Get-Content -path $str
$content | foreach {$_ -replace « OSDPassword », $PW} | Set-Content $str
}foreach ($str in $UAxml)
{
$content = Get-Content -path $str
$content | foreach {$_ -replace « OSDIP », $IP} | Set-Content $str
}foreach ($str in $UAxml)
{
$content = Get-Content -path $str
$content | foreach {$_ -replace « OSDDNS », $DNS} | Set-Content $str
}foreach ($str in $UAxml)
{
$content = Get-Content -path $str
$content | foreach {$_ -replace « OSDGW », $GW} | Set-Content $str
}# makes a copy of .XML to .TXT for XP/2003’s like unattended, just in case
copy « $VHDDrive\unattend.xml » « $VHDDrive\unattend.txt »Dismount-DiskImage -ImagePath $TEMPVHD
# $VMDisk02 = New-VHD –Path $VMDiskLocation\$VMName-DataDisk01.vhdx -SizeBytes 60GB
# Add-VMHardDiskDrive -VM $VM -Path $VMDisk02.path –ControllerType SCSI -ControllerNumber 0
# Create the VM
New-VM -Name $_.VMName -Path $Path -SwitchName $_.SwitchName -VHDPath $NewVHD -MemoryStartupBytes ([int64]$_.StartupRam * 1048576)# Configure the processors
Set-VMProcessor $_.VMName -Count $_.ProcessorCount# Configure Dynamic Memory if required
If ($_.DynamicMemory -Eq « Yes »)
{
Set-VMMemory -VMName $_.VMName -DynamicMemoryEnabled $True -MaximumBytes ([int64]$_.MaxRAM * 1048576) -MinimumBytes ([int64]$_.MinRAM * 1048576) -Priority $_.MemPriority -Buffer $_.MemBuffer
}# Record the result
if ((Get-VM $VMName -ErrorAction SilentlyContinue))
{
Add-Content $LogPath « Success: $VMName was created. »
}
else
{
Add-Content $LogPath « FAIL: $VMName was created. »
}
start-vm -Name $VMName
#vmconnect localhost $VMName
}
}
Ensuite il faut renseigner le fichier CSV, ici un exemple avec une machine WS2012, nommée SRV01:
VMName,VMPath,DiskType,DiffParent,DiskSize,ProcessorCount,StartupRAM,DynamicMemory,MinRam,MaxRAM,MemPriority,MemBuffer,SwitchName,Unattend,Password,IP,GW,DNS
SRV01,C:\LAB,Differencing,D:\LabCreator\2012.vhdx,,1,1024,Yes,256,4096,50,20,VLAN,2012WG,P@ssw0rd,10.0.0.1,10.0.0.254,10.0.0.1
Le disque parent 2012.VHDX, ainsi que le fichier de réponse 2012WG (pour WorkGroup), doivent être dans le répertoire de lancement (ici d:\LabCreator). Le disque parent est un WS2012 à jour, sysprépé et sur lequel on aura pris soin d’installer les fonctionnalités de base dont on a besoin pour nos VMs.
Le fichier de réponse (unattended.xml) est ici paramétré pour remplacer les champs devant être dynamiquement attribués par les valeurs du fichier CSV. Par exemple le nom de la machine est originalement renseigné avec la variable OSDComputerName, celle ci sera remplacée dans le fichier, lors de son insertion, par le nom de la VMs issu du fichier CSV…et ainsi de suite pour l’IP, le MDP admin, etc… bien sur il est possible d’ajouter ses propres variables ci cela est nécessaire…
Pour information, sur mes machines de test (Corei7, 24Go de ram et SSD) la création de 10 VMs Windows Server 2012 et Windows 8 prend moins de 10 minutes, du lancement à l’ouverture de session
c’est bien agréable pour monter les labos et les démos!!!
Bon Scripting, et si vous avez des contributions/modifications à suggérer, je suis bien sur preneur!!!!
Bonne nuit,
Pierre.