Recursive Directory Traversal to a Specific Depth in PowerShell
29 Apr 2020 · Comments: · Tags: PowerShellGet-ChildItemToDepth
The Get-ChildItemToDepth
function acts as a wrapper around Get-ChildItem
facilitating recursive
traversal of a path to a specific depth. Whilst what’s covered should be
provider
agnostic, I’ll be focusing specifically on file system directories.
Although the function serves a single purpose, behind the scenes the implementation differs depending on whether the PowerShell version is pre-5.0 or 5.x, read on for details.
PowerShell Prior to 5.0
Prior to PowerShell 5.0, Get-ChildItem
had no built-in method to limit
recursive traversal of a path to a specific depth. The Get-ChildItemToDepth
function achieves this through the use of a recursive function (a function that
calls itself). The recursion logic is a derivative work based on this code snippet
written by Chris Dent.
As at the time of writing this post (April 2020), all supported versions of Windows are capable of running PowerShell 5.x. Consequently I don’t tend to encounter anything older than PowerShell 4.0 (the stock version of PowerShell on Windows Server 2012 R2), so that’s all I’ve had the opportunity to test this function against. However, I see no reason for it not to work on even older versions of PowerShell.
PowerShell 5.x
In PowerShell 5.0, the Get-ChildItem
cmdlet gained a -Depth
parameter,
enabling a path to be recursively traversed to a specific depth. Unfortunately
in PowerShell 5.x the -Depth
parameter has a peculiar quirk that’s exhibited
when used against a legitimate path containing one or more wildcard characters.
It results in recursive traversal of the entire directory tree.
NB: This behaviour has since been rectified in PowerShell 6.0.
Problem
To illustrate the problem, I recursively traversed "C:\Program File?"
(the question mark is a wildcard denoting a single character) with no depth
limit (-Recurse
) and with a depth limit of two (-Depth 2
), using PowerShell
5.1 and 6.0.1 on the same machine. See how in PowerShell 5.1 count returns the
same value in both cases.
Workaround
To overcome this issue, Get-ChildItemToDepth
offloads responsibility for expanding a path containing wildcards from
Get-ChildItem
to Resolve-Path
and passes the result(s) to Get-ChildItem -LiteralPath <path> -Depth <n>
.
The -LiteralPath
parameter is used to avoid the expansion of literal wildcard
characters in file and directory names.
See example below, it recursively traverses "C:\Test\Sub*"
to a depth of two,
returning files with the extension XLSX
. I’ve deliberately included a
subdirectory with square brackets in the name (SubB[1]
) just to highlight why
Get-ChildItemToDepth
uses -LiteralPath
behind the scenes.
Comments