Sometimes I find it easier to create a new vCenter server then migrate the old one, and it is a perfectly good solution in many cases.
But annoyingly there is a lot of manual work involved.
One problem is the VM’s and Templates folders. They do not follow the host, so you have to create the folder structure manually and move each VM into the correct folder. Well I am way to lazy to do that by hand, so it’s time to Automate!
The following powershell code was created and testet in vSphere PowerCLI 6.5.1. Everything here is used at your own risk. I do not recommend that you use it through copy paste. Please read and understand the code before you execute.
Any suggestions or alterations are most welcome. This code should not be consider done or production ready. It was something I created in 1 hour to solve an ad-hoc problem.
Prerequisites
Before running the code you have installed and configured you new vCenter. You have disconnected your hosts from the old vCenter, but not removed anything from it. So the status on the old vCenter is that VMs and Hosts are disconnected.
You have connected your hosts to the new vCenter, and migrated any switches and VM networking. All hosts and VMs are connected to your vCenter, and they are located in the root folder or in Discovered VMs.
You should be good to go. Good Luck!
The Script
Import-Module VMware.PowerCLI
$global:DefaultVIServers | Disconnect-VIServer -Confirm:$false
$srcVc = "fqdn of source vCenter"
$dstVc = "fqdn of destination vCenter"
Connect-VIServer $srcVc
Connect-VIServer $dstVc
$sourceDatacenterName = "<source datacenter name>"
$targetDatacenterName = "<destination datacenter name>"
$moveVms = $true # Should VMs in target vCenter be moved to folders by Name best effort
# Checks if folder already exists
Function Check-Folder($f, $t) {
$result = $true
Try {
Get-Folder -Location $t -Name $f.Name -ErrorAction Stop
#Write-Host "Folder Found"
$result = $true
}
Catch {
#Write-Host "Folder does not exist"
$result = $false
}
return $result
}
# Creates the folder and moves the VMs
Function Create-Folder($f, $t, $move, $targetRoot) {
if (Check-Folder -f $f -t $t) {
Write-Host "!!!Folder already exists: " $f.Name
} else {
Write-Host "Creating Folder: " $f.Name
$targetFolder = New-Folder -Name $f.name -Location $t
if ($moveVms) {
#Write-Host "Moving VMs"
$VMs = Get-VM -Location $f -NoRecursion
foreach ($vm in $VMs) {
Write-Host "Moving VM:" $VM.Name
Try {
$targetVM = Get-VM -Name $vm.name -Location $targetRoot -ErrorAction Stop
if ($targetVM.Length -gt 1) {
Write-Host "Multiple VMs Error"
throw("Multiple VMs found")
} else {
Write-Host "Found VM:" $targetVM.name
# Pre vSphere 6.7
# $moveJob = Move-VM $targetVM -Location $targetFolder
# vSphere 6.7
$moveJob = Move-VM $targetVM -InventoryLocation $targetFolder
}
}
Catch {
Write-Host "Could not find VM:" $vm.name
}
}
}
Create-SubFolders -f $f -t $targetFolder -move $move -targetRoot $targetRoot
}
}
# Cycles through subfolders and creates them
Function Create-SubFolders($f, $t, $move, $targetRoot) {
$subFolders = Get-Folder -Location $f
foreach ($folder in $subFolders) {
Create-Folder -f $folder -t $t -move $move -targetRoot $targetRoot
}
}
# MAIN
$sourceLocation = Get-folder -Server $srcVc -Name vm | Where-Object { $_.Parent -match "^$($sourceDatacenterName)$" }
$targetLocation = Get-folder -Server $dstVc -Name vm | Where-Object { $_.Parent -match "^$($targetDatacenterName)$" }
$sourceRootFolders = Get-Folder -Server $srcVc | Where-Object { $_.Parent -eq $sourceLocation -and $_.Type -eq "VM" }
# Goes through all root folders in sourceDatacenter
foreach ($folder in $sourceRootFolders) {
# Create Root Folders
if (Check-Folder -f $folder -t $targetLocation) {
Write-Host "Folder already exists: " $folder.Name
} else {
#Write-Host "Creating Folder: " $folder.Name
Create-Folder -f $folder -t $targetLocation -move $moveVms -targetRoot $targetLocation
}
}
Notes
Please note that this code will only create folders and move VMs if the folder does not already exist in the target vCenter Datacenter. It will also move the VM multiple times, since I am finding the VMs in folder recursive. This is because many VMs end up in the Discovered VMs Folder, and I was ok with this happening, so I did not bother finding a better solution.
If you old and new datacenters have the same name, you can just find the object for them i another way at the top of the script. Or you can alter the names temporarily.
Please leave any suggestions or comments below.
Great Script
This script is amazing. Worked perfectly for helping me migrate from a 5.5 cluster to 6.5U1D
🙂
This worked great from vCenter 6.0 to 6.5. Thank you!!
Doesnt seem to work for 6.7 :\
What errors are your getting?
Script is not working for me. I have this error.
“Folder already exists: Discovered VMs”
It should not stop the script, but if your VMs are located in Discovered VMs, there might not be a good reason to use this script. Unless it is only some of them.
Great Script, worked like a charm – even though this was my experience running powercli.
I Moved one cluster last week and planning to move another tomorrow. yesterday when i ran the script it created all folders, can I run it second time so newly migrated VMs can be moved to existing folders? looking script I dont think it will do that or am I miss reading it? how difficult would be create a separate function just to move VMs to folder – so script can be run multiple times?
Thanks again,
You should be able to run it multiple times, it should only create folders if they do not already exist.
Thank you for your script,
Our environment is unique in that we use VM names with square brackets, e.g. “[prod] Service ABC”. Which is recognized by Get-Folder and Get-VM as regler expressions and generates errors.
With some modifications, I am able to migrate VMs from VC6.7 to VC7.0.
https://gist.github.com/jcppkkk/0e54ed7a879b29fefce4da691d4a1b9b