MSEndpointMgr

Backup your Hyper-V Lab environment on Windows 8 with PowerShell

During the past few weeks Microsoft has released a lot of new cool Previews of their upcoming software. For that reason my lab environment has grown quite large, and it’s no longer effective to manually back it up. So I turned to PowerShell and wrote a script that will take care of that for me.

What the script does

The script will put all your VM’s that are running in a Saved state, export them to a given folder and then start them again (it will also export ones that are in the Off state, but not start them). In the example code further down, you’ll see that I’m exporting the VM’s to my Qnap NAS device. When you run the script, it will create a “day dir” and export each VM into a separate subfolder. If you’d set C:\Backup as the value of $BackupFolder in the script, the folder structure would be as follows:
C:\Backup\2013-07-03\<name_of_your_vm>
The script will also log certain thing it does, even errors, to C:\Backup\LogFile.txt (if that’s the root folder specified).

Get it to work

In order to get the script working, you’d need to alter two variables. The value of $BackupFolder should be set to a folder which will be used as the root for all the backups. $PSDrivePath needs to set if $BackupFolder points to an mapped network drive. In my example code below, the setup looks like this:

  • \\qnap01\Backup – mapped as N: to my workstation running Windows 8 with Hyper-V
  • \\qnap01\Backup\Hyper-V Backup is my root folder.

In order to try and illustrate it better, a picture always works best.
41_1

The script

Save the below script as Export-LabEnvironment.ps1 to your computer. I’d recommend that you run this as a scheduled task on a certain schedule of your choosing.

$Error.Clear()
$WarningPreference = "SilentlyContinue"
$Date = Get-Date -Format d
$StringDate = $Date.ToString()
$BackupFolder = "\\qnap01\Backup\Hyper-V Backup"
$LogFile = "$($BackupFolder)\LogFile.txt"
$BackupSubFolder = "$($BackupFolder)\$Date"
$PSDrivePath = "\\qnap01\Backup"
try {
    if (Test-Path -Path $PSDrivePath) {
        New-PSDrive -Name N -PSProvider FileSystem -Root $PSDrivePath -ErrorAction Stop | Out-Null
    } else {
        Write-Output "$($PSDrivePath) not found."
    }
} catch {
    Write-Output "WARNING: $($_.Exception.Message)"
}
try {
    if (!(Test-Path -Path $LogFile)) {
        New-Item -ItemType File -Path $LogFile -ErrorAction Stop | Out-Null
    }
} catch {
    Write-Output "$(Get-Date -Format G) ## ERROR: $($_.Exception.Message)" | Out-File $LogFile -Append
}
if (Test-Path -Path $LogFile) {
    Write-Output "$(Get-Date -Format G) ## Starting backup of lab environment." | Out-File $LogFile -Append
    Write-Output "$(Get-Date -Format G) ## -----------------------------------------"  | Out-File $LogFile -Append
}
try {
    $SubFolder = Get-ChildItem $BackupFolder -Name "$StringDate"
    if (-not($SubFolder -like "$($StringDate)")) {
        Write-Output "$(Get-Date -Format G) ## Creating the $($Date) folder." -ErrorAction Stop | Out-File $LogFile -Append
        New-Item -ItemType Directory -Path $BackupSubFolder -ErrorAction Stop | Out-Null
    }
} catch {
    Write-Output "$(Get-Date -Format G) ## ERROR: $($_.Exception.Message)" | Out-File $LogFile -Append
}
try {
    Get-VM | ForEach-Object {
        if ($_.State -like "Running") {
            Write-Output "$(Get-Date -Format G) ## $($_.Name) is currently running, will stop it." -ErrorAction Stop | Out-File $LogFile -Append
            Stop-VM -Name $_.Name -Save -ErrorAction Stop
            Write-Output "$(Get-Date -Format G) ## Exporting $($_.Name) to $($BackupSubFolder)." -ErrorAction Stop | Out-File $LogFile -Append
            Export-VM -Name $_.Name -Path $($BackupSubFolder) -ErrorAction Stop
            Write-Output "$(Get-Date -Format G) ## Starting $($_.Name)." -ErrorAction Stop | Out-File $LogFile -Append
            Start-VM -Name $_.Name -ErrorAction Stop
        } elseif ($_.State -like "Off") {
            Write-Output "$(Get-Date -Format G) ## $($_.Name) is already turned off." -ErrorAction Stop | Out-File $LogFile -Append
            Write-Output "$(Get-Date -Format G) ## Exporting $($_.Name) to $($BackupSubFolder)." -ErrorAction Stop | Out-File $LogFile -Append
            Export-VM -Name $_.Name -Path $($BackupSubFolder) -ErrorAction Stop
        }
    }
} catch {
    Write-Output "$(Get-Date -Format G) ## ERROR: $($_.Exception.Message)" | Out-File $LogFile -Append
}
if ($Error[0]) {
    if (Test-Path -Path $LogFile) {
        Write-Output "$(Get-Date -Format G) ## Errors have occured during backup." | Out-File $LogFile -Append
        Write-Output "$(Get-Date -Format G) ## -----------------------------------------"  | Out-File $LogFile -Append
    }
} else {
    if (Test-Path -Path $LogFile) {
        Write-Output "$(Get-Date -Format G) ## Backup completed successfully." | Out-File $LogFile -Append
        Write-Output "$(Get-Date -Format G) ## -----------------------------------------"  | Out-File $LogFile -Append
    }
}
$Error.Clear()
Remove-PSDrive -Name N -Force | Out-Null

Nickolaj Andersen

Chief Technical Architect and Enterprise Mobility MVP since 2016. Nickolaj has been in the IT industry for the past 10 years specializing in Enterprise Mobility and Security, Windows devices and deployments including automation. Awarded as PowerShell Hero in 2015 by the community for his script and tools contributions. Creator of ConfigMgr Prerequisites Tool, ConfigMgr OSD FrontEnd, ConfigMgr WebService to name a few. Frequent speaker at conferences such as Microsoft Ignite, NIC Conference and IT/Dev Connections including nordic user groups.

5 comments

  • This script is awesome. Although the date format gave me some trouble I ran it and it created several subfolders based on the date. In your screenshot there is a backup folder “2013-07-03”. When I ran the script (on 26 May 2015) it created a folder “5”, inside of that a folder “26” and inside of that a folder “2015” and in that folder it created the backups.
    G:\Hyper-V Backups\5\26\2015
    5/26/2015 8:07:25 AM ## Starting backup of lab environment.
    5/26/2015 8:07:25 AM ## —————————————–
    5/26/2015 8:07:25 AM ## Creating the 5/26/2015 folder.
    5/26/2015 8:07:25 AM ## DEMO-CM01 is currently running, will stop it.
    5/26/2015 8:07:33 AM ## Exporting DEMO-CM01 to G:\Hyper-V Backup\5/26/2015.
    I just forced the format for the Get-Date command to match your formatting:
    #$Date = Get-Date -Format d
    $Date = Get-Date -Format yyyy-mm-dd

  • For me it doesnt work on windows 8.1. I get nothing in return, no error code. So when I run it, It gives me a new command prompt instantly. I dont know how to explain exactly but it doesnt do antyhing and my vms keep running.

    • Hi Niels,
      Could you please send me your script-file to my email address found on the about page? I’ll take a look and see if I can figure it out.
      Regards,
      Nickolaj

  • How about taking a VSS snapshot, mounting the snapshot, and then backing up the VMs…

Sponsors