Was investigating escaping a filename for PowerShell in https://github.com/PowerShell/PowerShellEditorServices/pull/765#discussion_r224297544.
I created a directory with the following files:
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 10/11/2018 10:57 AM 9 [script.ps1
-a---- 10/11/2018 10:57 AM 1 `[script.ps1
-a---- 10/11/2018 10:57 AM 1 ``[script.ps1
-a---- 10/11/2018 10:57 AM 1 ```[script.ps1
-a---- 10/11/2018 10:57 AM 1 ````[script.ps1
-a---- 10/11/2018 10:57 AM 8 script.ps1
(New-Item doesn't seem to have a LiteralPath parameter by the way)
I then run the following:
foreach ($i in 0..12) { $ticks = '`' * $i; Get-Item "./$ticks[script.ps1" }
The output of this in the given directory gives me:
Get-Item : Cannot retrieve the dynamic parameters for the cmdlet. The specified wildcard character pattern is not valid: [script.ps1
At line:1 char:44
+ ... h ($i in 0..12) { $ticks = '`' * $i; Get-Item "./$ticks[script.ps1" }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-Item], ParameterBindingException
+ FullyQualifiedErrorId : GetDynamicParametersException,Microsoft.PowerShell.Commands.GetItemCommand
Directory: C:\Users\roholt\Documents\Dev\sandbox\badnames
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 10/11/2018 10:57 AM 9 [script.ps1
-a---- 10/11/2018 10:57 AM 9 [script.ps1
-a---- 10/11/2018 10:57 AM 1 `[script.ps1
Get-Item : Cannot retrieve the dynamic parameters for the cmdlet. The specified wildcard character pattern is not valid: ``[script.ps1
At line:1 char:44
+ ... h ($i in 0..12) { $ticks = '`' * $i; Get-Item "./$ticks[script.ps1" }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-Item], ParameterBindingException
+ FullyQualifiedErrorId : GetDynamicParametersException,Microsoft.PowerShell.Commands.GetItemCommand
-a---- 10/11/2018 10:57 AM 1 ``[script.ps1
-a---- 10/11/2018 10:57 AM 1 `[script.ps1
-a---- 10/11/2018 10:57 AM 1 ```[script.ps1
Get-Item : Cannot retrieve the dynamic parameters for the cmdlet. The specified wildcard character pattern is not valid: ````[script.ps1
At line:1 char:44
+ ... h ($i in 0..12) { $ticks = '`' * $i; Get-Item "./$ticks[script.ps1" }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-Item], ParameterBindingException
+ FullyQualifiedErrorId : GetDynamicParametersException,Microsoft.PowerShell.Commands.GetItemCommand
-a---- 10/11/2018 10:57 AM 1 ````[script.ps1
-a---- 10/11/2018 10:57 AM 1 ``[script.ps1
Get-Item : Cannot find path 'C:\Users\roholt\Documents\Dev\sandbox\badnames\`````[script.ps1' because it does not exist.
At line:1 char:44
+ ... h ($i in 0..12) { $ticks = '`' * $i; Get-Item "./$ticks[script.ps1" }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\Users\roholt...````[script.ps1:String) [Get-Item], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand
Get-Item : Cannot retrieve the dynamic parameters for the cmdlet. The specified wildcard character pattern is not valid: ``````[script.ps1
At line:1 char:44
+ ... h ($i in 0..12) { $ticks = '`' * $i; Get-Item "./$ticks[script.ps1" }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-Item], ParameterBindingException
+ FullyQualifiedErrorId : GetDynamicParametersException,Microsoft.PowerShell.Commands.GetItemCommand
More concretely:
> Get-Item './[script.ps1' # 0
# Error (The specified wildcard character pattern is not valid: [script.ps1)
> Get-Item './`[script.ps1' # 1
# Finds '[script.ps1'
> Get-Item './``[script.ps1' # 2
# Finds '[script.ps1' <--- ???
> Get-Item './```[script.ps1' # 3
# Finds '`[script.ps1'
> Get-Item './````[script.ps1' # 4
# Error (The specified wildcard character pattern is not valid: ``[script.ps1)
> Get-Item './`````[script.ps1' # 5
# Finds '``[script.ps1'
> Get-Item './``````[script.ps1' # 6
# Finds '`[script.ps1' <--- ???
> Get-Item './```````[script.ps1' # 7
# Finds '```[script.ps1'
> Get-Item './````````[script.ps1' # 8
# Error (The specified wildcard character pattern is not valid: ````[script.ps1)
> Get-Item './`````````[script.ps1' # 9
# Finds '````[script.ps1'
> Get-Item './``````````[script.ps1' # 10
# Finds '``[script.ps1' <--- ???
> Get-Item './```````````[script.ps1' # 11
# Error (Cannot find path 'C:\Users\roholt\Documents\Dev\sandbox\badnames\`````[script.ps1' because it does not exist.)
> Get-Item './````````````[script.ps1' # 12
# Error (The specified wildcard character pattern is not valid: ``````[script.ps1)
Cases 0, 1, 3, 4, 5, 7, 8, 9, 11 and 12 make sense. Cases 2, 6 and 10 seem pretty strange to me.
Cases 2, 6 and 10 should report an invalid wildcard pattern, like cases 0, 4, 8 and 12.
Tagging @JamesWTruher because we discussed this offline earlier.
Trying to resolve the PSES issue linked above, I also tried the following:
[script.ps1, `[script.ps1, ``[script.ps1, etc.0, 1, 2, etc. respectively (so the content of the file represents the number of backticks in the name).Here are my results:
> ./[script.ps1 # 0
# Error (The specified wildcard character pattern is not valid)
> ./`[script.ps1 # 1
# Error (The specified wildcard character pattern is not valid)
> ./``[script.ps1 # 2
1
> ./```[script.ps1 # 3
1
> ./````[script.ps1 # 4
0
> ./`````[script.ps1 # 5
0
> ./``````[script.ps1 # 6
3
> ./```````[script.ps1 # 7
3
> ./````````[script.ps1 # 8
# Error (The specified wildcard character pattern is not valid)
> ./`````````[script.ps1 # 9
# Error (The specified wildcard character pattern is not valid)s
> ./``````````[script.ps1 # 10
# Error (The specified wildcard character pattern is not valid)
> ./```````````[script.ps1 # 11
# Error (The specified wildcard character pattern is not valid)
> ./````````````[script.ps1 # 12
1
> ./`````````````[script.ps1 # 13
1
> ./``````````````[script.ps1 # 14
# Error (The specified wildcard character pattern is not valid)
> ./```````````````[script.ps1 # 15
# Error (The specified wildcard character pattern is not valid)
> ./````````````````[script.ps1 # 16
# Error (The specified wildcard character pattern is not valid)
> ./`````````````````[script.ps1 # 17
# Error (The specified wildcard character pattern is not valid)
> ./``````````````````[script.ps1 # 18
# Error (The specified wildcard character pattern is not valid)
> ./```````````````````[script.ps1 # 19
# Error (The specified wildcard character pattern is not valid)
C:\Users\roholt\Documents\Dev\sandbox\badnames
> ./````````````````````[script.ps1 # 20
2
# I stopped at this point
I also tried invoking with a string literal:
> & '.\[script.ps1' # 0
# Error (The specified wildcard character pattern is not valid)
> & '.\`[script.ps1' # 1
1
> & '.\``[script.ps1' # 2
0
> & '.\```[script.ps1' # 3
3
> & '.\````[script.ps1' # 4
# Error (The specified wildcard character pattern is not valid)
> & '.\`````[script.ps1' # 5
# Error (The specified wildcard character pattern is not valid)
> & '.\``````[script.ps1' # 6
1
> & '.\```````[script.ps1' # 7
# Error (The specified wildcard character pattern is not valid)
> & '.\````````[script.ps1' # 8
# Error (The specified wildcard character pattern is not valid)
> & '.\`````````[script.ps1' # 9
# Error (The specified wildcard character pattern is not valid)
> & '.\``````````[script.ps1' # 10
2
> & '.\```````````[script.ps1' # 11
# Error (The specified wildcard character pattern is not valid)
> & '.\````````````[script.ps1' # 12
# Error (The specified wildcard character pattern is not valid)
> & '.\`````````````[script.ps1' # 13
# Error (The specified wildcard character pattern is not valid)
> & '.\``````````````[script.ps1' # 14
3
# I stopped at this point
After discussing this further with @JamesWTruher, we think one way to get around this is to use the fully provider-qualified name: Microsoft.PowerShell.Core\FileSystem::C:\path\to\`[script.ps1
@rjmholt Please look #7399 - perhaps it could resolve the issue (fix for ContainsValidWildcardPattern).
I believe this is more related to the WildcardPatten escape & unescape inconsistency mentioned in #7407
Re invocation with . / &: methinks the command-name argument should never be interpreted as a wildcard expression (though fixing that would technically be a breaking change) - see #4726
To add to the cases of unexpected behaviors with -Path: an argument that also contains _unescaped_ wildcard characters introduces the unexpected need for an additional layer of escaping:
$null = New-Item 'a['
Get-Item 'a`[' # OK - no unescaped metachar.
Get-Item '*`[' # BREAKS - unescaped metachar. *
Get-Item '*``[' # WORKS, but shouldn't be necessary
Also, interestingly, performing the filtering via -Include does _not_ exhibit the bug:
Get-ChildItem * -Include '*`[' # OK
Get-Item '*``[' # WORKS, but shouldn't be necessary
I think this is the most important problem here; the input is unescaped a varying (and hard-to-predict) number of times, which undermines the whole concept of escaping to my mind.
I think I found one more doubtful behavior. Please check if it's right
working directory:
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2019-06-14 鞓ろ泟 10:05 []
d----- 2019-06-14 鞓ろ泟 10:50 ``
Then run the following:
gi '``[``]'
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2019-06-14 鞓ろ泟 10:50 ``
'``[``]' should be interpreted as BACKTICK META-LBRACKET BACKTICK META-RBRACKET, then match ``
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2019-06-14 鞓ろ泟 10:05 []