Hyper-V WMI: Creating/Applying/Deleting Virtual Machine Snapshots


After I finished writting this I relized it got a bit long… – I guess I had a lot to talk about!  Hope you enjoy it (or at least find it mildly useful)





imageHyper-V implements a feature known as snapshots, this should not be confused with a SAN snapshot or a VSS snapshot these snapshots are quite different.  A Hyper-V snapshot allows you to save off the current state of a virtual machine even while the virtual machine is running or paused.  You can then you can revert back to this state at a latter point…  You can create tree’s of snapshots (see screen shot), think about application testing when you might need an XP RTM image, XP SP1, XP SP2, XP SP1 that was upgraded to SP2 and then rolled back to SP1 etc…  With a snapshot tree you can create all of these interesting combinations without having to reinstall a physical or virtual machine 20 times… and when the next service pack comes out you can just apply the interesting base snapshots create a new snapshot and install the service pack – Major Time Saver!


The way a snapshot works is that Hyper-V creates a copy of the virtual machine configuration (network connections, disk configuration, cpu count, ram count etc…) Hyper-V then creates a special diffrencing VHD file known as an AVHD for every virtual hard disk connected to the VM to prevent the current VHD from being changed.  If the virtual machine is running a full copy of the guest memory is also saved – unlike a saved state the virtual machine continues to run while this is occurring.  There are a few things that should be noted, since Hyper-V effectively uses a diffrencing VHD to branch the hard disk state VM’s that are using passthough disks or cd’s can not be snapshoted.  Along the same lines just like diffrencing VHD files have a disk read and write performance penalty over a fixed or even dynamically expanding VHD snapshots to incur this cost.  Another thing to note is that the AVHD file and saved memory file by default is located in the same location as the virtual machine configuration, this can be changed either by creating the virtual machine in a non-default location or more comely in the Virtual Machine Settings’s UI under Management (Snapshot File Location).


Snapshot’s are excellent for test and development they are a huge time saver.  They are also great for staging up a server you get the ability to undo when you accidentally type the wrong machine name or password… Just remember to merge your snapshots before putting the server into production, to merge a snapshot you just deleted the snapshot tree with the virtual machine off, it will then start a background merge which you can monitor from the Hyper-V management UI.  When the merge is completed you will have a flat VHD that you can then put into production with no-performance impact.  Now let’s see some code!


Taking a Snapshot




$VMManagementService = Get-WmiObject -Namespace root\virtualization -Class Msvm_VirtualSystemManagementService
$SourceVm = Get-WmiObject -Namespace root\virtualization -Query “Select * From Msvm_ComputerSystem Where ElementName=’VmToSnapshot‘”

$result = $VMManagementService.CreateVirtualSystemSnapshot($SourceVm)
#ProcessWMIJob($result)

Applying a Snapshot




$VMManagementService = Get-WmiObject -Namespace root\virtualization -Class Msvm_VirtualSystemManagementService
$SourceVm = Get-WmiObject -Namespace root\virtualization -Query “Select * From Msvm_ComputerSystem Where ElementName=‘VmToSnapshot’
$Snapshot = Get-WmiObject -Namespace root\virtualization -Query “Associators Of {$SourceVm} Where AssocClass=Msvm_ElementSettingData ResultClass=Msvm_VirtualSystemSettingData”

$result = $VMManagementService.ApplyVirtualSystemSnapshot($SourceVm, $Snapshot)
#ProcessWMIJob($result)

Deleting a Snapshot




$VMManagementService = Get-WmiObject -Namespace root\virtualization -Class Msvm_VirtualSystemManagementService
$SourceVm = Get-WmiObject -Namespace root\virtualization -Query “Select * From Msvm_ComputerSystem Where ElementName=’VmToSnapshot‘”
$Snapshot = Get-WmiObject -Namespace root\virtualization -Query “Associators Of {$SourceVm} Where AssocClass=Msvm_ElementSettingData ResultClass=Msvm_VirtualSystemSettingData”

$result = $VMManagementService.RemoveVirtualSystemSnapshot($Snapshot)
#ProcessWMIJob($result)

Enumerating Snapshots




$SourceVm = Get-WmiObject -Namespace root\virtualization -Query “Select * From Msvm_ComputerSystem Where ElementName=’VmToSnapshot‘”
Get-WmiObject -Namespace root\virtualization -Query “Associators Of {$SourceVm} Where AssocClass=Msvm_ElementSettingData ResultClass=Msvm_VirtualSystemSettingData” | Format-List -Property ElementName, InstanceID

