I've successfully created scripts on exporting files/folder, etc. and importing, but I'm having a hard time figuring out how to script the hosts and clusters view. I have a ROBO vcenter with tons of datacenters and clusters and obviously don't want to create by hand. I don't need all the cluster settings, I simply want the datacenter and clusters "shell". Any powercli script help for exporting all the datacenters and clusters and then re-importing to populate new vcenter would be greatly appreciated. I went through these boards but no one really seems to be doing exactly this.
@LucD yeah, now I get this.
Get-Folder : Cannot bind parameter 'Type'. Cannot convert value "blue" to type "VMware.VimAutomation.ViCore.Types.V1.Inventory.FolderType". Error: "Unable to match the identifier name blue
to a valid enumerator name. Specify one of the following enumerator names and try again:
VM, HostAndCluster, Datacenter, Datastore, Network"
At D:\Scripts\vCenter Scripts\ImportNetworkFolders.ps1:15 char:96
+ ... atacenter -Name $dcName | Get-Folder -Name $dummy -Type $row.Type) }
+ ~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-Folder], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetFolder
That's normal, I thought the type would say network.
The export needs to adapted
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
@LucD A different export script entirely? I remember reading about this one you did, but I couldn't figure out how to do it for just datastore or network folders?
New-VIProperty -Name 'BlueFolderPath' -ObjectType 'VirtualMachine' -Value { param($vm) function Get-ParentName{ param($object) if($object.Folder){ $blue = Get-ParentName $object.Folder $name = $object.Folder.Name } elseif($object.Parent -and $object.Parent.GetType().Name -like "Folder*"){ $blue = Get-ParentName $object.Parent $name = $object.Parent.Name } elseif($object.ParentFolder){ $blue = Get-ParentName $object.ParentFolder $name = $object.ParentFolder.Name } if("vm","Datacenters" -notcontains $name){ $blue + "/" + $name
} else{ $blue
} } (Get-ParentName $vm).Remove(0,1) } -Force | Out-Null
$dcName = "MyDC"
Get-VM -Location (Get-Datacenter -Name $dcName) | Select Name,BlueFolderPath |Export-Csv "C:\vm-folder.csv" -NoTypeInformation -UseCulture
Try these
For export
function Get-FolderPath {
<#
.SYNOPSIS
Returns the folderpath for a folder
.DESCRIPTION
The function will return the complete folderpath for
a given folder, optionally with the "hidden" folders
included. The function also indicats if it is a "blue"
or "yellow" folder.
.NOTES
Authors: Luc Dekens
.PARAMETER Folder
On or more folders
.PARAMETER ShowHidden
Switch to specify if "hidden" folders should be included
in the returned path. The default is $false.
.EXAMPLE
PS> Get-FolderPath -Folder (Get-Folder -Name "MyFolder")
.EXAMPLE
PS> Get-Folder | Get-FolderPath -ShowHidden:$true
#>
param(
[parameter(valuefrompipeline = $true,
position = 0,
HelpMessage = "Enter a folder")]
[VMware.VimAutomation.ViCore.Impl.V1.Inventory.FolderImpl[]]$Folder,
[switch]$ShowHidden = $true
)
begin {
$excludedNames = "Datacenters", "vm", "host"
}
process {
$Folder | ForEach-Object {
$fld = $_.Extensiondata
$fldType = "yellow"
if ($fld.ChildType -contains "Network") {
$fldType = "blue"
}
$path = $fld.Name
while ($fld.Parent) {
$fld = Get-View $fld.Parent
if ((!$ShowHidden -and $excludedNames -notcontains $fld.Name) -or $ShowHidden) {
$path = $fld.Name + "\" + $path
}
}
$row = "" | Select-Object Name, Path, Type
$row.Name = $_.Name
$row.Path = $path
$row.Type = $fldType
$row
}
}
}
$hidden = 'Datacenters','host','vm','network','datastore','vCLS'
Get-Folder | where{$_.Name -notin $hidden} |
Select @{N='Path';E={(Get-FolderPath -Folder $_).Path}} |
Export-Csv -Path .\export-folder.csv -NoTypeInformation -UseCulture
For import
Import-Csv -Path .\export-folder.csv -UseCulture -PipelineVariable row |
ForEach-Object -Process {
$root,$dcName,$path = $row.Path.Split('\',3)
$location = Get-Datacenter -Name $dcName
$path.Split('\') | ForEach-Object -Process {
$name = $_
try{
$location = Get-Folder -Name $_ -Location $location -ErrorAction Stop
}
catch{
New-Folder -Name $name -Location $location
}
}
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Getting some new errors on the import with these scripts....
New-Folder : 10/18/2022 7:35:09 AM New-Folder '10/18/2022 7:35:09 AM Get-Folder Folder with name 'Virtual Machine' was not found using the specified filter(s). ' is invalid or exceeds the maximum number of characters
permitted.
At line:10 char:7
+ New-Folder -Name $_ -Location $location
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [New-Folder], InvalidName
+ FullyQualifiedErrorId : Client20_InventoryServiceImpl_NewFolder_ViError,VMware.VimAutomation.ViCore.Cmdlets.Commands.NewFolder
New-Folder : 10/18/2022 7:35:09 AM New-Folder '10/18/2022 7:35:09 AM Get-Folder Folder with name 'VMkernel' was not found using the specified filter(s). ' is invalid or exceeds the maximum number of characters permitted.
At line:10 char:7
+ New-Folder -Name $_ -Location $location
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [New-Folder], InvalidName
+ FullyQualifiedErrorId : Client20_InventoryServiceImpl_NewFolder_ViError,VMware.VimAutomation.ViCore.Cmdlets.Commands.NewFolder
my .csv output
"Path"
"Datacenters\testing2\network\Virtual Machine"
"Datacenters\testing2\network\VMkernel"
"Datacenters\testing2\datastore\System"
"Datacenters\testing2\datastore\Virtual Machine"
My bad, I forgot that the $_ variable inside a catch-block contains the error, not the value from the loop.
I corrected the code above
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thanks for all the help. These scripts worked perfectly in my Lab but got the same errors in my other system. I think something is wrong with the PowerCLI install. It does the very first line in the import script and then simply errors out the rest with the same error. I do notice the $PSTableVersion shows 5.1.19041.1682 for the lab one and the non-working one is 5.1.14393.2125.
Those PS version differences shouldn't cause those errors.
You are sure that $name variable I added is there?
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Yeah, i got your updated script and it worked fine in my lab. I have to use the other powershell instance because of security; basically I'm running it from a jumpbox that has access to those particular vcenters.
i run it and it just errors.
New-Folder : Cannot convert 'System.Object[]' to the type 'VMware.VimAutomation.ViCore.Types.V1.Inventory.VIContainer' required by parameter 'Location'. Specified
method is not supported.
At line:11 char:40
+ New-Folder -Name $name -Location $location
+ ~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [New-Folder], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgument,VMware.VimAutomation.ViCore.Cmdlets.Commands.NewFolder
But that is again that original error which seems to indicate an array instead of single object is passed on the Location parameter.
You could do those 2 tests I mentioned yesterday
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
@LucD Get-Datacenter on any of the DC's just return one value.
The 2nd command returns 3 values Get-Datacenter -Name 'robo.dc.00001' | Get-Folder -Name 'Network'
Name Type
---- ----
network Network
Network VM
Network VM
So you have 2 VM folders that are named Network, and on Network folder that is also named Network.
Not sure how to code around that (yet)
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
yeah, i was thinking the same thing. so I tried adding -type network to your script. It worked...kind of. created my network folders, but also created a bunch of folders at the hosts and clusters view at the Datacenter root. I'm thinking I could just edit my .csv and trim out everything except the network folders
Import-Csv -Path c:\temp\export-networkfolder-test.csv -UseCulture -PipelineVariable row |
ForEach-Object -Process {
$root,$dcName,$path = $row.Path.Split('\',3)
$location = Get-Datacenter -Name $dcName
$path.Split('\') | ForEach-Object -Process {
$name = $_
try{
$location = Get-Folder -Type Network -Name $_ -Location $location -ErrorAction Stop
}
catch{
New-Folder -Name $name -Location $location
}
}
}