VMware Cloud Community
JBartholomew
Enthusiast
Enthusiast
Jump to solution

Issues with Get-FolderbyPath when connected to multiple vCenters

I am currently in the process of creating a script to automate batch creation of our VMs in various vCenters, and have reached the point where the VM Creation is doing exactly what I need, but it is still creating the VM in the root folder within the vCenter.

I started looking around for solutions on how to move the VM to the correct folder, or create the VM in the correct folder from the start, and came across the Get-FolderbyPath function created by LucD.

I started playing around with the function, and am struggling to get it to give me exactly what I need.

The biggest part of the issue is that our folder structure within each vCenter is a.) very similar to each other, and b.) each vCenter contains many of the same folder names

Our Folder layout is Datacenter/Company/Project/Environment, and so as a rough example we have folders called:

Paris/Company/Project/Environment

Ottawa/Company/Project/Environment

So if I am connected to only the Paris vCenter and run Get-FolderbyPath -Path "Paris/Company/Project/Lab" I get only one result and if I pipe that to a Get-VM I can verify that I only see the VMs I expect to be seeing.

But if I am connected to vCenter using -allLinked and run the same command I get multiple results, and I believe I have narrowed down what is happening, but I am not sure why.

When running the Get-folderbypath when connected to multiple vCenters the below is what is happening

If I am looking for "Paris/Company/Project/Lab" as a path, when the script runs through the Paris vCenter I only get one result (the expected result), but then the script runs through against the Ottawa vCenter, and if it does not have an exact "Company/Project/Lab" path it returns any folder that is named "Lab" no matter where its located, so the Folder results are as below:

IE.)

Paris/Company/Project/Lab

Ottawa/Company/Project2/Lab

Ottawa/Company/Project5/Lab

Ottawa/Company4/Project/Lab

The very strange part is that we also have folders such as below that are NOT being returned by the Get-Folderbypath function:

Paris/Company/Project2/Lab

Paris/Company2/Project/Lab

Paris/Company4/Project5/Lab

But if we do have an exact "Company/Project/Lab" Path in both vCenters the results are

Paris/Company/Project/Lab

Ottawa/Company/Project/Lab

and in this case the

Ottawa/Company/Project2/Lab

Ottawa/Company/Project5/Lab

Ottawa/Company4/Project/Lab

Paths are not shown.

So I am trying to figure out how to get the Get-folderbypath function to only give me Paris/Company/Project/Lab when connected to multiple vCenters or if that exact path doesn't exist, return 0 entries so I know it doesn't exist so I can instruct my script to create the new folder as required.

Tags (1)
Reply
0 Kudos
1 Solution

Accepted Solutions
LucD
Leadership
Leadership
Jump to solution

I just added the Server parameter to the function.
See it that can solve your issue.

Now you can do

Get-FolderByPath -Path 'DC//Folder1' -Server 'vcsa.domain'

and also

Get-FolderByPath -Path 'DC/Homelab/Folder1' -Server $global:defaultVIServer

The updated function

function Get-FolderByPath {

<#

.SYNOPSIS Retrieve folders by giving a path

.DESCRIPTION The function will retrieve a folder by it's path.

   The path can contain any type of leave (folder or datacenter).

.NOTES

   Author: Luc Dekens

.PARAMETER

   Path The path to the folder. This is a required parameter.

.PARAMETER

   Separator The character that is used to separate the leaves in the path. The default is '/'

.EXAMPLE

   PS> Get-FolderByPath -Path "Folder1/Datacenter/Folder2"

.EXAMPLE

   PS> Get-FolderByPath -Path "Folder1>Folder2" -Separator '>'

#>

    param(

        [CmdletBinding()]

        [parameter(Mandatory = $true)]

        [System.String[]]${Path},

        [char]${Separator} = '/',

        [PSObject]$Server

    )

    process {

        if ($Server) {

            if ($Server -is [String]) {

                $vcs = $global:defaultVIServers | Where-Object { $_.Name -eq $Server }

            }

            else {

                $vcs = $Server

            }

        }

        else {

            if ((Get-PowerCLIConfiguration).DefaultVIServerMode -eq "Multiple") {

                $vcs = $global:defaultVIServers

            }

            else {

                $vcs = $global:defaultVIServers[0]

            }

        }

        foreach ($vc in $vcs) {

            $si = Get-View ServiceInstance -Server $vc

            $rootName = (Get-View -Id $si.Content.RootFolder -Property Name).Name

            foreach ($strPath in $Path) {

                $root = Get-Folder -Name $rootName -Server $vc -ErrorAction SilentlyContinue

                $strPath.Split($Separator) | ForEach-Object {

                    $root = Get-Inventory -Name $_ -Location $root -Server $vc -ErrorAction SilentlyContinue

                    if ((Get-Inventory -Location $root -NoRecursion | Select-Object -ExpandProperty Name) -contains "vm") {

                        $root = Get-Inventory -Name "vm" -Location $root -Server $vc -NoRecursion

                    }

                }

                $root | Where-Object { $_ -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.FolderImpl] } | ForEach-Object {

                    Get-Folder -Name $_.Name -Location $root.Parent -NoRecursion -Server $vc

                }

            }

        }

    }

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

