Windows Server 2012: backup VM in Hyper-V

PowerShellMagazine - (wallpaper) - KEEP CALM.cdr Con Windows Server 2012 è stato introdotto il modulo per la gestione di Hyper-V tramite PowerShell che rende disponibili 164 cmdlets, per l’elenco e la documentazione di ciascun cmdlet si veda la sezione di TechNet Hyper-V Cmdlets in Windows PowerShell.

E’ possibile vedere l’elenco dei comandi dalla console di PowerShell tramite i comandi:

  • Elenco cmdlets: Get-Command -Module Hyper-V
  • Count dei cmdlets: (Get-Command -Module Hyper-V).Count
  • Help di un cmdlet: Get-Help NomeCmdlet (xes: Get-Help GET-VM la prima volta che si invoca il cmd Get-Help verrà richiesto di scaricare l’help, ovvero verrà eseguito il cmdlet Update-Help)

L’introduzione del modulo PowerShell Hyper-V rende quindi non più necessaria la PowerShell Management Library for Hyper-V che rendeva disponibile circa 80 cmdlets per la gestione di Hyper-V in Windows Server 2008 R2.

Questo significa che ad esempio è possibile rivedere lo script che avevo descritto nel post Hyper-V backup di macchine virtuali sfruttando i cmdlet offerti dal modulo Hyper-V in Windows Server 2012.

Di seguito riporto la versione per Windows Server 2012 dello script che può eseguire le operazioni di arresto VM, compattazione dei VHD nella VM, export della VM, avvio della VM, gestione del mantenimento del numero di copie di back e gestione log.

Nella nella sezione iniziale dello script è possibile impostare le seguenti configurazioni:

  • Nome macchina virtuale ($vmName = “VMTest”)
  • Path backup  ($bkpPath = “F:\HyperV-Export”)
  • Numero di backup da mantenere  ($bkpCopiesRetained = 2)
  • Compressione VHD della VM prima dell’esportazione ($compressVHDs = $TRUE)
  • Avvio della VM al termine del backup ($startVM = $TRUE)
  • Esecuzione dell’esportazione della VM ($exportVM = $TRUE)
  • Path dei file log ($logFilePath = $bkpPath)
  • Suffisso del nome dei file log ($logFileNameSuffix = “LogBackup”)
  • Numero di file di log da mantenere ($logFilesRetained = 3)

Script BackupVMTest.ps1:

# *** Impostazioni ***
$vmName = “VMTest”
$bkpPath = “F:\HyperV-Export”
$bkpCopiesRetained = 2
$compressVHDs = $TRUE
$startVM = $TRUE
$exportVM = $TRUE
$logFilePath = $bkpPath
$logFileNameSuffix = “LogBackup”
$logFilesRetained = 3
# ************************

# *** Import modulo Hyper-V
Import-Module Hyper-V

# *** Inizializzazioni ***
$now = Get-Date
$expPathVM = $bkpPath + “\” + $vmName
$bkpPathVM = $expPathVM + “-” + $now.ToString(“yyyy-MM-dd-HH-mm-ss”)
$logFileNameBase = $logFilePath + “\” + $logFileNameSuffix + “-” + $vmName
$logFile = $logFileNameBase + “-” + $now.ToString(“yyyy-MM-dd-HH-mm-ss”) + “.txt”
# ************************

# *** Creazione Backup Path
if (!(Test-Path $bkpPath)){
    New-Item $bkpPath -type directory
}

# *** Creazione Log Path
if (!(Test-Path $logFilePath)){
    New-Item $logFilePath -type directory
}

# *** Avvio backup
(Get-Date).ToString(“yyyy-MM-dd HH:mm:ss”) + ” Avvio Backup” | Out-File $logFile

