4

I want to list all files ending with some text in square brackets.

But neither Get-ChildItem *[* nor Get-ChildItem *`[* nor Get-ChildItem *``[* work.

How can I make this work without much ado (i.e. by creating variables, running additional commands through the pipe etc.)

AxD
  • 2,714
  • 3
  • 31
  • 53

2 Answers2

6

The following, which includes one of the things you tried, should work, but currently[1] doesn't work due to a bug:

# SHOULD work, but CURRENTLY BROKEN:
Get-ChildItem *``[*    # 1st ` is for string parsing, 2nd ` for wildcard escaping
Get-ChildItem "*``[*"  # ditto, with double quotes
Get-ChildItem '*`[*'   # single-quoted alternative, requires only 1 `

Note that the use of a (the first) positional argument implicitly binds to Get-ChildItem's -Path parameter.

The intent is for Get-ChildItem to see the following literal after argument parsing: *`[*, which correctly escapes [ with ` in order to treat it as a literal.

As an aside: unquoted *`[* is equivalent to double-quoted "*`[*", which results in literal *[*, because PowerShell's string parsing interprets the ` and effectively removes it.

Workarounds:

Instead of escaping the [ character, enclose it in [...], a character-set expression, which causes it to be matched literally:

Get-ChildItem *[[]*  # OK

Interestingly, performing the filtering via -Include does not exhibit the bug:

Get-ChildItem * -Include '*`[*'  # OK

Another option is to use -Filter instead of (implied) -Path, as demonstrated in Paxz's answer, but note that -Filter's wildcard language is not the same as PowerShell's (as supported by the -Path and -Include / -Exclude parameters); the -Filter argument is passed to the Windows API, whose wildcard language differs as follows:

  • It supports fewer constructs, notably no character sets or ranges ([...]).
  • It has legacy quirks - see this answer.
  • On the plus side, use of Filter, due to filtering at the source, performs better than letting PowerShell do the filtering via (implied) -Path or -Include.

Yet another option would be to add another layer of escaping, but that is ill-advised, because it will stop working once the bug is fixed:

# NOT RECOMMENDED: will stop working once the bug is fixed.
Get-ChildItem '*``[*' 

[1] As of Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.3

mklement0
  • 382,024
  • 64
  • 607
  • 775
3

You have to use the -Filter Parameter correct. When you don't specify the Parameter, like you did in your examples, it will assume you want to use the first Parameter (in this case -Path, Ref. Get-ChildItem Doc).

Try this instead:

Get-ChildItem -Filter "*`[*"

This found the file ad.a[s] for me.

You can also change the filter to this:

Get-ChildItem -Filter "*`[*`]"

to expand it for the closing bracket.

Paxz
  • 2,959
  • 1
  • 20
  • 34
  • 1
    This works when using a positional parameter: ``Get-ChildItem "*[`[]*"``. – Ansgar Wiechers Jan 08 '19 at 15:23
  • @AnsgarWiechers you are totally right! Sadly I can't figure out why this expression works. It would be great if you could explain how it works. (maybe in a seperate answer?) – Paxz Jan 08 '19 at 15:28
  • Unfortunately I can't explain it either. I would have expected ``"*`[*"`` to work with both the `-Path` and the `-Filter` parameter. – Ansgar Wiechers Jan 08 '19 at 15:48
  • 1
    Square brackets can be used as a wildcard character for Get-ChildItem and should be avoided in file and directory names whenever possible. They're supported in NTFS, but not by the .Net Framework, and consequently the support in Powershell is spotty. If you don't have control over the filenames, use the -LiteralPath parameter to retrieve them with Get-ChildItem. – Rich Moss Jan 08 '19 at 21:33
  • 1
    @AnsgarWiechers: Just `Get-ChildItem *[[]*` will do; `"*\`[*"` doesn't work with `-Path`, because the string parsing eats the backtick. `'*\`[*'` _should_ work, but doesn't due to a bug. – mklement0 Jan 09 '19 at 10:43
  • 1
    @Paxz: It's important to note that use of `-Filter` is a _workaround_ for a _bug_ in how `-Path` parses its arguments. Additionally, even though it works in this case, it's generally not a fully equivalent workaround, given that the `-Filter` wildcard language differs from PowerShell's wildcard language. – mklement0 Jan 09 '19 at 10:45
  • 1
    @Paxz: Additionally, note that `Get-ChildItem -Filter "*\`[*"` performs no escaping of the resulting wildcard argument at all (the backtick is removed during string expansion) and is the same as `Get-ChildItem -Filter *[*` - which is one indication that `-Filter` parses its argument differently. – mklement0 Jan 09 '19 at 10:54