Post info:

PowerCLI Script to migrate VMs from one vCenter to another

Hey everyone, this is another guest post from Ben Liebowitz, Matt’s brother.

Before I get into the script, I’ll give you some background…  We are working on migrating VMs off of our vSphere 4.1 environment to our new vSphere 5.5 environment.  The 4.1 environment is using the Nexus 1000v Virtual Switch while the 5.5 environment is using a vDS switch.

We found the easiest way to migrate the VMs was to remove them from inventory on the 4.1 side and then add them to inventory on the 5.5 side (as all the hosts in each environment saw the same storage).  Doing this manually for approx 250 VMs was painful, so I scripted the process.

I started with exporting the VM’s information regarding its name, datastore location, Network Portgroup(s), & folder location.  I found that by using the folder location in Get-VM, I was just getting it’s current folder name and not the full path.  Being I have folder name duplicates (one in an Internal Folder and the same structure in a DMZ folder) I needed a way to list the full path.  Thankfully, I found a Function written by Luc Dekens (@LucD22 / that he called #BlueFolderPath that solved my problem.

After that, I was able to connect to the 4.1 vCenter, export my list, shutdown the VM, remove it from inventory, then connect to my 5.5 vCenter, browse that same datastore, add the VM to inventory on the other side, move the VM to its original folder location, set the proper network portgroup, upgrade the virtual hardware, power the VM on, and finally upgrade the VMware tools.


# Define Variables
$vcenter41 = “your existing vcenter”
$vcenter55 = “your new vcenter”
$vsphere55host = “one of the vSphere 5.5 hosts to migrate to”
$datacenter = “datacenter name”
$csvfile = “path to csv”

#Build the BlueFolderPath function
New-VIProperty -Name 'FullPath' -ObjectType 'VirtualMachine' -Value {

$current = Get-View $vm.ExtensionData.Parent
$path = ""
do {
$parent = $current
if($parent.Name -ne "vm"){$path =  $parent.Name + "/" + $path}
$current = Get-View $current.Parent
} while ($current.Parent -ne $null)
} -Force | Out-Null

#Build the Get-folderbypath function
function Get-FolderByPath {
.SYNOPSIS  Retrieve folders by giving a path
.DESCRIPTION The function will retrieve a folder by it's
path. The path can contain any type of leave (folder or
.NOTES  Author:  Luc Dekens
The path to the folder.
This is a required parameter.
.PARAMETER Separator
The character that is used to separate the leaves in the
path. The default is '/'
PS> Get-FolderByPath -Path "Folder1/Datacenter/Folder2"
PS> Get-FolderByPath -Path "Folder1>Folder2" -Separator '>'

[parameter(Mandatory = $true)]
[char]${Separator} = '/'

if((Get-PowerCLIConfiguration).DefaultVIServerMode -eq "Multiple"){
$vcs = $defaultVIServers
$vcs = $defaultVIServers[0]

foreach($vc in $vcs){
foreach($strPath in $Path){
$root = Get-Folder -Name Datacenters -Server $vc
$strPath.TrimStart($Separator).Split($Separator) | %{
$root = Get-Inventory -Name $_ -Location $root -Server $vc -NoRecursion
if((Get-Inventory -Location $root -NoRecursion | Select -ExpandProperty Name) -contains "vm"){
$root = Get-Inventory -Name "vm" -Location $root -Server $vc -NoRecursion
$root | where {$_ -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.FolderImpl]}|%{
Get-Folder -Name $_.Name -Location $root.Parent -Server $vc

# Enable connections to multiple vCenters
Set-PowerCLIConfiguration -DefaultVIServerMode Multiple -Scope AllUsers -Confirm:$false

# Connect to 4.1 vCenter
connect-viserver vsphere41

# export list of VMs to Migrate to CSV
Get-Datacenter -name "datacenter" | Get-VM |
Select Name, @{N="Datastore";E={Get-Datastore -VM $_ | Select -ExpandProperty Name}},
@{N="Network";E={Get-VirtualPortgroup -VM $_ | Select -ExpandProperty Name}},
@{N="Parent";E={$_.FullPath}} |
Export-Csv "c:\migrate.csv" -NoTypeinformation -UseCulture

# Get VMs to Migrate
$migrate = Get-Datacenter -name "datacenter"

# Shutdown VMs (cleanly)
$migrate | Get-VM | Shutdown-VMGuest -Confirm:$false

# Wait for VMs to shutdown
start-sleep -s 60

# Remove VMs from Inventory
Get-datacenter -name "datacenter" | Get-Inventory | Remove-Inventory -Confirm:$false

# Connect to 5.5 vCenter
connect-viserver vsphere55

# Set a host in vcenter5.5 to add them to.
$esxhost = "vsphere01.domain.local"

## Add backto inventory & Change network for VMs
foreach ($row in (Import-Csv $csvfile)) {
$vmName = $row.Name
$vmxfile = "[$($row.Datastore)] $($vmName)/$($vmName).vmx"
$vmNewVM = New-VM -VMFilePath $vmxfile -VMhost $esxhost

# Move VM to existing folder locaiton
Move-VM -VM $row.Name -Destination (get-folderbypath $row.Parent)

# Change Network Portgroup
$vm = get-vm -Name $row.Name
Get-NetworkAdapter -VM $vm | Set-NetworkAdapter -NetworkName $row.Network -Confirm:$false

# Upgrade Virtual Hardware
Set-VM -VM $vmName -Version v10

# Poweron VMs
Start-VM -VM $row.Name -Confirm:$false | wait-tools
Get-VMQuestion -VM $vm | Set-VMQuestion –Option "I moved it" -confirm:$false

# Update VMware Tools
update-tools $vmName -Confirm:$false
start-sleep -s 300

} ## end foreach


Share This:

23 thoughts on “PowerCLI Script to migrate VMs from one vCenter to another

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.