VMware Cloud Community
adrianallan
Contributor
Contributor
Jump to solution

Recursive New-Folder

I am moving from one virtual center to another. I have created a script that will recreate the datacenters and clusters.

I am having problems figuring out how to recreate the folders. These folders can be buried as far as 4 deep in hierarchy so even though I can do a get-folder and find the folders I am not sure how to put them back the way I they are laided out in the original VC

$1 = Get-Folder | where-object { $_.name -notlike "Discovered virtual machine"} |`

where-object { $_.name -notlike "vm"} | where-object { $_.name -notlike "Datacenters"}|`

where-object { $_.name -notlike "host"}

$1 | export-Clixml test.xml

The code above of course does not have (I don't think) the information to put the folders back in hierachy when I do -

$newfolder = Import-Clixml .\test.xml

$newfolder | foreach-Object{

Get-Folder -Name VM -Location $_.DataCenter | New-Folder -Name $_.Folder

}

Quick Note: Some of our folders are 4 levels deep

Any assistance appreciated.

Thanks

I also have to copy the resourcepool info so figuring out this step would help.

Trying this:

$new= New-Object System.Collections.ArrayList

$c = $null

$a = Get-Folder testvm

$count = 0

while(! ($c.name -eq "vm")){

$Info = "" |Select Bottom, Up, count

#$new = Get-Folder $a.name

$Info.bottom = $a

$b = $a.parentid

$c = get-folder -id $b

$Info.up = $c.name

$a = $c

$info.count = $count++

$New.add($Info)

}

I have this peice working but I still have to start the build from the vm level down

Reply
0 Kudos
1 Solution

Accepted Solutions
avlieshout
VMware Employee
VMware Employee
Jump to solution

I created the following 2 function for this. Give it a try.

Just replace the $src and $dst parameters with the parameter that holds the connection to your vCenter server like this:

$src = Connect-VIServer "your vCenter server" -NotDefault

I've also attached a little text file with the functions.

-


#Export folder structure (no datacenter folders!)
function Export-Folders {
	filter Get-FolderStructure {
		$folder = "" | select Name,Children
		$folder.Name = $_.name
		$folder.Children = @($_ | Get-Folder -NoRecursion | Get-FolderStructure )
		$folder
	}
	$FolderStructure=@{}
	Get-Datacenter -Server $src | %{$FolderStructure[http://$_.name|http://$_.name] = $_ | Get-Folder -NoRecursion | Get-FolderStructure}
	$FolderStructure | Export-Clixml "Folders.xml"
}

-


#Import folder structure (no datacenter folders!)
function Import-Folders {
	$FolderStructure = Import-Clixml "Folders.xml"
	filter New-FolderStructure {
		param($parent)
		if (-not($folder = Get-Folder $_.name -Location $parent -ErrorAction:SilentlyContinue)) {$folder = New-Folder $_.name -Location $parent}
		$_.children | New-FolderStructure($folder)
	}
	$FolderStructure.GetEnumerator() | %{$dc = get-datacenter $_.name -server $dst; $_.value | New-FolderStructure($dc)}
}

-


Arnim van Lieshout

Blogging:

Twitter:

If you find this information useful, please award points for "correct" or "helpful".

Arnim van Lieshout Blogging: http://www.van-lieshout.com Twitter: http://www.twitter.com/avlieshout If you find this information useful, please award points for "correct" or "helpful".

View solution in original post

Reply
0 Kudos
9 Replies
avlieshout
VMware Employee
VMware Employee
Jump to solution

I created the following 2 function for this. Give it a try.

Just replace the $src and $dst parameters with the parameter that holds the connection to your vCenter server like this:

$src = Connect-VIServer "your vCenter server" -NotDefault

I've also attached a little text file with the functions.

-


#Export folder structure (no datacenter folders!)
function Export-Folders {
	filter Get-FolderStructure {
		$folder = "" | select Name,Children
		$folder.Name = $_.name
		$folder.Children = @($_ | Get-Folder -NoRecursion | Get-FolderStructure )
		$folder
	}
	$FolderStructure=@{}
	Get-Datacenter -Server $src | %{$FolderStructure[http://$_.name|http://$_.name] = $_ | Get-Folder -NoRecursion | Get-FolderStructure}
	$FolderStructure | Export-Clixml "Folders.xml"
}

-


#Import folder structure (no datacenter folders!)
function Import-Folders {
	$FolderStructure = Import-Clixml "Folders.xml"
	filter New-FolderStructure {
		param($parent)
		if (-not($folder = Get-Folder $_.name -Location $parent -ErrorAction:SilentlyContinue)) {$folder = New-Folder $_.name -Location $parent}
		$_.children | New-FolderStructure($folder)
	}
	$FolderStructure.GetEnumerator() | %{$dc = get-datacenter $_.name -server $dst; $_.value | New-FolderStructure($dc)}
}

-


Arnim van Lieshout

Blogging:

Twitter:

If you find this information useful, please award points for "correct" or "helpful".

Arnim van Lieshout Blogging: http://www.van-lieshout.com Twitter: http://www.twitter.com/avlieshout If you find this information useful, please award points for "correct" or "helpful".
Reply
0 Kudos
adrianallan
Contributor
Contributor
Jump to solution

This script worked perfectly, I have to admit I don’t yet understand all of how it does what it does but I’m working on it. I created all my folders the way I wanted, I am running a test on how I can make sure the right VM’s get placed in those folders

Thank you for your help

Reply
0 Kudos
adrianallan
Contributor
Contributor
Jump to solution

#Export folder structure (no datacenter folders!)

function Export-Folders {

filter Get-FolderStructure {

#$src = Connect-VIServer vcusa -NotDefault

$folder = "" | select Name,Children,Vm

$folder.Name = $_.name

$folder.Children = @($_ | Get-Folder -NoRecursion | Get-FolderStructure )

$vmname = @(Get-VM -Location $_ -NoRecursion)

$folder.Vm = $vmname.name

$folder

}

$FolderStructure=@{}

Get-Datacenter -Server $src | %{$FolderStructure[http://$_.name|http://$_.name] = $_ | Get-Folder -NoRecursion | Get-FolderStructure}

$FolderStructure | Export-Clixml "Folders.xml"

}

I added the get-vm line to get the vm's under that folder so I could move it back into the folder

But I am not sure how to iterate throught the file to do the move-vm cmdlet? - Tips?

Reply
0 Kudos
avlieshout
VMware Employee
VMware Employee
Jump to solution

Exporting VMs and their locations:

#Export vm locations
function Export-VmLocations {
	filter Get-Path {
		param($child)
		$folder = Get-View -Server $src $_.parent
	
		if ($folder.gettype().name -eq "Datacenter") {
			$child
		} else {
			$path = "" | select Name,Child
			$path.name = $folder.name
			$path.child = $child
			$folder | Get-Path($path)
		}
	}
	$VmLocations = @()
	foreach ($vm in Get-VM -Server $src) {
		$VmObj = "" | Select Name,Datacenter,Path
		$VmObj.Name = $vm.name
		$VmObj.Datacenter = $($vm | Get-Datacenter).name
		$VmObj.Path = $vm | Get-View | Get-Path
		$VmLocations += $VmObj
	}
	$VmLocations | Export-Clixml "VmLocations.xml"
}

-


Import Vm's again:

#Import vm locations (Move vm's to original location)
function Import-VmLocations {
	filter Get-VmLocation {
		param($parent)
		if ($_.child) {
			$_.child | Get-VmLocation(Get-Folder -Server $dst -Location $parent $_.Name)
		} else {
			Get-Folder -Server $dst -Location $parent $_.Name
		}
	}
	foreach ($vm in (Import-Clixml "VmLocations.xml")) {
		$dc = Get-Datacenter -Server $dst $vm.datacenter
		Move-VM ($dc | Get-VM $vm.Name) -Destination ($vm.path | Get-VmLocation($dc)) 
	}
}

-


Have fun!

Arnim van Lieshout

Blogging: http://www.van-lieshout.com

Twitter:

If you find this information useful, please award points for "correct" or "helpful".

Arnim van Lieshout Blogging: http://www.van-lieshout.com Twitter: http://www.twitter.com/avlieshout If you find this information useful, please award points for "correct" or "helpful".
adrianallan
Contributor
Contributor
Jump to solution

This is EXACTLY what I am looking for, I've tried the export and create folder function it worked great I've not used the putting the vm's back in place yet but I'll be testing it this weekend

Reply
0 Kudos
adrianallan
Contributor
Contributor
Jump to solution

Apologies in advance.

Is there a way I can modify the folder and VM folder scripts to work on single Datacenters at a time. My requirement has changed and some folks would rather move one DC at a time vs. having the script just move all of the VC (we are also breaking off one of the DC's into their own VC).

Reply
0 Kudos
RvdNieuwendijk
Leadership
Leadership
Jump to solution

If you change Arnim's Export-Folders function you can export only one datacenter. You have to change:

Get-Datacenter -Server $src 

into:

Get-Datacenter -Name YourDatacenter -Server $src 

If you want to use Arnim's Export-VmLocations function you have to change:

foreach ($vm in Get-VM -Server $src) {

into:

foreach ($vm in (Get-Datacenter -Name YourDatacenter | Get-VM -Server $src)) {

Robert

Message was edited by: RvdNieuwendijk

Blog: https://rvdnieuwendijk.com/ | Twitter: @rvdnieuwendijk | Author of: https://www.packtpub.com/virtualization-and-cloud/learning-powercli-second-edition
A_Mikkelsen
Expert
Expert
Jump to solution

Thanks for the scripts, they work like a charm. Also on vSphere 4.1.

If you need to restore the folders and VM's to a new datacenter then change the following lines.

Import-Folders

$FolderStructure.GetEnumerator() | %{$dc = get-datacenter $_.name -server $dst; $_.value | New-FolderStructure($dc)}

into

$FolderStructure.GetEnumerator() | %{$dc = get-datacenter -Name "New_DataCenter" -server $dst; $_.value | New-FolderStructure($dc)}

Import-VM's

$dc = Get-Datacenter -Name $vm.datacenter -Server $dst

into

$dc = Get-Datacenter -Name "New_DataCenter" -Server $dst

If you found this or any other answer useful please consider the use of the Helpful or correct buttons to award points.

Regards

A. Mikkelsen

If you found this or any other answer useful please consider the use of the Helpful or correct buttons to award points. Regards A. Mikkelsen
Reply
0 Kudos
A_Mikkelsen
Expert
Expert
Jump to solution

If you get an error while importing, check if you in the folders parent, is a sub folder with the same name as the one you are creating.

To get around the error, change the if statement in the filter (add -NoRecursion)

from

if (-not($folder = Get-Folder $_.name -Location $parent -ErrorAction:SilentlyContinue)) {$folder = New-Folder $_.name -Location $parent}

to

if (-not($folder = Get-Folder $_.name -Location $parent -ErrorAction:SilentlyContinue -NoRecursion)) {$folder = New-Folder $_.name -Location $parent}

If you found this or any other answer useful please consider the use of the Helpful or correct buttons to award points.

Regards

A. Mikkelsen

If you found this or any other answer useful please consider the use of the Helpful or correct buttons to award points. Regards A. Mikkelsen
Reply
0 Kudos