Powershell: Brackets Treated As Special Characters In Single Quotes

Created on 6 May 2019  路  5Comments  路  Source: PowerShell/PowerShell

Steps to reproduce

In File Explorer on an NTFS volume, create the file: [abc].txt

Following this run:

ls '[abc].txt'

Expected behavior

    Directory: C:\Users\Dave

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        2019-05-06 12:07 AM              0 [abc].txt

Actual behavior

No output displayed.

Environment data

Name                           Value
----                           -----
PSVersion                      6.2.0
PSEdition                      Core
GitCommitId                    6.2.0
OS                             Microsoft Windows 10.0.17763
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0鈥
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Additional Cases and Information

The file name can be displayed using tab completion, but the brackets are preceded by back ticks, which indicates that Windows can see the file and assumes that the brackets are special characters. When attempting to list the file using the ls command, the following error is generated:

ls : Cannot find path 'C:\Users\Dave\`[abc`].txt' because it does not exist.
At line:1 char:1
+ ls '.\`[abc`].txt'
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : ObjectNotFound: (C:\Users\Dave\`[abc`].txt:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

Other commands generate no output or errors as well.

Get-FileHash '[abc].txt'
# Generates no output

1 | Out-File '[abc].txt'
# Generates error stating that the wildcard path did not resolve to a file

According to Microsoft's "About Quoting Rules" page, "When you enclose a string in single-quotation marks (a single-quoted string), the string is passed to the command exactly as you type it. No substitution is performed".

Issue-Question Resolution-Fixed WG-Engine-Providers

Most helpful comment

Short:
https://github.com/PowerShell/PowerShell/pull/9257 resolves this issue.

Long:
Most cmdlets that accept a path treats the first string parameter as -Path, which can do wildcard/glob. The command

ls '[abc].txt'

is the same as

Get-ChildItem -Path '[abc].txt'

where [abc].txt will be considered as a wildcard pattern which matches either a.txt/b.txt/c.txt, so we have to:

  1. Escape the bracket, tell the cmdlet that we are not doing wildcard:
Get-ChildItem -Path '`[abc`].txt'
  1. Or, use -LiteralPath to indicate that the path is literal:
Get-ChildItem -LiteralPath '[abc].txt'

However, the first solution still does not work because the Get-ChildItem cmdlet is not handling the -Path argument correctly, when it contains escaped special character:

  • Get-ChildItem check if glob should be performed on -Path

    • if contains (non-escaped) wildcard character

    • resolves the path as pattern

    • else

    • resolves the path as literal (first solution falls in here)

Which means it will try to find a file literally named `[abc`].txt instead of [abc].txt

All 5 comments

/cc @kwkam @mklement0

Short:
https://github.com/PowerShell/PowerShell/pull/9257 resolves this issue.

Long:
Most cmdlets that accept a path treats the first string parameter as -Path, which can do wildcard/glob. The command

ls '[abc].txt'

is the same as

Get-ChildItem -Path '[abc].txt'

where [abc].txt will be considered as a wildcard pattern which matches either a.txt/b.txt/c.txt, so we have to:

  1. Escape the bracket, tell the cmdlet that we are not doing wildcard:
Get-ChildItem -Path '`[abc`].txt'
  1. Or, use -LiteralPath to indicate that the path is literal:
Get-ChildItem -LiteralPath '[abc].txt'

However, the first solution still does not work because the Get-ChildItem cmdlet is not handling the -Path argument correctly, when it contains escaped special character:

  • Get-ChildItem check if glob should be performed on -Path

    • if contains (non-escaped) wildcard character

    • resolves the path as pattern

    • else

    • resolves the path as literal (first solution falls in here)

Which means it will try to find a file literally named `[abc`].txt instead of [abc].txt

@kwkam Thanks for great comment! Should we add new test in #9257 related the issue?

And the related issues re file-creating cmdlets such as Out-File (and operator >) are #4726 and #9475. Related: #9225.

:tada:This issue was addressed in #9257, which has now been successfully released as v7.0.0-preview.2.:tada:

Handy links:

Was this page helpful?
0 / 5 - 0 ratings