Reputation: 191
I have a directory which contains a lot of folders. I want to list all folder (path) that go deeper than 2 levels. So in below case folder 1 & 2.
Directory/folder1
Directory/folder1/test1/test/testsub
Directory/folder1/test2
Directory/folder1/test3
Directory/folder2/blablabla/bla/1
Directory/folder3/test
Directory/folder4/test
Directory/folder5/test
I was trying the following:
$Depth = 3
$Path = "."
$Levels = "\*" * $Depth
$Folder = Get-Item $Path
$FolderFullName = $Folder.FullName
Resolve-Path $FolderFullName$Levels | Get-Item | ? {$_.PsIsContainer} | Write-Host
Upvotes: 5
Views: 16578
Reputation: 725
I have created a search from index of x to a certain index of a folder I am looking for which should allow you to search between 2 and beyond
$Folders = Get-ChildItem -Path C:\Folder1 -Recurse -Directory
If you know the name of a folder that you want to be the max index you can search for its index then you can search between x index and max index
if($folder.name -eq "Admin")
{
#Get the index of the known folder
$folderIndex = $folder.FullName.ToString().Split('\\').Count
}
Set the starting index in this example 2 you can add "-and $folder.FullName.ToString().Split('\').Count -lt $folderIndex" to get the folders between 2 and max index id
if($folder.FullName.ToString().Split('\\').Count -ge 2)
{
$folderIndex2 = $folder.FullName.ToString().Split('\\').Count
$folder.FullName + ' Index ID:' + $folderIndex2
}
The output would show up as PS C:\Users\Programmer> $folder.FullName + ' Index ID:' + $folderIndex2
C:\Folder1\Folder2\Folder3\Folder4 Index ID:5 The drive itself is counted as index 1
Hope this helps
Upvotes: 0
Reputation: 437111
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.
$Depth = 3
$Path = '.'
$Levels = '/*' * $Depth
Get-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.
$Depth = 3
$Path = '.'
$Levels = '/*' * $Depth
Get-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:
folder1
folder2
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/$_" }
.
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 only
Get-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 = '/*' * $Depth
Get-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 directories
Get-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 below
Get-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.
Upvotes: 7
Reputation: 100
Please try this
$Folders = Get-ChildItem 'C:\Program Files' -Directory -Recurse -Depth 1 |
Select-Object -ExpandProperty fullname |
Sort-Object
$Folders
Upvotes: -1