How to copy folders structure between two virtual center servers ?

Hello !
It is some time since i posted last time. There was quite a lot happening in my life lately so that’s why 😉 I’ve spent huge amount of time on my first lecture that was given in Poland at PLVMUG,
plvmug.q1.2013-26-700x464 (1)
after that i was back again in Poland to see my family on Easter. But anyway… i am lately having more free time, so i can share some of my thoughts with you again 😉
This time i want to show how we can copy folder structures between different virtual center servers. For example if you have to make a migration between virtual center servers, there is a lot to think of while doing this. You can’t forget about your annotations, folders(structure), location of virtual machines.
If you are migrating 20-50 vms, that’s not a big deal to move that kind of volume between VC, but what if you need to migrate 1000 or 2000 or 10000 vms ? And probably you don’t keep virtual machines inside ‘Discovered virtual machines’ folder, but you already have some structure.
This example was built based on example where cluster vms are attached to 1 folder structure. So if you have a virtual center and datacenter within, i assume here that structure looks like this:
‘blue\vm folders\’
‘\Datacenter X\ Cluster_Omega\Somefolder_with_Structure’

This function is able to move not only folder structures between VC but it also generates list of virtual machines and their folder ids, to which they should be moved. So if all my vms from cluster Omega resides somewhere in folder ‘Somefolder_with_Structure\x\y\z\’ you can grab the output of script to variable :
$mvlist=Copy-VCFolderStructure ….
While copying the folder structure this funtion will also return an array of vms with Name and Folder property, where the Folder property is actually an ID of a folder on the new virtual center server in which this vm should be placed.

