List folders at or below a given depth in Powershell List folders at or below a given depth in Powershell powershell powershell

List folders at or below a given depth in Powershell


The solution immediately below, which builds on your own, assumes that your intent is to find those child directories whose subtrees exceed a given depth.

If you instead want to find all directory paths that are at a given depth or deeper, see the bottom section.
Your approach cannot achieve that, because it finds directories at the given depth only, not also below.


Your own clever wildcard-based approach should work in principle, but:

  • (a) it can be greatly streamlined.

  • (b) additional work is needed to limit output to the distinct list of those child folders whose subtrees are too deep.

(a) Streamlining your approach:

$Depth = 3$Path = '.'$Levels = '/*' * $DepthGet-ChildItem -Directory $Path/$Levels
  • As in your own approach, '/*' * $Depth dynamically creates a multi-directory-level wildcard expression (e.g., /*/* for a $Depth of 2) that can be appended to the input $Path to match only paths at that level.

  • The -Directory switch (PSv3+) limits matching to directories only.

(b) Limiting output to the distinct set of top-level folder with too-deep subtrees:

$Depth = 3$Path = '.'$Levels = '/*' * $DepthGet-ChildItem -Directory $Path/$Levels |  ForEach-Object { ($_.FullName -split '[\\/]')[-$Depth] } |    Select-Object -Unique

Note: Splitting by [/\\] - that is, by either / or \ - makes the solution work on Unix-like platforms too (PowerShell Core); on Windows, -split '\\' (by an escaped \) is sufficient.

With your sample folder hierarchy, the above would yield:

folder1folder2
  • If you want the full paths instead, append
    | Convert-Path -LiteralPath { "$Path/$_" }.

  • If you want directory-info objects ([System.IO.DirectoryInfo]) instead, append
    | Get-Item -LiteralPath { "$Path/$_" }.


Optional reading: Getting folders up to, at, or beyond a certain depth:

Note:

  • Even though the solutions below target folders (directories), you can include files too by simply omitting -Directory, or target files only by replacing -Directory with -File.

  • For simplicity, the commands implicitly target the current directory.


At-a-given-depth-only logic:

This is the same logic employed in the solution above; the following code lists folders at depth 2 only, i.e. those at the grandchild level (child directories of child directories) - note that, unlike with Get-ChildItem -Depth, depth counting starts with 1, i.e. 1 refers to child directories:

$depth = 2 # grandchild directories onlyGet-ChildItem -Directory -Path ('*/' * $depth)
  • To output full paths, enclose the Get-ChildItem command in (...).FullName or pipe it to Select-Object -ExpandProperty FullName.

  • To output relative paths (e.g., folder1/test1/test/testsub), additional work is needed, because adding -Name will not work as expected in this case (it will output just the directory names):

$depth = 2 # grandchild directories# Calculate the length of the path prefix for determining relative paths.# (Using the current dir ($PWD) as the reference path here.)$PrefixLen = (Convert-Path -LiteralPath $PWD).Length + 1$Levels = '/*' * $DepthGet-ChildItem -Directory -Path ('*/' * $depth) |  ForEach-Object { $_.FullName.Substring($PrefixLen) }

Up-to-a-given-depth logic:

The PSv5+ -Depth parameter limits Get-ChildItem's recursion depth, i.e., it only finds items up to the specified depth, but note that it is depth 0, not 1 that represents the immediate children.
Note that use of -Depth implies -Recurse, though you may specify the latter as well.

For instance, to enumerate child folders and grandchild folders (2 levels) in the current directory, use:

$depth = 2 # child and grandchild directoriesGet-ChildItem -Directory -Depth ($depth - 1)
  • To output full paths, enclose the Get-ChildItem command in (...).FullName or pipe it to Select-Object -ExpandProperty FullName.

  • To output relative paths, simply add the -Name switch to the Get-ChildItem call.

At-a-given-depth-or-deeper logic:

Limiting results to items at levels greater than or equal to a given depth requires a custom solution:

$depth = 2 # grandchild directories and belowGet-ChildItem -Directory -Name -Recurse |  Where-Object { ($_ -split '[/\\]').Count -ge 2 } |    Get-Item -LiteralPath { "$PWD/$_" }

If your input path isn't the (implied) current dir., substitute that path for $PWD.

  • To output full paths, replace Get-Item with Convert-Path.

  • To output relative paths, simply omit the Get-Item call.


Please try this

$Folders = Get-ChildItem 'C:\Program Files' -Directory -Recurse -Depth 1 |      Select-Object -ExpandProperty fullname |      Sort-Object$Folders