Search code examples
powershellget-childitem

Is it possible to filter using Get-ChildItem -Name?


In one of the questions I answered recently I found interesting answer which shouldn't be working but still was. The question was about how to find specific folder recursively by its name and cd to it.

The answer proposed by A guest who's called Redd was:

Get-ChildItem -Path .\ -Name Folder -Recurse -Depth 10

As per the documentation of Get-ChildItem, -Name parameter is supposed to be SwitchParameter type and is responsible for returning only name (System.String), instead of System.Object.

How it's possible that the solution still works?


MCVE:

# cd C:\SO\56628221
mkdir test, test1, test2, test3
mkdir .\test2\folder
Get-ChildItem -Path .\ -Name Folder -Recurse -Depth 10

Current output:

test2\folder

Expected output:

Get-ChildItem : A positional parameter cannot be found that accepts argument 'Folder'.

What have I tried?

  1. First I checked that -Path is the only positional parameter. Apparently it is:

Get-ChildItem -Path documentation

All the other params have Position: Named.

  1. Then I tried to switch the arguments to something like this:
Get-ChildItem -Path .\ Folder -Name -Recurse -Depth 10

It was still working, so that was clear indication that what I'm passing to the cmdlet is not the value for -Name.

  1. Last thing I supposed was that I just send array of strings to -Path. I tried to do this explicitely:
[string[]]$a = '.\','Folder'
$a.GetType()
Get-ChildItem -Path $a -Name -Recurse -Depth 10

# Output:
PS C:\SO\56628221> $a.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String[]                                 System.Array


PS C:\SO\56628221> Get-ChildItem -Path $a -Name -Recurse -Depth 10
test
test1
test2
test3
test2\folder
Get-ChildItem : Cannot find path 'C:\SO\56628221\Folder' because it does not exist.
At line:1 char:1
+ Get-ChildItem -Path $a -Name -Recurse -Depth 10
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\SO\56628221\Folder:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

Solution

  • tl;dr:

    Apparently there's an incorrect information in current version of Get-ChildItem documentation, stating that -Filter is no longer positional.

    The above is no longer true, it's been fixed in this PR.


    Long answer:

    In fact, the value 'Folder' is being passed to -Filter parameter. Even though PowerShell 6 documentation says opposite, -Filter is a positional parameter. By mistake, that change was introduced in PowerShell v6+ while PowerShell 5.1 help article for Get-ChildItem is still correct.

    The cmdlet you run:

    Get-ChildItem -Path .\ -Name Folder -Recurse -Depth 10
    

    is effectively:

    Get-ChildItem -Path ".\" -Name -Filter "Folder" -Recurse -Depth 10
    

    Even though -Filter parameter in Get-ChildItem might be tricky in usage, in that case it works perfectly and the filter is applied to only show items named 'Folder'. As that invocation doesn't specify -File or -Directory, if you run:

    # Create new file named 'Folder'
    New-Item Folder
    

    and then run the cmdlet once again, it'd return both file and folder which was created:

    PS C:\SO\56628221> Get-ChildItem -Path .\ -Name Folder -Recurse -Depth 10
    Folder
    test2\folder
    

    The output is exactly the same if you explicitely use -Filter:

    PS C:\SO\56628221> Get-ChildItem -Path .\ -Name -Filter Folder -Recurse -Depth 10
    Folder
    test2\folder