Migrate folder structure from old to new vSphere vCenter

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.

View Comments (13)

  • This script is amazing. Worked perfectly for helping me migrate from a 5.5 cluster to 6.5U1D

  • 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.

Related Post