Hyper-V How To: Copy-VM
Some friends here on the Hyper-V team shared a PowerShell 2.0 script for copying a VM:
################################################################################
#
# Copyright ©2008 Microsoft Corporation. All rights reserved.
#
# File: Copy-Vm.ps1
#
# THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
# ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
# PARTICULAR PURPOSE.
#
# Copyright ©2008 Microsoft Corporation. All rights reserved.
#
################################################################################param
(
[string]$VmName = $(throw "VmName required"),
[string]$Path = $(throw "Path required"),
[string]$NewName = ""
)#
# Constants
#
$SilentlyContinue = [System.Management.Automation.ActionPreference]0#
# Utility functions
## Processes the (possibly asynchronous) result of a method call on one
# of Hyper-V's service objects, and return the resulting object, if any.
function ProcessResult
{
param
(
[System.Management.ManagementBaseObject]$Result,
[ScriptBlock]$ExtractScript = $null,
[string]$ResultClass = ""
)$RetObj = $null
if ($Result.ReturnValue -eq 0)
{
if ($ExtractScript -ne $null)
{
$RetObj = [WMI] ($Result | Select-Object -inputObject $ExtractScript)
}
}
else
{
if ($Result.ReturnValue -ne 4096)
{
throw $Result.ReturnValue
}
$Job = [WMI]$Result.Job
while ($Job.JobState -eq 4)
{
Write-Progress $Job.Caption "% Complete" -PercentComplete $Job.PercentComplete
Start-Sleep 1
$Job.PSBase.Get()
}if ($Job.JobState -ne 7)
{
throw $Job.ErrorDescription
}Write-Progress $Job.Caption "Completed" -Completed $true
if ($ResultClass -ne "")
{
$Query = "Associators of {$Job} Where ResultClass=$ResultClass AssocClass=Msvm_AffectedJobElement"
$RetObj = Get-WmiObject -Namespace root\virtualization -Query $Query
}
}if ($RetObj -ne $null)
{
$RetObj
}
}#
# Main script body
##Stop script exection on errors
Set-Variable $ErrorActionPreference Stop# If no target name was specified, generate a generic one
if ($NewName -eq "")
{
$NewName = "Copy of " + $VmName
}# If we are going to display progress bars, clear the console window so that
# we can see the progress bars more clearly,
if ($ProgressPreference -ne $SilentlyContinue)
{
Clear-Host
Write-Host "Copying `"$VmName`" to `"$NewName`"..."
}# Get the service object
$VmSvc = Get-WmiObject -Namespace root\virtualization -Class Msvm_VirtualSystemManagementService# Find the virtual machine to copy.
$Query = @"
Select * From Msvm_ComputerSystem Where
ElementName='$VmName' Or
Name='$VmName'
"@$SourceVm = Get-WmiObject -Namespace root\virtualization -Query $Query
# Since the virtual machine name is not unique, we need to check for
# multiples. If there is more than one, we'll return an error.
$SourceCount = [int]0
if ($SourceVm -ne $null)
{
$SourceCount = [int]($SourceVm | Measure-Object).Count
}if ($SourceCount -eq 0)
{
throw "Virtual machine `"$VmName`" not found."
return
}
elseif ($SourceCount -ne 1)
{
if ($ProgressPreference -ne $SilentlyContinue)
{
Write-Host "The name `"$VmName`" has been given to multiple virtual machines. Specify the source virtual machine by ID instead. The IDs for virtual machines with this name are listed below."
$SourceVm | `
Select-Object @{Name="ID";Expression={$_.Name}},@{Name="Name";Expression={$_.ElementName}} | `
Format-Table -AutoSize
}
throw "The name `"$VmName`" has been given to multiple virtual machines."
}# Export the virtual machine
$Result = $VmSvc.ExportVirtualSystem($SourceVm, $true, $Path)
$Temp = ProcessResult $Result# Rename the export directory
$CopyPath = (Join-Path $Path $VmName | Rename-Item -NewName $("Copy of " + $VmName) -PassThru)# Import the virtual machine
$Result = $VmSvc.ImportVirtualSystem($CopyPath, $true)
$CopyVm = ProcessResult $Result {throw "Unexpected error."} Msvm_ComputerSystem# Rename the copy virtual machine to "Copy of $VmName"
$Query = @"
Associators of {$CopyVm} Where
ResultClass=Msvm_VirtualSystemSettingData
AssocClass=Msvm_SettingsDefineState
"@$CopyVssd = Get-WmiObject -Namespace root\virtualization -Query $Query
$CopyVssd.ElementName = "Copy of " + $CopyVssd.ElementName$Result = $VmSvc.ModifyVirtualSystem($CopyVm, $CopyVssd.PSBase.GetText(1))
$Temp = ProcessResult $Result {$_.ModifiedSettingData} Msvm_VirtualSystemSettingData# Update and return the copied virtual machine object
$CopyVm.PSBase.Get()
$CopyVm
For more info on how to use PS cmdlets see: https://www.microsoft.com/technet/scriptcenter/topics/msh/cmdlets/index.mspx
See also James O’Neil’s New and improved PowerShell Library for Hyper-V. Now with more functions and... documentation!
For all 35 sample Hyper-V PS1 scripts in a zipfile, go to: Hyper-V PowerShell Example Scripts.zip-download