Folder by Path

There seem to be many vSphere environments where the same foldername is used multiple times. A blue folder with the name Servers is quite common for example.

If you need to retrieve such a folder with the Get-Folder cmdlet, you will have to walk the path to the folder leaf by leaf and use the Location parameter. It would be handier if you could just specify the path to the folder and retrieve the folder like that.

The following is a small function that will allow you to do just that.

Update August 6th 2020: The missing NoRecursion switch caused folders by the same name, further down in the hierarchy, to be returned as well.

Update July 5th 2019: The functions have been updated to support the situation where a user is connected to multiple vSphere Servers.

Update February 18th 2016: In some situations the function might return folders with the same name from different location. Fixed by adding NoRecursion on line 48

The Script

Annotations

Line 26-33: Handle multiple vSphere Server connections

Line 26: Takes care of Single or Multiple mode. In multiple mode, the function will look for the folder on each connected vSphere server. See Get-PowerCLIConfiguration.

Line 33: Loop over all the vSphere servers.

Line 34-35: Get the rootfolder (aka folder Datacenters) for a specific vSphere server connection

Line 36: The function can accept more than one path. This loops through all the provided paths.

Line 37: The function starts looking at the root folder. This is the hidden Datacenters folder.

Line 38: The provided path is split into separate leaves.

Line 39: The Path can have a datacenter as a leaf, hence the functions uses the Get-Inventory cmdlet to find the children.

Line 40-42: Skip the hidden “vm” folder

Line 44-46: When all the children are retrieved, the Where-clause will only pass the Folder objects back.

Line 45: Notice that we have to back one leaf, hence the $root.Parent on the Location parameter.

Sample Usage

I created the function to avoid this problem.

The function is quite simple to use.

This gives me exactly the folder I want.

Now it becomes easy to fetch for example all the VMs that are located in a specific folder.

Bonus: a New-VIProperty

Retrieving folders by path became easy, it would now be interesting to see what the path of a VM is. That’s where you can use the following New-VIProperty.

It creates a new property called BlueFolderPath and that property will show you the blue folder path where a VM is located.

