Is Get-ChildItem -Recurse broken when there are square brackets in the input path?

get-childitem, powershell

Solution

TL;DR: Use `-LiteralPath` for the folder when there might be unusual characters (inc. square brackets) in the names.

I wasn't able to reproduce this as per the OP in PowerShell v5.1.17134.590.

However, I was able to reproduce something similar, using the following command to attempt to list files in a folder I suspected was empty, in order to delete it. In actual fact, this folder had 12 `.mp3` files in it:

[PS]> gci '.\Music\Artist - Name\Album Name [Disc 1]\'

[PS]>

Adding the `-Recurse` switch caused the cmdlet to return an error rather than the (misleading) empty response shown above. I tested the same command with the `-Include *` option, and still there were no results, however this time there was no error when combined with the `-Recurse` switch.

-LiteralPath

The thing that worked best for me was to specify the path with the `-LiteralPath` parameter:

[PS]> gci -LiteralPath '.\Music\Artist - Name\Album Name [Disc 1]\'

Escaping

To cover some other possible cases, you might want to try to escape the square brackets. Using the suggestion from @PetSerAl in the comments on the OP you could try something like this:

[PS]> [System.Management.Automation.WildcardPattern]::Escape('.\Music\Artist - Name\Album Name [Disc 1]\')

.\Music\Artist - Name\Album Name `[Disc 1`]\

Sadly, this didn't work straight away. I found that I needed to escape twice, and then the following command gave the correct directory listing:

[PS]> gci '.\Music\Artist - Name\Album Name ``[Disc 1``]\'

See the following Q&A for more about square brackets & escaping:

- How do I use square brackets in a wildcard pattern in PowerShell Get-ChildItem?

Problem

OK, so I feel like this must be a bug in PowerShell, but I wanted to see if you guys think this sounds broken. It's quite an easy thing to reproduce, but I can see why it might not be a particularly common use case. The steps I've put below aren't actually what my script was doing, I was actually calculating sizes of subfolders - I've just condensed it down to the simplest possible scenario that shows my problem. I have only tried this on PowerShell 5.0.10240.16384, but might soon have the chance to test it on an earlier version [Edit: I have now tested this on PowerShell 2.0, and the bug does not appear in that version - it works as expected]. Just a quick note - I've used `gci` throughout as an abbreviation for Get-ChildItem. If you didn't already know, this works to actually type into PowerShell too. But the problem exists whatever alias you use. First, create a folder called `Test [123]` somewhere handy. In that folder, create a couple of files. Mine are caled `Test1.txt` and `Test2.txt`. They don't need to have anything in them. Next, open a PowerShell session and `Set-Location` to the parent folder of your new `Test [123]` folder. Now, run `gci -Filter Test*` and you should see something like: ``` Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 11/15/2015 3:22 PM Test [123] ``` All good, right? Next, try `gci -Filter Test* | gci`. This makes the output of the first gci the input for the next one, ie shows us the children of each item the first gci returns. This gives us the following: ``` Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 11/14/2015 10:21 PM 0 Test1.txt -a---- 11/15/2015 3:55 PM 0 Test2.txt ``` Again, all good - exactly as expected. This is all the files from our `Test [123]` folder. Now try this: `gci -Filter Test* | gci -Recurse`. All we've changed is that the second call to `gci` is now recursive, so it should show us all files including subfolders. We don't have any subfolders, so we're expecting the same results, right? Wrong. We don't get any output at all. Seems very odd that all we've done is added `-Recurse` and now we get different output. I think that adding `-Recurse` should never render less output, only ever more. Here's the next weird thing. Now try `gci -Filter Test* | gci -Recurse -Name`. This is the same as before except with the `-Name` parameter added. This is simply saying that we want the same output, except we only want the filenames and not the full information about each item. So we're probably expecting nothing back. But that's not what we get, we get this: ``` Test1.txt Test2.txt ``` This has got to be broken, right? Firstly `-Recurse` should never reduce the amount of output, and secondly asking for the output in a different format should not change the amount of output we get. This only happens when there are square brackets in the name of the folder. If you create another folder, just called `Test`, and run all the commands above again, you will always see the files from the `Test` folder. My research lead me to the `-LiteralPath` parameter; however, rephrasing the above command as `gci -Filter Test* | foreach { gci -Recurse -LiteralPath $_ }`, so as to use that parameter, still returns no output, and again, adding the `-Name` parameter starts the files being returned again. I've managed to do a workaround for this, using the `-Name` parameter and then combining it with the path of the folder I'm searching, then passing that into `Get-Item`, but that's made the code longer and uglier than it needs to be. So my question is, have I made a mistake or misunderstood something? Or is this a bug I should report?

Original source

Related problems