This page looks best with JavaScript enabled

Hyper-V Backup With Checkpoints/Snapshots

UPDATE: This post is old and intended as a walk through on how my original script was put together for those wishing to learn PowerShell. For the finished, up-to-date script please check out this post and you can download the script from my TechNet profile.

I previously posted a quick and dirty Hyper-V backup script that was very basic but did the job required at the time. I always wanted to revisit it and improve it. I’m moving the change log and updates to this page, as this post is more about the script itself. I started to look at improving the script by using the Export-VM cmdlet, however exporting to a network share requires that the Active Directory computer account of the server running the export have permission to the share, which may not be possible for some administrators. In my case, I’m backing up the VMs to a NAS appliance which I cannot add the necessary permissions to. The finished script below will copy all files related to a VM into a folder which, should you need to restore, can be easily imported through the Hyper-V import function. The script is intended to be run locally on a Hyper-V host and has been tested on Windows 10 Enterprise, Windows Server 2016 Datacenter Core, and Windows Server 2012 R2 Datacenter.

Here’s the complete script, scroll down for a detailed explanation of each section.

1
"\] # ------------------------------------------- # Script: hyper-v-backup\_v3-2.ps1 # Version: 3.2 # Author: Mike Galvin twitter.com/digressive # Date: 24/04/2017 # ------------------------------------------- ##Set Variables $vs = $env:computername #$vms = Get-VM | Where-Object {$\_.State -eq 'Running'} $vms = Get-VM $backup = "\\\\nas\\VM\_Backups\\$vs" ##Set Log Location $log = "F:\\scripts\\$vs.log" ##Set Mail Config $toaddress = "it@contoso.com" $fromaddress = "$vs@contoso.com" $subject = "$vs Hyper-V Backup Log" $mailserver = "mail.contoso.com" ##Start Log Start-Transcript $log ##For each VM do the following ForEach ($vm in $vms) { ##Create Directories New-Item "$backup\\$($vm.name)\\Virtual Machines" -ItemType directory -Force New-Item "$backup\\$($vm.name)\\VHD" -ItemType directory -Force New-Item "$backup\\$($vm.name)\\Snapshots" -ItemType directory -Force ##Stop the VM Stop-VM $vm -Verbose Start-Sleep -s 5 ##Copy the config files and folders Copy-Item "$($vm.ConfigurationLocation)\\Virtual Machines\\$($vm.id)" "$backup\\$($vm.name)\\Virtual Machines\\" -Recurse -Force -Verbose Copy-Item "$($vm.ConfigurationLocation)\\Virtual Machines\\$($vm.id).\*" "$backup\\$($vm.name)\\Virtual Machines\\" -Recurse -Force -Verbose ##Copy the VHD Copy-Item $vm.HardDrives.Path -Destination "$backup\\$($vm.name)\\VHD\\" -Recurse -Force -Verbose ##Get the snapshots $snaps = Get-VMSnapshot $vm ##For each snapshot do the following ForEach ($snap in $snaps) { ##Copy the snapshot config files and folders Copy-Item "$($vm.ConfigurationLocation)\\Snapshots\\$($snap.id)" "$backup\\$($vm.name)\\Snapshots\\" -Recurse -Force -Verbose Copy-Item "$($vm.ConfigurationLocation)\\Snapshots\\$($snap.id).\*" "$backup\\$($vm.name)\\Snapshots\\" -Recurse -Force -Verbose ##Copy the snapshot root VHD Copy-Item $snap.HardDrives.Path -Destination "$backup\\$($vm.name)\\VHD\\" -Recurse -Force -Verbose } ##Start the VM Start-VM $vm -Verbose Start-Sleep -s 60 } ##Stop Log Stop-Transcript ##Send Mail $body = Get-Content -Path $log | Out-String Send-MailMessage -To $toaddress -From $fromaddress -Subject $subject -Body $body -SmtpServer $mailserver ##END

Let’s go through each section of the script.

1
"\] ##Set Variables $vs = $env:computername #$vms = Get-VM | Where-Object {$\_.State -eq 'Running'} $vms = Get-VM $backup = "\\\\nas\\VM\_Backups\\$vs" ##Set Log Location $log = "F:\\scripts\\$vs.log" ##Set Mail Config $toaddress = "it@contoso.com" $fromaddress = "$vs@contoso.com" $subject = "$vs Hyper-V Backup Log" $mailserver = "mail.contoso.com"

Here, we set the name of the server the script is running on, along with the locations of the backup folder and the log folder. By default the script will backup all VMs on the server.

3.2 update: here we also set the parameters for the emailing of the log file.

1
"\] ##For each VM do the following ForEach ($vm in $vms) { ##Create Directories New-Item "$backup\\$($vm.name)\\Virtual Machines" -ItemType directory -Force New-Item "$backup\\$($vm.name)\\VHD" -ItemType directory -Force New-Item "$backup\\$($vm.name)\\Snapshots" -ItemType directory -Force ##Stop the VM Stop-VM $vm -Verbose Start-Sleep -s 5 ##Copy the config files and folders Copy-Item "$($vm.ConfigurationLocation)\\Virtual Machines\\$($vm.id)" "$backup\\$($vm.name)\\Virtual Machines\\" -Recurse -Force -Verbose Copy-Item "$($vm.ConfigurationLocation)\\Virtual Machines\\$($vm.id).\*" "$backup\\$($vm.name)\\Virtual Machines\\" -Recurse -Force -Verbose ##Copy the VHD Copy-Item $vm.HardDrives.Path -Destination "$backup\\$($vm.name)\\VHD\\" -Recurse -Force -Verbose

Now we create the necessary destination folders, stop the VM, copy the configuration files (.vmcx and .vmrs for Windows 10/Windows Server 2016, .xml for Windows Server 2012 R2) and folders to the destination. For VMs with no snapshots/checkpoints the VHDs associated with the VM are copied, for VMs with snapshots/checkpoints, the current active snapshot files are copied the appropriate destination location.

1
"\] ##Get the snapshots $snaps = Get-VMSnapshot $vm ##For each snapshot do the following ForEach ($snap in $snaps) { ##Copy the snapshot config files and folders Copy-Item "$($vm.ConfigurationLocation)\\Snapshots\\$($snap.id)" "$backup\\$($vm.name)\\Snapshots\\" -Recurse -Force -Verbose Copy-Item "$($vm.ConfigurationLocation)\\Snapshots\\$($snap.id).\*" "$backup\\$($vm.name)\\Snapshots\\" -Recurse -Force -Verbose ##Copy the snapshot root VHD Copy-Item $snap.HardDrives.Path -Destination "$backup\\$($vm.name)\\VHD\\" -Recurse -Force -Verbose }

For VMs with snapshots/checkpoints, this section copies the configuration files and folders to the backup location, along with the root VHD files which are not copied in the previous section when snapshots/checkpoints are present.

1
"\] ##Start the VM Start-VM $vm -Verbose Start-Sleep -s 60 } ##Stop Log Stop-Transcript ##Send Mail $body = Get-Content -Path $log | Out-String Send-MailMessage -To $toaddress -From $fromaddress -Subject $subject -Body $body -SmtpServer $mailserver

When copy is complete, the VM is started and the script waits 60 seconds before moving on to the next VM. 3.2 update: Once all VMs have been backed up, the log file is closed and then emailed using the parameters specified at the top of the script.

I take great care to test my ideas and make sure my articles are accurate before posting, however mistakes do slip through sometimes. If you’d like to get in touch with me please use the comments, Twitter (you can tweet me and my DMs are open) or my contact form. I hope this article helps you out, please consider supporting my work here. Thank you.

-Mike

Share on
Support the author with