51 Comments

    Daniel

    Replace Split() int line 39 with .Split($Separator, [StringSplitOptions]::RemoveEmptyEntries)

    Daniel

    It does return the correct folder, but only after throwing an error.

    Get-Inventory:
    Line |
    36 | $root = Get-Inventory -Name $_ -Location $root -N …
    | ~~
    | Cannot validate argument on parameter ‘Name’. The argument is null, empty, or an element of the argument collection contains a null value. Supply a collection that does not contain any null values and then try the command again.

      Daniel

      Uh, I noticed it throws the error when the Path starts with /

    Angelo

    hello,
    in this link:
    https://communities.vmware.com/thread/530723
    you said that:
    You will have to copy the code for my Get-FolderByPath function to your .ps1 file (at the top).Then you call the function later on in the .ps1 file.

    could you give me an example please ? how can i call function in the file?

      LucD

      Just copy the complete function to your .ps1 file.
      Then, in the same .ps1 file, you can call the function.

      function Get-FolderByPath{
      ...
      }

      Get-FolderByPath -Path "DC1/Blue1/Blue12/Blue121/Servers"

        Angelo

        i have an error message when i use this code:

        Import-Csv Folder.csv -UseCulture | %{

        $vm = Get-VM -Name $_.VmName

        $folder = Get-FolderByPath -Path $_.FolderName

        Move-VM -VM $vm -Destination $folder

        }

        ###############error####################”
        PS C:\Dell\Folder> .\folder.ps1
        AVERTISSEMENT : Specifying Folder in the Destination parameter is deprecated and the parameter will stop accepting Folder objects at a future release. Please use the InventoryLocation
        parameter instead.
        Move-VM : 21/10/2020 13:50:13 Move-VM The operation for the entity “XXXX” failed with the following message: “The request refers to an unexpected or unknown type.”
        Au caractère C:\Dell\Folder\folder.ps1:92 : 3
        + Move-VM -VM $vm -Destination $folder
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : NotSpecified: (:) [Move-VM], InvalidType
        + FullyQualifiedErrorId : Client20_TaskServiceImpl_CheckServerSideTaskUpdates_OperationFailed,VMware.VimAutomation.ViCore.Cmdlets.Commands.MoveVM

        AVERTISSEMENT : Specifying Folder in the Destination parameter is deprecated and the parameter will stop accepting Folder objects at a future release. Please use the InventoryLocation
        parameter instead.
        Move-VM : 21/10/2020 13:50:18 Move-VM The operation for the entity “XXXX” failed with the following message: “The request refers to an unexpected or unknown type.”
        Au caractère C:\Dell\Folder\folder.ps1:92 : 3
        + Move-VM -VM $vm -Destination $folder
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : NotSpecified: (:) [Move-VM], InvalidType
        + FullyQualifiedErrorId : Client20_TaskServiceImpl_CheckServerSideTaskUpdates_OperationFailed,VMware.VimAutomation.ViCore.Cmdlets.Commands.MoveVM

    Joe

    LucD,
    I am using your script which technically works great since it still creates the VMs in the proper folder, however when I run the script (powershell 5.0.10586.117 with powercli 6.5.1) I still receive errors in the window. I’ll receive the name error at the start and end of this command plus I’ll receive the folder errors for each folder level. Do you have any thoughts on what could be causing this?

    Command:
    Get-VM $VMName | ?{($_.ExtensionData.Config.Hardware.Device | ?{$_.GetType().Name -eq “VirtualMachineVideoCard”}).useAutoDetect -eq $false} | %{($_|Get-View).ReconfigVM((New-Object VMware.Vim.VirtualMachineConfigSpec -Property @{DeviceChange=(New-Object VMware.Vim.VirtualDeviceConfigSpec -Property @{Operation=”edit”;Device=(New-Object VMware.Vim.VirtualMachineVideoCard -Property @{UseAutoDetect=”$true”;Key=(($_.ExtensionData.Config.Hardware.Device | ?{$_.GetType().Name -eq “VirtualMachineVideoCard”}).key)})})}))}

    Errors:
    Get-Inventory : Cannot validate argument on parameter ‘Name’. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
    At line:26 char:39
    + $root = Get-Inventory -Name $_ -Location $root -Server $vc …
    + ~~
    + CategoryInfo : InvalidData: (:) [Get-Inventory], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetInventory

    Get-Inventory : Get-Inventory Inventory with name ‘Folder A’ was not found using the specified filter(s).
    At line:26 char:19
    + … $root = Get-Inventory -Name $_ -Location $root -Server $vc -NoRec …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (:) [Get-Inventory], VimException
    + FullyQualifiedErrorId : Core_OutputHelper_WriteNotFoundError,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetInventory

    Michael Vandijck

    How to find VM in nested folder structure? Duplicate VM names are present in different subfolders.

    I’m currently working on a script to manage VM’s using PowerCLI. I’ve found this function Get-FolderByPath which does his job correctly I suppose. It returns the folder correctly..

    However I still have troubles getting the machines from the correct folder. I have 2 folders in a nested tree as follows

    Datacenter\folderA\subfolderB
    Datacenter\folderA\Old_machines_subfolderB

    In both folders are a couple VM’s present. The machine names are the same, keeping th “Old machines” as a “backup” while creating the same VM’s with same naming in SubfolderB.

    The problem is that if I want to get the machines from SubfolderB (which are turned on) I’m getting random results which also includes machines from “Old machines” folder (which are turned off).

    Any idea how to fix this issue?
    Thanks in advance!

    Cheers!
    Michael

      LucD

      Hi Michael,
      Not sure how the code you are using looks like, but for me this seems to be working without an issue.
      Take this test folder structure
      Folders
      When I run the following code

      $folder1 = Get-FolderByPath -Path 'DC1/Folder2/Folder1/MyVM'
      $folder2 = Get-FolderByPath -Path 'DC1/Folder2/Folder3/MyVM'

      Write-Host "nFolder1n"
      Get-VM -Location $folder1 | select -ExpandProperty Name

      Write-Host "nFolder2n"
      Get-VM -Location $folder2 | select -ExpandProperty Name

      It returns the VMs in both folders correctly.
      VMs
      Perhaps you could share the code you are using?
      Luc

    Everton Poyato

    Luc,

    I have a vCenter ‘VC1’ with with two DataCenter: DC1 and DC2
    Both have a folder called ‘PDI’

    When I connect to this vCenter and use Get-FolderByPath it returns the way I want:

    $ DC = ‘DC1’
    $ Vmfolder = ‘PDI’

    $ Folder = $ DC + “>” + $ vmfolder
    $ Vmfolder = Get-FolderByPath -Path $ folder -Separator ‘>’

    But when I use the new-vm command it is not binding to the folder of that DataCenter that I have specified:

    New-VM -VMHost $ hostesx -Datastore $ datastoreLun -Location $ vmfolder -Name $ hostname -template $ template -OSCustomizationSpec $ hostname

    New-VM: 01/12/2016 12:25:54 New-VM The specified parameter ‘Location’ expects a single value, but its name criteria ‘PDI’
    Corresponds to multiple values.

    kevin

    I have a similar issue….I am moving resources from 1 vcenter to another. need to make sure the VMs and templates end up in the correct folder when completed. have duplicate folder names in the VM folder structure. move-inventory doesn’t support folderID as a vi-container, any ideas on how to accomplish this?

    Franics

    is there any script which can create folder from excel file?

      LucD

      Yes, you can use something like

      New-Item C:\MyFolder -Type Directory

      If you want to create a number of directories from a CSV file, you do something like this

      Import-Csv C:\MyFolders.csv -UseCulture | %{
      New-Item -Path $_.FolderName -ItemType Directory
      }

    Bala

    When I tried to retriev Subfolder Path details using the Get-FolderByPath Function its giving me error, Not sure why its giving below error:

    PowerCLI C:\Users\e3006122\Desktop> Get-FolderByPath -Path “cape/First”
    Get-Inventory : 15-12-2015 17:07:08 Get-Inventory Inventory with
    name ‘First’ was not found using the specified filter(s).
    At C:\Users\e3006122\Documents\Sabre Documents\PowerCLI
    SCripts\GetFolderbyPath.ps1:42 char:19
    + $root = Get-Inventory -Name $_ -Location $root -Server $vc
    -NoRecursio …
    +
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (:) [Get-Inventory], VimExceptio
    n
    + FullyQualifiedErrorId : Core_OutputHelper_WriteNotFoundError,VMware.VimA
    utomation.ViCore.Cmdlets.Commands.GetInventory

    If I try to retrieve the Foldername using Get-Inventory its working fine.

      Amine

      Same problem and until now i didn’t find solution of the famous “inventory with name “XXX” does not found

        LucD

        What is each qualifier in the Path you are using?
        Does it start with the Datacenter?

        A screenshot of the layout of the hierarchy would help me to analyse the issue further.

          Amine

          SO my tree is DatacenterName / Folder 1/Folder2 .

          I tried to execute
          -Get-FolderByPath -Path “DatacenterName/Folder 1/Folder2”
          Get-FolderByPath -Path “Folder 1/Folder2”
          and i get the same error inventory with name ‘Folder1’ was not found using the specified filter …
          I verified that i’m connected well to my vcenter
          commands like get-folder … works well.
          defaultviservers displays 2 results
          Get-iventory -location $root -server $vc works well

            LucD

            Are ‘Folder 1’ and ‘Folder2’ both of the type VM?
            What does it say in the Type column when you just do Get-Folder.

              Amine

              Yes, the Type of folder is VM

                LucD

                Looks like the Get-Inventory cmdlet might have an issue with the NoRecursion switch.
                Try changing line 26 to

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

                  Amine

                  It doesn’t solve my problem .
                  Always with the same error inventory with name “folder or datacentername” was not found using the specified filter.
                  When i execute get-inventory command . It displays result with 3 columns (Name, Type,ID).
                  My folders and my datacenter are displayed in the result

                    LucD

                    Sorry to hear that.
                    A screenshot of the tree structure of the VM folder could help me trying to analyse further.

    samir

    hi,

    I want to create new folders under folders

    like

    Clients
    -Client1
    -DC
    -Exchange
    -SQL
    -Client2
    -DC
    -Exchange
    -SQL
    -Client3
    -DC
    -Exchange
    -SQL
    -Client4
    -DC
    -Exchange
    -SQL

    is there anyway that we can do this using script?

    Thanks in advance!

      LucD

      Hi Samir,
      Yes, that can be done.
      In fact there are several options.

      Example 1

      $tgtFolders = 'Clients/Client1','Clients/Client2','Clients/Client3','Clients/Client4'
      $subfolders = 'DC','Exchange','SQL'

      foreach($fld in $tgtFolders){
      $fldObj = Get-FolderByPath -Path $fld
      foreach($newlfd in $subfolders){
      New-Folder -Location $fldObj -Name $newfld -Confirm:$false
      }
      }

      Example 2

      $baseFolder = 'Clients/Client'
      $numberOfClients = 4
      $subfolders = 'DC','Exchange','SQL'

      1..$numberOfClients | %{
      $fldObj = Get-FolderByPath -Path "$($baseFolder)$_"
      foreach($newlfd in $subfolders){
      New-Folder -Location $fldObj -Name $newfld -Confirm:$false
      }
      }

      I hope that helps,
      Luc

    Aaron

    Is there any way to do this with Datastore folders?

    Johan Donders

    Great .. it works … thx a lot.
    BTW, my root folder is called “centre de données”

    Ehren

    Hi,

    I think we have found an issue where this is not working and wondered if you had any input.

    If we have two folders named “SuperFolder” and run get-folderbypath and specify the path to one of them it returns them both such as below:

    Get-FolderByPath -Path “it services admin/it services” | Get-FolderPath

    Name Path
    —- —-
    SuperFolder Datacenter\Org SuperFolder Datacenter\Org\SelfManaged\IT Services

    Do you have any thoughts on why?

    Thanks a lot.

      Ehren

      The formatting went crazy and I mistyped something, for clarity:

      Get-FolderByPath -Path “Datacenter/Org” | Get-FolderPath

      Name :: Path
      SuperFolder :: Datacenter\Org
      SuperFolder :: Datacenter\SelfManaged\Org

      So it seems like the “selfmanaged” folder being in the ‘middle’ of the specified path (Datacenter and Org) seems to trip it up as the root and end are the same with other folders inbetween.

      Would appreciate your thoughts.

      Thanks

    Peter

    Hi,

    Looks like I may have found the issue regarding returning multiple folder objects within the same root folder.

    Scenario:
    Datacenter/Folder/Folder1
    Datacenter/Folder/Folder2/Folder1
    Issue:
    run get-folderbypath -path Datacenter/Folder/Folder1
    function returns BOTH ‘Folder1’ objects

    run get-folderbypath -path Datacenter/Folder/Folder2/Folder1
    function returns correct ‘Folder1’ object only

    FIX:
    Modify line 48 by adding ‘-NoRecursion’ to the end of the line
    Get-Folder -Name $_.Name -Location $root.Parent -Server $vc -NoRecursion

    run get-folderbypath -path Datacenter/Folder/Folder1
    function returns correct ‘Folder1’ object only

    Do you see any issues that modifying this line could cause?

      LucD

      Great find !
      No, I don’t see any obvious issues this might cause.

    Peter

    Hi Luc,

    I have the following scenario :
    Datacenter/folder/folder1
    Datacenter/folder/folder2/folder1

    when I use this function
    get-folderbypath -path Datacenter/folder/folder1
    it returns both ‘folder1’ folders

    Any ideas why it is picking up both?

      Matt

      To fix the “multiple child issue” I modified my loop from:
      foreach($strPath in $Path){
      $root = Get-Folder -Name $rootName -Server $vc -ErrorAction SilentlyContinue
      $strPath.Split($Separator) | %{
      $root = Get-Inventory -Name $_ -Location $root -Server $vc -ErrorAction SilentlyContinue
      if((Get-Inventory -Location $root -NoRecursion | Select -ExpandProperty Name) -contains “vm”){
      $root = Get-Inventory -Name “vm” -Location $root -Server $vc -NoRecursion
      }
      }

      to:
      for ($i = 0; $i -lt $strPath.Split($Separator).count; $i++) {
      $FOLDER = $strPath.Split($Separator)[$i]
      if ($i -eq 0 ) {
      # FIRST FOLDER
      $root = Get-Inventory -Name $FOLDER -Location $root -Server $vc -ErrorAction SilentlyContinue
      } else {
      # SUBSEQUENT FOLDERS
      $root = Get-Inventory -Name $FOLDER -Location $root -Server $vc -ErrorAction SilentlyContinue | ? {$_.Parent.Name -eq $root}
      }
      if((Get-Inventory -Location $root -NoRecursion | Select -ExpandProperty Name) -contains “vm”){
      $root = Get-Inventory -Name “vm” -Location $root -Server $vc -NoRecursion
      }
      }

        LucD

        Thanks for sharing that Matt.

    AndyP

    Hi LucD – is there a way to import a folder structure using the the path to import folders with the same name under different levels in the folder structure?
    eg import from a csv that contains name and path in seperate columns
    Name Path
    Prod folder_UniqueName1\ServiceLevel\Prod
    Prod folder_UniqueName1\ServiceLevel\Prod

    cleaning advice

    Hello! I know this is somewhat off topic but I was wondering if you knew where I could locate
    a ccaptcha plugin forr my comment form? I’m using the same blog platform as yours and I’m having difficulty finding one?
    Thanks a lot!

    Feel free to urf to myy site; cleaning advice

    Alberto

    Hey Luc thanks for all this..
    I was able to export the VMs and their folder structure with your Get-ParentName function but here is the problem I am having right now.
    I am migrating all those VMs to a new VC where the same folder structure exists but there are duplicated folder names of coarse.
    All my VMs by default will go into the Discovered Virtual Machine folder after the migration. Do you have any other function to import the CSV file I have and move the VMs in the Discovered VM folder to their individual folder using the full blue folder path this way I can avoid the duplicated names issue??

    Maybe I can use the Get-Folderbypath function.

    Thanks in advance,
    Alberto

      LucD

      Did you already check out Export/Import VM Folder Structure to new vCenter ?
      It discusses nearly the same thing you are trying to do.
      It contains several pointers to export and import scripts.
      Let me know if those help.

    David Roger

    Hi.
    I think you can replace “$root = Get-Folder -Name Datacenters -Server $vc” by “$root = Get-Folder -NoRecursion -Server $vc”.
    Name of root folder is not always “Datacenters”.
    Thanks for this article.

      LucD

      Thanks for the tip !
      Have you ever seen another name for the root folder ?
      I always saw “datacenters” in the environments where I tested.

    Mike

    @admin
    I am using vSphere Client Version 5.0.0 build 455964 and Power CLI version 5.0 build 435427. I would give you a copy of my output but unfortunately the server details are confidential. Thanks for your help.

    Mike

    @admin
    Thank you for that code. Unfortunately it still doesn’t seem to have returned any folder details for those VMs that are in vApp groups. They still just come through as blank. Thanks for the suggestion anyway, much appreciated.

      admin

      @Mike, strange, I get the path for VMs in a vApp.
      Which vSphere and PowerCLI versions are you using ?

    Mike

    Hi LucD,

    Thank you very much for this script, it is much appreciated. I have a problem with a couple of VMs that are in vApp groups and they are reporting as null for the BlueFolderPath. Is there a way around this?

    Many Thanks.

      admin

      @Mike, does this version produce the path you want to see ?

      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.vApp){
      $parentFolder = Get-VIObjectByVIView (Get-View $object.VApp.ExtensionData.ParentFolder)
      $blue = Get-ParentName $parentFolder
      $name = $parentFolder.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

    Grzegorz Kulikowski

    Hi Gregg, Luc, This is the first time i see this script from Luc as he mentioned about it on communities today/yesterday. Secondly, believe me that if somebody writes code about the same stuff it does not mean that he has even seen somebody else code before. It’s just how scripting/coding looks. You CAN have the same ideas and try to implement them in a similar way, i guess that’s nothing wrong with that. That said, this script is for completely different thing, i don’t even see how did you manage to tell that “i have copied his script” ?:) So next time you will accuse somebody of taking somebody else credits think twice as i do not feel “cool” about being accused of that. All my code on my site is written by me and if i want to mention about somebody approach i always put link,quotes etc… . That being said 😉 Cool script Luc, as always 😉

      LucD

      @Grzegorz, as I already commented, I don’t consider your function a copy. Your script is set up completely different.

      Let’s stop any further comments on this, both parties have had their say in this.

      Happy scripting Grzegorz 🙂

    Flux

    This script doesn’t seem to be working for me. I’ve tried using PowerCLI 5.1 Release 1 and PowerCLI 5.0.1 against vCenter Server 5.0U1 and I get the following:

    Get-Folder Folder with name ‘Datacenters’ was not found, using the specified filter(s).

    Any tips on where to look?

    Thanks,
    Flux.

      LucD

      @Flux, just to make sure, you are running this while connected to a vCenter ?

    Gregg

    Hi

    I think someone has replicated your work and claimed it’s theirs

    psvmware.wordpress.com/2012/09/14/get-vmfolderpath-to-check-in-which-vm-folder-our-vm-resides/

      LucD

      Hi Gregg, the function starts from the same idea, but it is written differently. So I don’t think it’s a replication of my script.
      Thanks for letting me know.

    Steven Garcia

    Very Cool. Thanks, LucD!

Leave a Reply

Your email address will not be published. Required fields are marked *

*
*

This site uses Akismet to reduce spam. Learn how your comment data is processed.