Description
Edited for the current status as of PowerShell Core 7.3.0-preview.4
Note:
-
Originally, this issue was also about the inability to execute files whose literal names happen to be syntactically invalid wildcard patterns.
-
This execution aspect was partially fixed in Make command searcher not use wildcard search for execution #9202 (but wasn't back-ported to the currently stable version, v6.2.3)
- Invocation by wildcard pattern still works as a fallback, but paths with
[
and]
that exist literally now take precedence. - Therefore, if no literal match is present, you may still end up invoking an unrelated file by accident, which is problematic (e.g., if
a.ps1
is present in the current dir. and.\[ab].ps1
is invoked, with no file literally named[ab].ps1
present,.\a.ps1
is executed instead.)
- Invocation by wildcard pattern still works as a fallback, but paths with
Seemingly, all external-executable invocation methods ( .
, &
, Start-Process
, powershell -File
) as well as redirections >
/ >>
mistakenly interpret script / file paths as wildcard patterns, and if a path that contains [
happens not contain a syntactically valid range expression, invocation and redirection break (in Windows PowerShell, no longer in PowerShell Core, except with Start-Process
) or can end up accidentally targeting an unrelated executable.
-
In other words: The problem sometimes occurs, unless each instance of
[
happens to be part of a valid range expression; e.g.,a[b]
(valid) vs.a[b
(invalid); curiously, however, the equally invalidb[b
does not. -
But even with a syntactically valid range expression - and some invalid ones - the behavior is unexpected:
'foo' > 'file[1].txt'
attempts wildcard matching and complains,Cannot perform operation because the wildcard path file[1].txt did not resolve to a file.
- Attempting escaping then inappropriately retains the escape characters - see Passing an escaped wildcard expression to -Path in file-creating cmdlets causes the escaped representation to be used as the literal filename #9475
-
Attempting to invoke (open) such a file fails quietly, even with escaping (run
New-Item file[1].txt
first):./file[1].txt
... quiet no-op./file`[1`].txt
... quiet no-op- If you created a
.ps1
file named, say,file[1].ps1
('"hi"' | Set-Content -LiteralPath file[1].ps1
):- Invocation with an explicit path unexpectedly only works if
.ps1
is also specified. - Invocation via $env:PATH doesn't work at all - neither with or without
.ps1
- Invocation with an explicit path unexpectedly only works if
Fundamentally, external-executable / redirection output paths should be treated as literals in these situations.
See this comment for a discussion and an overview of related issues.
Original tests below.
Steps to reproduce
Run the following Pester tests.
Describe "Redirection with and invocation of literal file paths that are invalid as wildcard patterns" {
BeforeAll {
Push-Location testdrive:\
$f1 = './t[1.ps1'
$f2 = './t[1.txt'
New-Item -Type File $f1 -Value "'hi'"
}
# Passes now, due to fix in #9202
It "Script file can be dot-sourced." {
. $f1 | Should -Be 'hi'
}
# Passes now, due to fix in #9202
It "Script file can be called." {
& $f1 | Should -Be 'hi'
}
# Passes now, due to fix in #9202
It "Script file can be called via CLI with -File" {
pwsh -noprofile -file $f1 | Should -Be 'hi'
}
It "Redirection works with new file (>)" {
& { 'hi' > $f2; Get-Content -LiteralPath $f2 } | Should -Be 'hi'
}
It "Redirection works with existing file (>)" {
New-Item -Force -Type File $f2
& { 'hi' > $f2; Get-Content -LiteralPath $f2 } | Should -Be 'hi'
}
It "File path is passed correctly to external programs" {
if ($IsWindows) {
cmd /c type ($f1 -replace '/', '\') | Should -Be "'hi'"
} else {
/bin/cat $f1 | Should -Be "'hi'"
}
}
AfterAll {
Pop-Location
}
}
Expected behavior
All tests should pass.
Actual behavior
The >
tests fail on all platforms.
In v6.2.3, the invocation tests fail too.
Environment data
PowerShell Core 7.0.0-preview.5
Originally reported for PowerShell Core v6.0.0-beta.7.