View solution in original post

Reply
0 Kudos
2 Replies
LucD
Leadership
Leadership
Jump to solution

I just added the Server parameter to the function.
See it that can solve your issue.

Now you can do

Get-FolderByPath -Path 'DC//Folder1' -Server 'vcsa.domain'

and also

Get-FolderByPath -Path 'DC/Homelab/Folder1' -Server $global:defaultVIServer

The updated function

function Get-FolderByPath {

<#

.SYNOPSIS Retrieve folders by giving a path

.DESCRIPTION The function will retrieve a folder by it's path.

   The path can contain any type of leave (folder or datacenter).

.NOTES

   Author: Luc Dekens

.PARAMETER

   Path The path to the folder. This is a required parameter.

.PARAMETER

   Separator The character that is used to separate the leaves in the path. The default is '/'

.EXAMPLE

   PS> Get-FolderByPath -Path "Folder1/Datacenter/Folder2"

.EXAMPLE

   PS> Get-FolderByPath -Path "Folder1>Folder2" -Separator '>'

#>

    param(

        [CmdletBinding()]

        [parameter(Mandatory = $true)]

        [System.String[]]${Path},

        [char]${Separator} = '/',

        [PSObject]$Server

    )

    process {

        if ($Server) {

            if ($Server -is [String]) {

                $vcs = $global:defaultVIServers | Where-Object { $_.Name -eq $Server }

            }

            else {

                $vcs = $Server

            }

        }

        else {

            if ((Get-PowerCLIConfiguration).DefaultVIServerMode -eq "Multiple") {

                $vcs = $global:defaultVIServers

            }

            else {

                $vcs = $global:defaultVIServers[0]

            }

        }

        foreach ($vc in $vcs) {

            $si = Get-View ServiceInstance -Server $vc

            $rootName = (Get-View -Id $si.Content.RootFolder -Property Name).Name

            foreach ($strPath in $Path) {

                $root = Get-Folder -Name $rootName -Server $vc -ErrorAction SilentlyContinue

                $strPath.Split($Separator) | ForEach-Object {

                    $root = Get-Inventory -Name $_ -Location $root -Server $vc -ErrorAction SilentlyContinue

                    if ((Get-Inventory -Location $root -NoRecursion | Select-Object -ExpandProperty Name) -contains "vm") {

                        $root = Get-Inventory -Name "vm" -Location $root -Server $vc -NoRecursion

                    }

                }

                $root | Where-Object { $_ -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.FolderImpl] } | ForEach-Object {

                    Get-Folder -Name $_.Name -Location $root.Parent -NoRecursion -Server $vc

                }

            }

        }

    }

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
JBartholomew
Enthusiast
Enthusiast
Jump to solution

Luc,

You never fail to amaze me. This is exactly what was required as I realized part of the flaw in my logic was that I was looking for the vCenter name as the root of the path, when it is actually the hidden "Datacenters" folder and so there isn't really a way to define which vcenter root it is just by path. This will work for my purposes as I will be able to inject the logic to determine from the VM Tags what vCenter should be used and use that for the $server variable.

Reply
0 Kudos