Trying to find a quick way to import all the VM & Templates (aka BLUE Folders) from Site A to Site B. Each Site has its own vCenter with multiple "Datacenters" located inside. I just want all the folders and subfolders of one Datacenter.. Now that explained here's whats happening
Exporting Site A folders using this line of code is working perfectly:
Get-Datacenter "Datacenter1" | Get-Folder | Get-FolderPath | Export-Csv "C:\Scripts\learning\folders.csv" -NoTypeInformation
I get a nice CSV file with NAME and PATH headings with all the names and paths of each folder.
Now when I try to Create the folders at Site B, it doesnt work most of the time. All these failed:
Import-Csv $importlist -UseCulture | %{
New-Folder -Name $_."Name" -Location $_."Path"
}
Import-Csv $importlist -UseCulture | %{
New-Folder -Name $_."Name" -Location (Get-Folder -Name $_."Path")
}
Import-Csv $importlist -UseCulture | %{
New-Folder -Name $_."Name" -Location (Get-Datacenter "Datacenter1" | Get-Folder -Name $_."Path")
}
Now.. if I do that last script AND remove "DATACENTER1" from the cell in CSV file under Path, the root folders get created. Still no joy on the subfolders.
Now I have reviewed other code in other posts on this site. And several from "some of people who are on this site offen and wrote some books" (you know who you are ). None of them work for me. All I need is to have several hundred (yes hundred) folders created with multi-sub levels deep. Some case 5 or 6 levels deep.. IE: DATACENTER\VM\ROOT FOLDER\ SUB LEVEL1\SUB LEVEL2\SUB LEVEL3\SUB LEVEL4\ <here be vms>
Thanks,
Boston Tech Guy
Ok, try this updated version
$root = Get-Folder -Name Datacenters
$folders= Import-Csv C:\folder.csv -UseCulture
$folders |
where {"vm","host","network","datastore" -notcontains $_.Name} |
Sort-Object -Property {(Select-String -InputObject $_.Path -Pattern '\\+' -AllMatches).Matches.Count} | %{
$location = $root
$qualifiers = $_.Path.Split('\')
$qualifiers[0..($qualifiers.Count -2)] | %{
$location = Get-Inventory -Name $_ -Location $location -NoRecursion
if($location.EXtensionData -is [VMware.Vim.Datacenter]){
$location = Get-Folder -Name vm -Location $location
}
}
New-Folder -Name $_.Name -Location $location
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
The New-Folder cmdlet unfortunately doesn't allow to specify a folderpath for the Location parameter.
But you could try something like this
$root = Get-Folder -Name Datacenters
Import-Csv $importlist -UseCulture |
Sort-Object -Property {(Select-String -InputObject $_.Path -Pattern '/+' -AllMatches).Matches.Count} | %{
$location = $root
$qualifiers = $_.Path.Split('/')
$qualifiers[0..($qualifiers.Count -2)] | %{
$location = Get-Inventory -Name $_ -Location $location
}
New-Folder -Name $qualfiers[-1] -Location $location
}
We start in the 'root' of the vCenter.
The script first take the folders with shortest path.
It follows all the qualifiers in the Path, except for the last one, which is the new folder.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Still getting errors. Also my editor is not recognizing some of the strings used in the code above. Here is what PowerGUI shows for the code
$root = Get-Folder -Name Datacenters
Import-Csv $importlist -UseCulture |
Sort-Object -Property {(Select-String -InputObject $_.Path -Pattern '/+' -AllMatches).Matches.Count} | %{
$location = $root
$qualifiers = $_.Path.Split('/')
$qualifiers[0..($qualifiers.Count -2)] | %{
$location = Get-Inventory -Name $_ -Location $location
}
New-Folder -Name $qualfiers[-1] -Location $location
}
The script you have provided is above my knowledge to understand without some help. The errors I am getting back are:
Get-Inventory : 8/5/2013 11:24:07 AM | Get-Inventory | Inventory with name 'vm\FolderTest' was not found using the specified |
filter(s).
At C:\Users\##########\AppData\Local\Temp\a3e47d9d-2312-40d2-8767-bd6fea574ca1.ps1:17 char:21
+ | $location = Get-Inventory -Name $_ -Location $location | |
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
+ CategoryInfo | : ObjectNotFound: (:) [Get-Inventory], VimException | |
+ FullyQualifiedErrorId : Core_OutputHelper_WriteNotFoundError,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetInventory |
I used the Get-Inventory cmdlet because it can return any object by name from your vSphere hierarchy.
In the Path that is imported from the CSV there can be different type of nodes in there; datacenter, folder...
The Path content is deconstructed in separate qualifiers. The script starts on the left and stores the object in the $location variable.
For the last qualifier in the Path, the script assumes it is a Folder, and so it creates the folder.
The error seems to come from the Path with value vm\FolderTest.
That is apparently a folder created in the root of the vSphere hierarchy.
I find it strange that the Path seems to contain a back-slash, I would assume that the Path only has forward-slashes.
What do you see in the CSV file ? Back- or forward-slash ?
If it is all back-slashes, the argument for the Split method has to be changed to '/'.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
That is interesting... The output in the CSV file from my Export Script above is this:
#TYPE Selected.System.String | |
Name | Path |
vm | DATACENTER1\vm |
network | DATACENTER1\network |
host | DATACENTER1\host |
datastore | DATACENTER1\datastore |
Security | DATACENTER1\Security |
Foldertest | DATACENTER1\Foldertest |
Test1 | DATACENTER1\Foldertest\Test1 |
Test 2 | DATACENTER1\Foldertest\Test 2 |
Clearly "\"
Now I changed the Path.Split to a backslash, got errors. Changed all the forward slashes in quotes to backslashes, got errors... They were all the same
Cannot index into a null array.
At C:\Users\\########\AppData\Local\Temp\a3e47d9d-2312-40d2-8767-bd6fea574ca1.ps1:19 char:5
+ New-Folder -Name $qualfiers[-1] -Location $location
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : NullArray
When back to my test CSV replaced all the backslashes with forward slashes, went back to your original code AND... got new errors:
Get-Inventory : 8/5/2013 1:36:23 PM Get-Inventory Inventory with name 'vm' was not found using the specified filter(s). At C:\Users\########\AppData\Local\Temp\a3e47d9d-2312-40d2-8767-bd6fea574ca1.ps1:17 char:21
+ $location = Get-Inventory -Name $_ -Location $location + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (:) [Get-Inventory], VimException + FullyQualifiedErrorId : Core_OutputHelper_WriteNotFoundError,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetInventory
Those first 4 lines are hidden system folders that are present in the vSphere hierarchy.
I should adapt the script to skip those when they are the last qualifier, since you obviously can't create them.
Try perhaps with removing lines 3-6 from the CSV (the vm, host, network and datastore lines)
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Already did that on the IMPORT CSV. :smileycool: Then I created a plain testing CSV file just to get a success. My testing CSV is listed below.
Name | Path |
NewTest1 | vm |
NewSub1 | vm\Foldertest |
NewSub2 | vm\Foldertest |
Ok, now I see where I went wrong, I assumed the CSV only had the Path column in there.
Something like this
Path
vm\NewTest1
vm\Foldertest\NewSub1
vm\Foldertest\NewSub2
I'll have to update the script.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Ahhhh. OK. Thank you. Would it be better for me to change the CSV File?
You can give it a try with an updated CSV
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Just did. No go. Plus in the long run, that wouldnt help with all the folders that need to be created at the second location to look like the original source.
Ok, try this updated version
$root = Get-Folder -Name Datacenters
$folders= Import-Csv C:\folder.csv -UseCulture
$folders |
where {"vm","host","network","datastore" -notcontains $_.Name} |
Sort-Object -Property {(Select-String -InputObject $_.Path -Pattern '\\+' -AllMatches).Matches.Count} | %{
$location = $root
$qualifiers = $_.Path.Split('\')
$qualifiers[0..($qualifiers.Count -2)] | %{
$location = Get-Inventory -Name $_ -Location $location -NoRecursion
if($location.EXtensionData -is [VMware.Vim.Datacenter]){
$location = Get-Folder -Name vm -Location $location
}
}
New-Folder -Name $_.Name -Location $location
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Ok got some forward movement. :smileygrin: Still getting error messages though.. Folders at the parent level worked. None of the subfolders.
I am using a test CSV file so not to play with production systems but everything is setup the same. When I run my export script on my DEV Environment I get the list located below (same as what I posted previously):
#TYPE Selected.System.String | |
Name | Path |
vm | DATACENTER1\vm |
network | DATACENTER1\network |
host | DATACENTER1\host |
datastore | DATACENTER1\datastore |
Security | DATACENTER1\Security |
Foldertest | DATACENTER1\Foldertest |
Test1 | DATACENTER1\Foldertest\Test1 |
Test 2 | DATACENTER1\Foldertest\Test 2 |
So to add new folders and sub folders to my Dev environment my test CSV file looks like this:
Name | Path |
NewParent1 | DATACENTER1\vm |
NewSub1 | DATACENTER1\vm\Foldertest |
NewSub2 | DATACENTER1\vm\Foldertest |
With the new code that you have provided I get these error messages (they come back very very quick) on Sub Folders. The folder NewParent1 was created.
Get-Inventory : 8/5/2013 3:52:20 PM Get-Inventory Inventory with name 'vm' was not found using the specified filter(s). At C:\Users\######\AppData\Local\Temp\a3e47d9d-2312-40d2-8767-bd6fea574ca1.ps1:18 char:21
+ $location = Get-Inventory -Name $_ -Location $location -NoRecursion + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (:) [Get-Inventory], VimException + FullyQualifiedErrorId : Core_OutputHelper_WriteNotFoundError,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetInventory
New-Folder : 8/5/2013 3:52:20 PM New-Folder Value cannot be found for the mandatory parameter Location At C:\Users\######\AppData\Local\Temp\a3e47d9d-2312-40d2-8767-bd6fea574ca1.ps1:23 char:5
+ New-Folder -Name $_.Name -Location $location + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [New-Folder], VimException + FullyQualifiedErrorId : Core_BaseCmdlet_UnknownError,VMware.VimAutomation.ViCore.Cmdlets.Commands.NewFolder
Get-Inventory : 8/5/2013 3:52:21 PM Get-Inventory Inventory with name 'vm' was not found using the specified filter(s). At C:\Users\######\AppData\Local\Temp\a3e47d9d-2312-40d2-8767-bd6fea574ca1.ps1:18 char:21
+ $location = Get-Inventory -Name $_ -Location $location -NoRecursion + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (:) [Get-Inventory], VimException + FullyQualifiedErrorId : Core_OutputHelper_WriteNotFoundError,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetInventory
New-Folder : 8/5/2013 3:52:21 PM New-Folder Value cannot be found for the mandatory parameter Location At C:\Users\######\AppData\Local\Temp\a3e47d9d-2312-40d2-8767-bd6fea574ca1.ps1:23 char:5
+ New-Folder -Name $_.Name -Location $location + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [New-Folder], VimException + FullyQualifiedErrorId : Core_BaseCmdlet_UnknownError,VMware.VimAutomation.ViCore.Cmdlets.Commands.NewFolder
Thanks.
My test CSV file looked like this (the one you gave earlier).
Name | Path |
vm | DATACENTER1\vm |
network | DATACENTER1\network |
host | DATACENTER1\host |
datastore | DATACENTER1\datastore |
Security | DATACENTER1\Security |
Foldertest | DATACENTER1\Foldertest |
Test1 | DATACENTER1\Foldertest\Test1 |
Test 2 | DATACENTER1\Foldertest\Test 2 |
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
That should be perfectly fine. Also that is what this script is going to use in Production. I only created a small CSV file to test with as I dont have two DEV environments.
But does the script work correctly when the CSV looks like that ?
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Luc,
Sorry I didnt get back to you yesterday. Started building out a new datacenter for a client.
YES! The script worked perfectly. I even went 4 levels deep into a directory, still kept working.
This is huge! This script would now give a simple process of exporting folder structure from vCenter and using the same file to import/create the folders in a second vCenter. This would be key if you were working on... oh I dont know... say a massive SRM Project
Thank you!!!!! HUGE!!!
Boston Tech Guy
Hey
I want to copy the folder structure from our current vCenter to new Vcenter
Folder structure will be like this ( Same folder name can come in various paths)
UR\User1\Folder1\1
UR\User1\Folder1\1\2
UR\User1\Folder2\2
UR\User2\Folder4\4
UR\User2\Folder4\4\4\5\2
UR\User2\Folder4\4\4\5\2\Folder1
I have used the attached script, however it create the folder Structure as shown in the screenshot attached.
Where do you initialise $Folderpath?
Btw, always nice when you mention the source of your code.
I assume you forgot that you got this code from the post "PowerCLI to Generate Nested VM Folder Structure".
In the Remarks on that post, you'll notice that the same issue has been reported there as well.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
I apologies. Yeh That was my source for the code.
Yeh I noticed it after couple of hours and have fixed the issue now.
Thanks for your time and comments 🙂