Enumerating Snapshots – With a bit more information…




$SourceVm = Get-WmiObject -Namespace root\virtualization -Query “Select * From Msvm_ComputerSystem Where ElementName=’VmToSnapshot‘”
$Snapshots = Get-WmiObject -Namespace root\virtualization -Query “Associators Of {$SourceVm} Where AssocClass=Msvm_ElementSettingData ResultClass=Msvm_VirtualSystemSettingData”

$script:list = @()
foreach ($Snapshot in $Snapshots)
{
   
$SnapObj = New-Object -TypeName System.Object
   
$SnapObj | Add-Member -MemberType NoteProperty -Name SnapshotName -Value $Snapshot.ElementName
   
$SnapObj | Add-Member -MemberType NoteProperty -Name SnapshotID -Value $Snapshot.InstanceID
   
$SnapObj | Add-Member -MemberType NoteProperty -Name SnapshotParentName -Value ([WMI]$Snapshot.Parent).ElementName
   
$script:list += $SnapObj
}
$script:list

ProcessWMIJob Function
Put this block at the top of your script and uncomment the ProcessWMIJob call if you want the function call to wait for completion and provide error messages…



function ProcessWMIJob

   
param
    ( 
        [
System.Management.ManagementBaseObject]$Result
    ) 

   
if ($Result.ReturnValue -eq 4096)
    { 
       
$Job = [WMI]$Result.Job

       
while ($Job.JobState -eq 4)
        { 
           
Write-Progress $Job.Caption “% Complete” -PercentComplete $Job.PercentComplete
           
Start-Sleep -seconds 1
           
$Job.PSBase.Get()
        } 
       
if ($Job.JobState -ne 7)
        { 
           
Write-Error $Job.ErrorDescription
           
Throw $Job.ErrorDescription
        } 
       
Write-Progress $Job.Caption “Completed” -Completed $TRUE
    } 
   
elseif ($Result.ReturnValue -ne 0)
    { 
       
Write-Error “Hyper-V WMI Job Failed!”
       
Throw $Result.ReturnValue
    } 

ENJOY!


Taylor Brown
Hyper-V Integration Test Lead
http://blogs.msdn.com/taylorb


clip_image001

Comments (16)

  1. Marc Sherman says:

    Hi,

    In the ProcessWMIJob function, when $Result.ReturnValue is not 0 or 4096, you throw. How can we map $Result.ReturnValue to a meaningful description of the error (other than just "job failed") ?

    thanks,

    Marc

  2. Marc,

    I am working on a post for latter this week to talk about this problem – and hopefully a good solution to it…

    A stop gap is to look at the windowsvirtualzation.mof file in system32…

    -Taylor

  3. Hyper-v says:

    James O'Neill: I've decided to go ahead and post the PowerShell library I have been working on

  4. Hyper-v says:

    Hyper-V implements a feature known as snapshots, this should not be confused with a SAN snapshot or a

  5. HyperVoria says:

    James O'Neill: I've decided to go ahead and post the PowerShell library I have been working on

  6. Today, I ventured into the IT Pro field and trying to figure out how to write my first PowerShell implementation

  7. Kevin says:

    I don’t suppose you could post the VBScript version of these since power shell does not run on server core.

    Thanks,

  8. Ganga says:

    I had a question,

    I have only one VM (not running) and when I use the query: "Select * from Msvm_ComputerSystem", it gives back the result set containing details of only the host computer system and NOT the virtual machine present. Any idea why this is happening?

  9. vidhya says:

    Hi Your post was useful. But, i face problem in low disk space. Since, deletion of snapshot doesnt delete the differencing disks(.avhd) and they are not merged due to active running of VM. Is there a way to script turn off and after merge completes turn on the VM on deletion of snapshot?

     ==================================
    New Post Just For You Today!

  10. Ruffy says:

    hi, I want to stop VM integration services "Time synchronization", how to do it by hyper-v WMI programe

    Thanks

  11. MJ Almassud says:

    what an owesome job with those scripts.

    could you please tell me what changes do I need to make to allow the script that deletes snapshots, to delete all snapshots of a specific VM or something like Delete Snapshot subtree?

    I'd really appreciate your help with this.

  12. TS says:

    Taking a snapshot example above terminates in Powershell with an error

    "cannot call a method on a null value expression"

    What am i missing?

  13. Logan says:

    I do not understand where and how to run these scripts. Can you please describe how to use these scripts? Thanks.

  14. kavya says:

    i need code for creating vm using wmi in c#