When you include something like [1]
in a file name like File[1].txt
used with the Invoke-WebRequest
and the -OutFile
parameter you get an error Cannot perform operation because the wildcard path File[1].txt did not resolve to a file.
This is caused by the behavior documented here.
With other cmdlets you would use -LiteralPath
to force the path to be taken literally but in this case that is not an option.
I have tried escaping the [
and ]
characters with ` or \
but it still gives the same error.
To simplify testing you can reproduce the same issue with Out-File
, Test-Path
, etc.
#Fails
Out-File -FilePath "file[1].txt"
Out-File -FilePath "file`[1`].txt"
Out-File -FilePath "file\[1\].txt"
#Succeeds
Out-File -LiteralPath "file[1].txt"
#Fails
Test-Path -Path "file[1].txt"
#Succeeds
Test-Path -LiteralPath "file[1].txt"
How can I escape characters that would be used to express wildcards in -Path
, -FilePath
, -OutFile
, etc. so that they function like the string was specified with -LiteralPath
since -LiteralPath
isn't available with Invoke-WebRequest
?
Update:
In PowerShell (Core) 7.1+, file paths passed to the -OutFile
parameter of Invoke-WebRequest
and Invoke-RestMethod
are now interpreted literally:
That is, -OutFile
now acts like -LiteralPath
,[1] and there is no longer a need to escape [
and ]
characters, so that the following example command works as-is:
# PowerShell 7.1+ only.
Invoke-WebRequest http://example.org -OutFile File[1].txt
Therefore, the following applies only to Windows PowerShell (and to now-obsolete PowerShell (Core) versions v7.0 and below):
Unfortunately, escaping the [
and ]
characters as `[
and `]
so that they are treated literally when interpreted as a wildcard expression with -Path
(or -FilePath
) and -OutFile
only half works at the moment, due to a bug discussed in the bottom section:
Performing the escaping ensures that the target parameter accepts the path (the command doesn't break anymore) ...
... but on creation of the file it is mistakenly the escaped representation that is used as the literal filename - see bottom section.
Workaround for now:Tip of the hat to hashbrown for helping to simplify it.
Invoke-RestMethod
/ Invoke-WebRequest
save to a temporary file...# Literal output file path.
$outFile = '.\file[1].txt'
# Simulate a call to Invoke-RestMethod / Invoke-WebRequest -OutFile.
# Save to a *temporary file*, created on demand - such
# a temporary file path can be assumed to never contain '[' or ']'
'hi' | Out-File -FilePath ($tempFile = New-TemporaryFile)
# Rename (move) the temporary file to the desired target path.
Move-Item -Force -LiteralPath $tempFile -Destination $outFile
In Windows PowerShell v4-, use [IO.Path]::GetTempfileName()
in lieu of New-TemporaryFile
.
Use any of the following string-literal representations, which ultimately result in the same string with verbatim content file`[1`].txt
, which, when interpreted as a wildcard expression, is the escaped equivalent of literal string file[1].txt
:
'file`[1`].txt'
"file``[1``].txt"
file``[1``].txt
To create this escaping programmatically, use:
$literalName = 'file[1].txt'
$escapedName = [WildcardPattern]::Escape($literalName) # -> 'file`[1`].txt'
What matters is that the target cmdlet sees the [
and ]
as `
-escaped in the -Path
(-FilePath
) argument it is passed for them to be treated verbatim.
If you use "..."
quoting or an unquoted argument (which mostly behaves as if it were enclosed in "..."
), PowerShell's string parsing gets in the way: `
is also used as the escape character inside expandable strings ("..."
), so in order to pass `
through, you must escape it itself, as ``
.
`[
inside "..."
turns into just [
- the `
is "eaten" - because `[
is an escaped [
from "..."
's perspective, and escaping a character that doesn't need escaping turns into just that character; in short: both "file`[1`].txt"
and file`[1`].txt
turn into plain file[1].txt
, as if you had never used `
.By contrast, `
characters are used verbatim inside '...'
-quoted strings and need no escaping.
-Path
:The bug mentioned above - that on file creation the escaped representation is mistakenly used as the literal filename - affects most cmdlets, unfortunately: That is, they unexpectedly retain the `
characters in the escaped pattern on creating a file, so that by specifying -Path 'file`[1`].txt'
you'll end up with a file literally named file`[1`].txt
.
Fortunately, most cmdlets do support -LiteralPath
, so use of -LiteralPath file[1].txt
is the better choice anyway and avoids this bug.
Some of the affected cmdlets:
Invoke-WebRequest
and Invoke-RestMethod
Out-File
and therefore also redirection operators >
and >>
, which effectively call Out-File
behind the scenes.
Note that Set-Content
and Add-Content
do not exhibit this problem.
All(?) Export-*
cmdlets.
Others?
The bug has been reported in GitHub issue #9475.
[1] This was technically a breaking change, but it was considered acceptable, due to the counterintuitive nature of the original behavior. Unfortunately, the counterintuitive behavior still surfaces in many other contexts - including still with Out-File
unless -LiteralPath
is explicitly used. See GitHub issue #17106 for a summary.