#requires -version 3.0

<#
These commands require the Hyper-V module and appropriate permissions
This is not a script to run from start to finish but a series of commands
that demonstrate key steps in converting a snapshot to a virtual machine.

  ****************************************************************
  * DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED *
  * THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK.       *
  *     DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING.         *
  ****************************************************************

#>

#not really necessary in PowerShell 3 because of auto-loading
Import-Module Hyper-V

#Testing with the local server
$Server = $env:COMPUTERNAME

<#
Path to store exports. This will be created if it doesn't exist. 
It is relative to the server.
#>
$ExportPath = "E:\Exports"
#name of VM to export
$VMName= "Test Rig"
#snapshot name, which will be name of imported VM as well
$SnapName= "$VMName Clone"

#region create the snapshot

#create the snapshot with a custom name. This will use the default path for snapshots

$snapshot = Checkpoint-VM -Name $VMName -SnapshotName $SnapName -ComputerName $Server -Passthru
#this is what you get
$snapshot

#endregion

#region Export the snapshot to disk

#the snapshot has computer information so export is ON the server
$export = Export-VMSnapshot -VMSnapshot $snapshot -Path $ExportPath -Passthru 

#$export is a snapshot object
$export

#here are the exported files
dir E:\Exports -Recurse

#endregion

#region create new VM re-using exported disk

#use values from snapshot
$clone = New-VM -Name $snapshot.Name -NoVHD -MemoryStartupBytes $snapshot.MemoryStartup -switch "Private Data" -ComputerName $Server 

#add hard drives using the exported drives, not the ones in the path
ForEach ($drive in $Snapshot.HardDrives) {
    #I want to use the exported disk files not the ones the snapshot points to.
    $VHD = Split-Path -leaf ($drive.path)

    #construct the path to the Virtual Hard Disk Folder and
    #the path to what should be the boot drive
    $VHDPath = Join-Path (Join-Path (Join-Path $ExportPath $VMName) "Virtual Hard Disks") $VHD
    
    #define a hash table for Add-VMHardDiskDrive parameters
    $addDriveHash=@{
     VMName=$Clone.Name
     Path=$VHDPath
     ControllerType=$drive.ControllerType
     ControllerNumber=$drive.ControllerNumber
     ControllerLocation=$drive.ControllerLocation
     Computername=$Server
    }
    
    #The parameters to be passed to Add-VMHardDiskDrive
    $addDriveHash
    
    Add-VMHardDiskDrive @addDriveHash 
} #foreach drive

#adjust VM with settings from snapshot
#create a hashtable of snapshot values to apply to the clone
$paramhash=@{
MemoryStartupBytes=$snapshot.MemoryStartup
ProcessorCount=$snapshot.ProcessorCount
Notes="Cloned $(Get-Date)"
Name=$($clone.Name)
Computername=$Server
}

if ($snapshot.DynamicMemoryEnabled) {
    $paramhash.Add("DynamicMemory",$snapshot.DynamicMemoryEnabled)
    $paramhash.Add("MemoryMinimumBytes",$snapshot.MemoryMinimum)
    $paramhash.Add("MemoryMaximumBytes",$snapshot.MemoryMaximum)
}

#add other settings as needed
Set-VM @paramhash

#the final result
Get-VM $clone.name -ComputerName $Server | Select *

#endregion

#region import snapshot as new VM

#modify XML configuration if you want to change the name.
$VMPath = Join-Path (Join-Path $ExportPath $VMName) "Virtual Machines"
$VMConfigPath = (dir $vmpath -filter *.xml).FullName
#should be only one xml file
[xml]$config = Get-Content -Path $VMConfigPath

#rename snapshot name if you want
$config.configuration.properties.name.'#text'="My Cloned VM"

#save the config file
$config.Save($VMConfigPath)

<#
#If running this remotely these commands can be done via a remoting session.
 $sb = {
 $VMPath = Join-Path (Join-Path $using:ExportPath $using:VMName) "Virtual Machines"
 $VMConfigPath = (dir $using:vmpath -filter *.xml).FullName
 [xml]$config = Get-Content -Path $VMConfigPath
 $config.configuration.properties.name.'#text'="My Cloned VM"
 #save the config file
 $config.Save($VMConfigPath)
 }
Invoke-Command $sb -computername $Server
#>

#import the snapshot
#register in place. Existing machine must be gone. Not an issue if importing on
#a different server.
Import-VM -Path $VMConfigPath -Register -whatif

#or I could have copied using existing path since original disks still exist in default location
$VHDPath = (Join-Path (Join-Path $ExportPath $VMName) "Virtual Hard Disks")
#VhdDestinationPath is marked obsolete but it works
Import-VM -Path $VMConfigPath -Copy -GenerateNewId -VhdDestinationPath $VHDPath -ComputerName $server

#endregion