Script de création de VMs HyperV v3


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 SilentlyContinue

Import-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 $UAXml

            foreach ($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 Sourire

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.

A propos Red Kaffe

IT Trainer and Consultant on Microsoft Technologies. Windows Server and Client, Service Center 2012, WSUS/MDT/ADK/WAIK, SBS 2008/2011, Office 365, etc. Fully dedicated to support and train my customers...
Cet article, publié dans Scripting, WS 2012, est tagué , . Ajoutez ce permalien à vos favoris.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s