如何使用Invoke-WebRequest的-OutFile参数,在文件路径中转义方括号

8
当你在文件名中包含像[1]这样的东西,比如使用Invoke-WebRequest-OutFile参数时,你会得到一个错误:Cannot perform operation because the wildcard path File[1].txt did not resolve to a file. 这是由于这里文档所述的行为引起的。
对于其他的cmdlets,你可以使用-LiteralPath来强制采取字面路径,但在这种情况下这不是一个选项。
我已经尝试使用`或\转义[]字符,但仍然会出现相同的错误。
为了简化测试,您可以使用Out-FileTest-Path等来重现相同的问题。
#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"

我应该如何转义在 -Path-FilePath-OutFile 等参数中表示通配符的字符,以便它们像使用 -LiteralPath 参数一样正常运行,因为 -LiteralPathInvoke-WebRequest 中不可用?


1
使用单引号括起文件,并用反引号转义方括号:Test-Path -Path 'file\[1`].txt'` - Theo
1个回答

14

更新:

  • 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):


转义 [] 字符为 `[`],以便在使用 -Path (-FilePath) 和 -OutFile 作为 通配符表达式 解释时将它们视为字面量。不幸的是,这种方法目前只有一半起作用,因为底部部分讨论的一个错误

  • 执行转义确保目标参数接受路径(命令不再中断)...

  • ... 但是在文件创建时,错误地使用了转义表示法作为字面量文件名 - 请参见底部部分。

现在的解决方法:感谢hashbrown帮助简化。

  • 使 Invoke-RestMethod / Invoke-WebRequest 保存到临时文件中...
  • ... 然后将临时文件重命名(移动)为所需的输出文件路径。
# 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

在Windows PowerShell v4-中,使用[IO.Path]::GetTempfileName()代替New-TemporaryFile


将文字路径转义以用作通配符模式:

使用以下任何字符串文字表示之一,最终将得到具有直接内容file`[1`].txt的相同字符串,当被解释为通配符表达式时,它是文字字符串file[1].txt转义等效形式:

  • 'file`[1`].txt'
  • "file``[1``].txt"
  • file``[1``].txt

要通过编程方式创建此转义程序,请使用:

$literalName = 'file[1].txt'
$escapedName = [WildcardPattern]::Escape($literalName) # -> 'file`[1`].txt'

重要的是目标 cmdlet 在传递给它的 -Path (-FilePath) 参数中将 [] 视为 ` 转义,以便它们被视为原义。如果您使用 "..." 引用或未引用的参数(大多数情况下表现得像被包含在 "..." 中),则 PowerShell 的字符串解析会妨碍该过程:在可扩展字符串("...")内部也使用 ` 作为转义字符,因此为了通过 ` ,您必须对其进行转义,如 ``。否则,像 `[ 这样的内容在 "..." 内部变成了 [,因为从 "..." 的角度来看,`[ 是一个转义的 [,而转义不需要转义的字符会变成该字符;简而言之:像 "file`[1`].txt"file`[1`].txt 这样的内容都会变成普通的 file[1].txt,就好像您从未使用过 ` 一样。相比之下,在 '...' 引用的字符串内部,` 字符以原义使用,不需要转义。

许多 cmdlets 的有缺陷的文件创建行为,包括 -Path 参数:

如上所述的错误 - 在文件创建时误用了转义后的表示法作为文本文件名 - 影响了大部分 cmdlets,不幸的是:它们在创建文件时意外地保留了转义模式中的`字符,因此通过指定-Path 'file[1].txt',你最终会得到一个名为file`[1`].txt的文本文件。

幸运的是,大多数 cmdlets确实支持-LiteralPath,因此使用-LiteralPath file[1].txt是更好的选择,可以避免这个bug。

受影响的一些cmdlets:

  • Invoke-WebRequestInvoke-RestMethod

  • Out-File以及因此也包括重定向运算符>>>,它们在幕后有效地调用了Out-File

  • 请注意,Set-ContentAdd-Content没有展示这个问题。

  • 所有(?)的Export-* cmdlets。

  • 其他?

该漏洞已经在GitHub issue #9475中报告。


[1] 这实际上是一项破坏性的更改,但由于原始行为的反直觉特性而被认为是可以接受的。不幸的是,这种反直觉的行为在许多其他情况下仍然存在 - 包括仍然使用Out-File,除非明确使用-LiteralPath。有关摘要,请参见GitHub问题#17106


您对此问题的回答非常有帮助。不过,微软的文档中是否描述了PowerShell在字符串内如何解释方括号的默认行为呢?更有帮助的是提供包含文件名的字符串示例。 - Tony
很高兴听到这个消息,@Tony。问题归结为给定目标参数是否支持通配符表达式(其中 [ 是元字符)。在大多数 cmdlet 中,是 -Path 参数支持通配符,而 -LiteralPath 参数使用其参数“逐字”。不幸的是,并非所有 cmdlet 都遵守这种区别,有几种情况下文件路径会意外地被视为通配符 - 请参见 GitHub 问题 #17106 上的此评论 进行概述。 - mklement0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接