# **** Shutdown virtual machines
if ((Get-VM -Name $vmName).State -eq “Running”){
    (Get-Date).ToString(“yyyy-MM-dd HH:mm:ss”) + ” Arresto VM ” + $vmName | Out-File $logFile -append
    Stop-VM -Name $vmName -force -Verbose | Out-File $logFile -append
}
else{
    (Get-Date).ToString(“yyyy-MM-dd HH:mm:ss”) + ” VM ” + $vmName + ” non attiva”| Out-File $logFile -append
}

# *** Compattamento VHD
if ($compressVHDs){
    Get-VMHardDiskDrive -VMName $vmName | foreach {
        if ($_.Path -ne $NULL) {
            if ($_.Path.EndsWith(“.iso”) -eq $FALSE){
                (Get-Date).ToString(“yyyy-MM-dd HH:mm:ss”) + ” Compressione VHD ” + $_.DiskPath | Out-File $logFile -append
                Optimize-VHD -Path $_.Path -Verbose | Out-File $logFile -append
            }
        }
    }
}

# *** Export virtual machines
if ($exportVM){
    (Get-Date).ToString(“yyyy-MM-dd HH:mm:ss”) +  ” Esportazione VM ” + $vmName | Out-File $logFile -append
    Export-VM -Name $vmName -Path $bkpPath -Verbose | Out-File $logFile -append
}

# *** Avvio VM
if ($startVM){
    (Get-Date).ToString(“yyyy-MM-dd HH:mm:ss”) +  ” Avvio VM ” + $vmName | Out-File $logFile -append
    Start-VM -Name $vmName -Verbose | Out-File $logFile -append
}

# *** Rename directory esportazione
if (Test-Path ($expPathVM)){
    (Get-Date).ToString(“yyyy-MM-dd HH:mm:ss”) +  ” Rename directory esportazione” | Out-File $logFile -append
    Move-Item $expPathVM $bkpPathVM -Verbose | Out-File $logFile -append
}

# *** Eliminazione backup obsoleti
$bkpFolders = Get-ChildItem $bkpPath | Where {$_.psIsContainer -eq $true -and $_.FullName -like ($expPathVM + “*”)} | Sort $_.FullName

if ($bkpFolders.Count -gt $bkpCopiesRetained){
    for ($i = 1; $i -le $bkpFolders.Count – $bkpCopiesRetained; $i++) {
            (Get-Date).ToString(“yyyy-MM-dd HH:mm:ss”) + ” Eliminazione backup directory ” + $bkpFolders[$i-1].FullName | Out-File $logFile -append
            Remove-Item $bkpFolders[$i-1].FullName -Recurse -Verbose | Out-File $logFile -append
        }
}

# *** Eliminazione log file obsoleti
$logFiles = Get-ChildItem $logFilePath | Where {$_.psIsContainer -eq $false -and $_.FullName -like ($logFileNameBase + “*”)} | Sort $_.FullName

if ($logFiles.Count -gt $logFilesRetained){
    for ($i = 1; $i -le $logFiles.Count – $logFilesRetained; $i++) {
            (Get-Date).ToString(“yyyy-MM-dd HH:mm:ss”) + ” Eliminazione log file ” + $logFiles[$i-1].FullName | Out-File $logFile -append
            Remove-Item $logFiles[$i-1].FullName -Verbose | Out-File $logFile -append
        }
}

# *** Termine backup
(Get-Date).ToString(“yyyy-MM-dd HH:mm:ss”) + ” Backup terminato” | Out-File $logFile –append

Per avviare lo script ad esempio da un’operazione schedulata è possibile utilizzare il comando:

%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe Path\BackupVMTest.ps1

Per poter eseguire gli script PowerShell locali occorre impostare l’execution policy ad esempio su RemoteSigned con il seguente comando (a riguardo si veda Using the Set-ExecutionPolicy Cmdlet):

Set-ExecutionPolicy RemoteSigned

Lo script può essere eseguito anche in ambiente Windows 8 dove è stato installato il Client Hyper-V, a tal proposito dal momento che sui sistemi operativi client l’account Administrator è disabilitato per default si ricordi che lo script deve essere eseguito con privilegi amministrativi.