如何解决使用 -File 选项调用 PowerShell 脚本的参数中的引号问题?

How to solve problem with quotes in arguments on calling a PowerShell script with -File option?

提问人:AlexK 提问时间:1/17/2023 最后编辑:AlexK 更新时间:1/18/2023 访问量:136

问:

我想从带有参数的 Windows 10 专业版命令行调用一个小型 PowerShell (v5.1) 脚本。

param($ReqURL, $JSONString) 
Write-Host $ReqURL # for debug 
Write-Host $JSONString # for debug 
Invoke-RestMethod  -Uri $ReqURL -Method Patch -ContentType "application/json" -Body $JSONString

在 PowerShell 控制台中调用脚本工作正常:

.\http-patch.ps1  -ReqURL myRESTApi -JSONString '{"lastname": "Bunny"}'

当我转义双引号时,从 Windows 命令提示符 () 调用脚本有效,如下所示:cmd.exe

PowerShell .\http-patch.ps1 -ReqURL myRESTApi  -JSONString '{\"lastname\": \"Bunny\"}'

但是当我使用该选项时,它失败了,因为脚本内部等于:-File$JSONString'{"lastname":

PowerShell -File "C:\work\LV Demo\http-patch.ps1" -ReqURL myRESTApi  -JSONString '{\"lastname\": \"Bunny\"}'

我认为这里有一些引号问题,但我找不到正确的方法。

PowerShell cmd 参数传递 号双引号

评论


答:

2赞 mklement0 1/17/2023 #1

使用 powershell.exe(Windows PowerShell CLI)的 -File 参数时,从外部 PowerShell 调用时只有引号 () 被识别为具有语法功能,例如:cmd.exe

因此,从 to 切换到(嵌入的字符需要以任何一种方式转义为 (sic):'""\"

:: From cmd.exe
PowerShell -File "C:\work\LV Demo\http-patch.ps1" -JSONString "{\"lastname\": \"Bunny\"}" -ReqURL myRESTApi

相比之下,当您使用 时,未转义的字符之后识别字符串。 - 在初始命令行解析期间唯一具有语法功能的标记已被剥离,因为生成的标记随后被解释为 PowerShell 代码-Command'...'"

有关何时使用与何时使用的指导。 以及结果解析的差异,请参阅此答案-Command-File


在 PowerShell 内部,很少需要调用另一个 PowerShell 实例,因为可以在进程内直接调用文件。.ps1

如果确实需要从 PowerShell 内部调用 CLI(例如,需要从 PowerShell 内部调用 CLI,即 PowerShell (Core) 的 pwsh.exe,反之亦然),最佳选择是使用脚本块{ ... })(仅在从 PowerShell 内部调用时有效),因为:powershell.exe

  • 允许你关注 PowerShell 自己的报价和转义要求。
  • 支持接收类型化输出(字符串以外的对象)、基于 XML 的后台序列化,尽管类型保真度有限 - 请参阅此答案
# From PowerShell
# Note how the " chars. now need NO escaping.
# (If you were to use a "..." string, you'd escape them as `" or "")
PowerShell { 
 & C:\work\LV Demo\http-patch.ps1" -JSONString '{"lastname": "Bunny"}' -ReqURL myRESTApi 
}

虽然可以通过单个参数进行调用,类似于必须从 PowerShell 外部调用的方式,但您不仅会失去类型化输出的好处,而且还会在 PowerShell 7.2.x 之前运行一个长期存在的 bug,该 bug 需要手动转义嵌入的 字符。 as \ 调用外部程序 - 请参阅此答案- 正如你自己的一次尝试所证明的那样(在这里,使用是完全可以的,因为 PowerShell 可以识别它):'...'

# !! Note the unexpected need to \-escape the embedded " chars.
PowerShell -File .\http-patch.ps1 -JSONString '{\"lastname\": \"Bunny\"}' -ReqURL myRESTApi  

# Variant with double quotes.
# !! Note the *double* escaping: first with ` - for the sake of PowerShell itself -
# !! then with \ due to the bug.
PowerShell -File .\http-patch.ps1 -JSONString "{\`"lastname\`": \`"Bunny\`"}" -ReqURL myRESTApi  

评论

0赞 AlexK 1/18/2023
非常感谢,它可以在 cmd 终端工作!只是为了我的 interesst:当我从 PowerShell 终端调用 PowerShell 时,为什么它会失败?我明白了JSONString = {\
1赞 AlexK 1/19/2023
我问题的背景是我开始直接从 PowerShell 终端测试 http-patch.ps1。很高兴它有效,我想在LabVIEW VI中调用脚本(LabVIEW没有原生HTTP补丁VI),这类似于从cmd.exe执行此操作。这出错了。于是我开始测试不同的组合,几乎发疯了,发现每个组合的行为都不同。脚本块解决方案对我来说看起来最优雅。