function Copy-VCFolderStructure {
		Copy-VCFolderStructure copies folder and its structure from one VC to another..

		Copy-VCFolderStructure can be handy when doing migrations of clusters/hosts between
		Virtual Center servers. It takes folder structure from 'old' VC and it recreates it on 'new'
		VC. While doing this it will also output virtualmachine name and folderid. Why would you
		want to have it ? Let's say that you have a cluster on old virtual center server
		Copy-VCFolderStructure will copy entire folder structure to 'new' VC, and while doing this
		it will output to screen VMs that resides in those structures. VM name that will be shown on
		screen will show also folderid, this ID is the folderid on new VC.  After you have migrated
		your hosts from old cluster in old VC to new cluster in new VC, and folder structure is there,
		you can use move-vm cmdlet with -Location parameter. As location you would have give the
		folder object that corresponds to vm that is being moved. Property Name is the name of VM
		that was discovered in that folder and Folder is the folderid in which the vm should be moved
		into. This folderid has to first changed to folder, for example :
		$folderobj=get-view -id $folder|Get-VIObjectByVIView
		We can then use $folderobj as parameter to move-vm Location parameter

	.PARAMETER  OldFolder
		This should be the extensiondata of folder that you want to copy to new VC.
		$folderToRecreate=Get-Folder -Server oldVC.lab.local -Name teststruct
		Have in mind that this should be an single folder and not an array.

	.PARAMETER  ParentOfNewFolder
		When invoking the function this is the root folder where you want to attach the copied folder.
		Let's say you are copying folder from \DatacenterA\FolderX\myfolder
		If you will have the same structure on the new VC, you would have set ParentOfNew folder
		to FolderX. Still it's not a problem if you have a new structure on new VC. Let's say that on
		new VC you have folder: \DatacenterZ\NewStructure\FolderZ and you want to copy entire
		'myfolder' beneath the FolderZ. In that case, first create a variable that has desired folder
		$anchor=get-folder 'FolderZ' -Server newVC
		Make sure that $anchor variable will have only 1 element.

		This parameter describes virtual center to which we are copying the folder structure.
		Copy-VCFolderStructure works only when you are connected to both old and new vc at the
		same time. You need to set your configuration of PowerCLI to handle multiple connections.
		Set-PowerCLIConfiguration -DefaultVIServerMode 'Multiple'
		You can check if you are connected to both servers using $global:DefaultVIServers variable

		This parameter describes virtual center from which we are copying the folder structure.
		Copy-VCFolderStructure works only when you are connected to both old and new vc at the
		same time. You need to set your configuration of PowerCLI to handle multiple connections.
		Set-PowerCLIConfiguration -DefaultVIServerMode 'Multiple'
		You can check if you are connected to both servers using $global:DefaultVIServers variable

		PS C:\> Set-PowerCLIConfiguration -DefaultVIServerMode 'multiple'
		PS C:\> $DefaultVIServers
		Ensure that you are connected to both VC servers
		Establish variables:
		This will be the folder that we will be copying from old VC
		$folderToRecreate=Get-Folder -Server $OldVC -Name 'teststruct'
		This will be the folder to which we will be copying the folder structure
		$anchor=get-folder 'IWantToPutMyStructureHere' -Server $NewVC
		Copy-VCFolderStructure -OldFolder $folderToRecreate.extensiondata -NewVC $NewVC
		-OldVC $OldVC -ParentOfNewFolder $anchor
		$OldFolder expects to get extensiondata object from the folder, if you will not provide it, function will
		block it.

		If you are planning to move vms after hosts/vm/folders were migrated to new VC, you might use it in this way.
		By default Copy-VCFolderStructure will output also vms and their folder ids in which they should reside on new
		VC. You can grab them like this:
		$vmlist=Copy-VCFolderStructure -OldFolder $folderToRecreate.extensiondata -NewVC $NewVC
		-OldVC $OldVC -ParentOfNewFolder $anchor
		You can now export $vmlist to csv
		$vmlist |export-csv -Path 'c:\migratedvms.csv' -NoTypeInformation
		And once all virtual machines are in new virtual center, you can import this list and do move-vm operation on those
		vms. Each vm has name and folder properties. Folder is a folderid value, which has to be converted to Folder object.
		move-vm -vm $vmlist[0].name -Location (get-view -id $vmlist[0].folder -Server $newVC|get-viobjectbyviview)
		-Server $newVC
		This would move vm that was residing in previously on old VC in migrated folder to its equivalent on new VC.

		NAME:  Copy-VCFolderStructure

		AUTHOR: Grzegorz Kulikowski

		NOT WORKING ? #powercli @ 

		THANKS: Huge thanks go to Robert van den Nieuwendijk for helping me out with the recursion in this function.



   [parameter(Mandatory = $true)]
   [parameter(Mandatory = $true)]
   [parameter(Mandatory = $true)]
   [parameter(Mandatory = $true)]
  $NewFolder = New-Folder -Location $ParentOfNewFolder -Name $OldFolder.Name -Server $NewVC
  Get-VM -NoRecursion -Location ($OldFolder|Get-VIObjectByVIView) -Server $OldVC|Select-Object Name, @{N='Folder';E={$}}
  foreach ($childfolder in $OldFolder.ChildEntity|Where-Object {$_.type -eq 'Folder'})
                   Copy-VCFolderStructure -OldFolder (Get-View -Id $ChildFolder -Server $OldVC) -ParentOfNewFolder $NewFolder -NewVC $NewVC -OldVC $OldVC

My example:
We have our VcOld: at : vc1.lab.local My cluster is CL_Holandia

Our NewVC before the movement looks like this:
As you can see in dc_new there is a folder that should keep my folder structure called: ‘Some_Holder’


On NewVC we have now structure like this:
We are connected to 2 virtual center servers : vc.lab.local and vc2.lab.local
Our cluster folder is named CL_Holandia where we keep all vms that are inside the cluster.
We are defining folder to be copied from old_VC:
$folderToRecreate=get-folder -Server $oldVC -Name ‘CL_Holandia’
we define to which folder this structure should go:
$anchor=get-folder’CL_Holandia’ -Server $newVC
We store VMs in variable $Vmlist
$vmlist=Copy-VCFolderStructure -OldFolder $folderToRecreate.extensiondata -ParentOfNewFolder $Anchor -NewVC $NewVC
-OldVC $OldVC


When we will add the cluster to new VC we will have structure probably like this. There will be additional ‘Discovered virtual machine’ folder, where all vms will appear and the rest of our copied structure. That means that we should now move vms to their proper folders.

After the last movement we will see proper structure:
It’s time now to move our vms from cluster from old VC, to folder of NEW cluster in NEW NC. So we will use now
$Vmlist variable do to this:
foreach($vm in $vmlist) {move-vm -vm $ -destination (get-view -id $vm.folder|get-viobjectbyviview)}
This should do it. We should see now our structure with vms and folder in proper place.
I do realize that i write this post at 1 am, but this is the only time i guess now that i have it free… So i know there might be some issues/bugs with this code. Please post a comment whenever you see some error. I will try to fix it as soon as possible. Please note that not all of you should have the same setup as me. This solution in regards of moving vms on new VC to proper folders will work only if you have similar folder structure(1 CL x 1 main_folder). I will try to rewrite this function entirely in order to make it as compatible with all structures as it can be.
At the end i would like to thank to Robert van den Nieuwendijk for his time and effort in writing this function. Without him it would take ages for me to write this recursion…
I hope that this function will help some of you with similar setup when you need to do migrations.

*images from PLVMUG session were taken from: