Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / PowerShell

PowerShell Script to Automate Hyper V Snapshots

5.00/5 (2 votes)
8 Dec 2016Ms-PL5 min read 14.8K  
PowerShell Script to Automate Hyper V Snapshots

Do you run a bunch of VMs and need to take scheduled snapshots? And then, do you end up with so many snapshots that you fill up your hard disk(s) with so many of these files that they become meaningless? Here is a useful PowerShell scriptlet that will let you automate the hassle.

I frequently have the need to experiment, and run the cutting edge version of software, just to find out what it can do better or differently. This means, I usually have a bunch of software on my systems that are guaranteed to be unstable themselves and may be difficult to remove. The alternative is to run a whole lot of VMs. Now, you may be running VMs for a very different reason — may be you are a datacenter or a virtual server host administrator who has their production machines as VMs on a server.

The net thing is that we need to [a] take frequent backups of these machines and [b] we want to ensure that we have the least possible number of backups. For most of my needs, I take backups at key points in the lifecycle of my experiments. For example, immediately after I have a freshly installed machine ready to go (heck, I don’t want to be rebuilding and reconfiguring from scratch just to uninstall the software I am playing with). And then after I have configured it for the first time. If I am patching or upgrading the software, I have snapshots taken just before the patch or upgrade and again after I have tested that the activity has left most major functionality in a working and usable condition. And so on and so forth…. However, over a period of time, this means that your system fills up with snapshots and their related “.AVHDX” disks, consuming a lot of space. Over a period of time, I have gathered that I typically don’t want to have snapshots older than 14 days around.

In this post, I will show you how to create a neato little PowerShell script that will take care of these hassles for you. I will also show you how to stick this script into a Task Scheduler item so that it runs periodically, making your life much easier.

The Script

Since our script would be creating new snapshots as well as deleting old ones, it makes sense to do the delete first. However, note that the deletion of a snapshot is done in two stages by the underlying Hyper V service. In the first stage, the snapshot configuration is deleted and then the underlying snapshot differencing disk (“.avhdx” file) is merged into the parent VHD(X). We need to wait for both of these stages to complete before we invoke the subsequent creation of the latest snapshot.

Note: Technically, you can fire all of the commands at once and leave it to the Hyper V service’s queue to run them one after another. But this is in no way optimal performance for your VMs or your host servers. Therefore, we will introduce a small delay in between.

Get-VM | Get-VMSnapshot | Where-Object {$_.CreationTime -lt (Get-Date).AddDays(-14)} | Remove-VMSnapshot

Do
{
    Start-Sleep -s 30
} While ((Get-VM | Where-Object {$_.Status -ne "Operating normally"}) -ne $null)

Get-VM | Where-Object {$_.State -eq "Running"} | Checkpoint-VM

The first Get-VM line basically enumerates all VMs on the disk and gets their snapshots. Using the Where-Object filter, we find those snapshots that are older than 14 days. Then we queue the snapshot for deletion. At the end of this combination command, you will find each VM’s snapshot deleted and the Hyper V console (or PowerShell) show the Status column as “Merging Disks”. The Do/While loop waits for all the VMs to return to “Operating normally” status — it will have this status even if the VM is turned off — by sleeping for 30 seconds at a time. Once all VMs have “Operating normally” in their Status, we issue the Get-VM – Checkpoint-VM combination where again all Running VMs are enumerated and their checkpoints are taken.

Like I said above, I usually keep a few magic checkpoints handy and these can be older than 14 days. To prevent deletion of such VMs, we can expand the first Where-Object (the one with the CreationTime filter). I usually name such magic checkpoints with a specific prefix, example “SPECIAL – Before Patch 1.16”. So I simply need to look for this prefix (“Special”). To do this in the above command, the Where-Object filter will be changed as:

Where-Object {($_.CreationTime -lt (Get-Date).AddDays(-14)) -and ($_.Name -match '^SPECIAL.*')}

The above match condition is just a regular expression that checks for strings starting with the stringSPECIAL”.

Save the above script into a “.ps1” file.

Automation with Task Scheduler

From your system’s Administrative Tools folder, fire up “Task Scheduler”. If you are on Windows 8/8.1, switch to the Metro desktop and search for “Task Scheduler”. Once there, follow the below steps:

  1. Create a new task (“Create task” option on right-side action pane).
  2. Provide a name and description. Select the option “Run whether user is logged on or not” and check the box for “Run with highest privileges”. If you need to, click “Change User or Group” and provide account username and password of the account you wish the Task Scheduler to use to run this task… by default, it would be your account.
  3. From the dropdown list, configure the task for the version of the OS you are currently using.
  4. On the Triggers tab, click New and specify the schedule and repetition. I like to schedule this on Friday nights after 10 PM server time, repeating every 14 days (Recurrence set to 2 weeks).
  5. On the Actions tab, click New. The action should be set to “Start a program”, with the word “powershell” in the “Program/script” box. In the “Add arguments” box, enter the following:
    -command &{D:\Automation\PowerShell\Checkpoint-RunningVMs.ps1}

    (where “D:\Automation\PowerShell” is the folder where you saved the file and “Checkpoint-RunningVMs.ps1” is the file you saved it to.

  6. Go through the Conditions and Settings tabs as well and change options to ensure that the task runs only once per schedule and can be stopped if necessary.

Once you save your scheduled task, it is a good idea to try to invoke it (right-click and select Run). If there are errors, you should look in the Windows Event Log for the error messages, and fix the issues. It would also be a good idea to initially set the trigger to a time that's a few minutes later to test how it performs when it runs automatically and then once you are satisfied with the automation, change the schedule to the one you actually want.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)