I originally wrote this script for my own clusters to upgrade them from Windows Server 2008 R2 to Windows Server “8” Beta and since then I have shared it with a few others who also found it very helpful.  I had some designs on improving it but decided I would put those on hold until later.  The script is pretty straight forward it gathers all of the information about a VM from the source cluster and then does in import from the source cluster to the destination machine having Hyper-V copy all of the VHD and other configuration files.  The script takes advantage of a few new Hyper-V features in Window Server “8” Beta – specifically the ability to import directly from a VM configuration file as well as our new Hyper-V PowerShell cmdlet’s.  If you want more details on Compare-VM, Import-VM or any of the other cmdlet’s take a look at the TechNet documentation.

 

 

Script Limitations and Assumptions

All of these can be worked around – but many will be handled better in future releases (i.e. RC/RTM) thus I did not spend to much time scripting around them.

  • Must Be Run on a Windows Server “8” Beta Hyper-V Host
  • VM’s must be using CSV
  • VM’s VHD’s must all be on the same CSV and the same folder and must be located under the “Virtual Hard Disks” Folder
  • VM’s can not have snapshots (due to a bug in Windows Server “8” Beta)

 

 

 

function Migrate-VMFromR2Cluster {
     param (
     [Parameter(Mandatory
=$true,Position=0,HelpMessage="Name Of The VM To Be Migrated")]
     [
String]
     $VmName,
     [Parameter(Mandatory
=$true,Position=0,HelpMessage="Name Of The Source Cluster")]
     [
String]
     $SourceCluster,
     [Parameter(Mandatory
=$true,Position=0,HelpMessage="Path Where The VM Will Be Copied To On Local Machine")]
     [
String]
     $TargetVMPath,
     [Parameter(Mandatory
=$true,Position=0,HelpMessage="Name Of The Virtual Switch The VM Will Be Connected To")]
     [
String]
     $TargetHyperVSwitchName
)

#Get all of the VM's settings on the source server, we have to do this prior to offlining the configuration file
$SourceServer = ((Get-ClusterGroup $VmName -Cluster $SourceCluster).OwnerNode).Name
$SourceVM = Get-WmiObject -Namespace "root\virtualization" -ComputerName $SourceServer -Class "Msvm_ComputerSystem" -Filter "ElementName = '$VmName'"
$VmDataRoot = ($SourceVM.GetRelated("Msvm_VirtualSystemGlobalSettingData").ExternalDataRoot.ToLower()).Replace("c:\", "\\$SourceServer\c`$\")
$VmConfigurationFile = ($VmDataRoot+ "\Virtual Machines\" + $SourceVM.Name + ".xml")
$VhdSourcePath = ($VmDataRoot + "\Virtual Hard Disks")
$Msvm_VirtualSystemSettingData = ($SourceVM.GetRelated("Msvm_VirtualSystemSettingData") | % {$_})
$Msvm_SyntheticEthernetPortSettingDataCollection = $Msvm_VirtualSystemSettingData.GetRelated("Msvm_SyntheticEthernetPortSettingData")

#Get all of the VLAN and networking configurations for the VM
#
- this is requried as in Windows 2008 and 2008 R2 we store the network settings in the switch configuration not with the VM
#
- in Windows Server "8" Beta there was a bug that this data was also not present in the export file
$SwitchPortSettings = New-Object -TypeName System.Collections.Hashtable
foreach ($Msvm_SyntheticEthernetPortSettingData in $Msvm_SyntheticEthernetPortSettingDataCollection)
{
    
$Msvm_SwitchPort = $Msvm_SyntheticEthernetPortSettingData | % {[WMI]($_.Connection| % {$_})}
     if ($Msvm_SwitchPort.__Path -ne $null)
     {
          $Msvm_VLANEndPoint = $Msvm_SwitchPort.GetRelated("Msvm_VLANEndPoint") | % {$_}
          $Msvm_VLANEndpointSettingData = $Msvm_VLANEndPoint.GetRelated("Msvm_VLANEndpointSettingData") | % {$_}
          $SwitchPortSettings.Add($Msvm_SyntheticEthernetPortSettingData.InstanceID, 
            
@($Msvm_SwitchPort, $Msvm_VLANEndpointSettingData.AccessVLAN))
     }
}

#Offline the VM's configuration file so that we can open in for Import
(Get-ClusterGroup $VmName -cluster $SourceCluster) | Get-ClusterResource | Stop-ClusterResource | Out-Host

#Generate a VM compatability object which will be used to fixup all the network adapters
#
- note that copy is specified meaning the VHDs will be copied over the network
$compare = Compare-VM -Copy -Path $VmConfigurationFile -VhdSourcePath $VhdSourcePath -VhdDestinationPath $TargetVMPath -VirtualMachinePath $TargetVMPath

#Fixing network adapters and make sure they use correct VMSwitch and keep VLAN ID and mac spoofing settings
Foreach ($NetworkAdapter in $Compare.vm.NetworkAdapters)
{
     $NetworkAdapter | Connect-VMNetworkAdapter -SwitchName $TargetHyperVSwitchName
     $NicSetting = $SwitchPortSettings[$NetworkAdapter.Id]
     if ($NicSetting -ne $null)
     {
         $NetworkAdapter | Set-VMNetworkAdapterVlan -Access -VlanId $NicSetting[1]
         if ($NetworkAdapter[0].AllowMacSpoofing)
         {
             $NetworkAdapter | Set-VMNetworkAdapter -MacAddressSpoofing On
         }
     }
}
Import-VM -CompatibilityReport $Compare
Set-VM -Name $VmName -AutomaticStopAction ShutDown
}

Taylor Brown
Hyper-V Enterprise Deployment Team
taylorb@microsoft.com
http://blogs.msdn.com/taylorb

WS08R2-HyperV_v_rgb