为什么PowerShell无法识别引用的参数?

问题描述 投票:2回答:2

当您直接调用脚本(在PowerShell控制台或ISE中)或通过另一个PowerShell实例调用脚本时,为什么PowerShell会以不同方式处理引用的参数?

这是脚本(TestQuotes.ps1):

param
(
    [string]
    $Config = $null
)

"Config = $Config"

结果如下:

PS D:\Scripts> .\TestQuotes.ps1 -Config "A B C"
Config = A B C
PS D:\Scripts> PowerShell .\TestQuotes.ps1 -Config "A B C"
Config = A
PS D:\Scripts> .\TestQuotes.ps1 -Config 'A B C'
Config = A B C
PS D:\Scripts> PowerShell .\TestQuotes.ps1 -Config 'A B C'
Config = A

有任何想法吗?

windows powershell parameters quotes
2个回答
6
投票

根据PowerShell.exe Command-Line Helppowershell可执行文件的第一个参数是-Command

PowerShell[.exe]
       [-Command { - | <script-block> [-args <arg-array>]
                     | <string> [<CommandParameters>] } ]
       [-EncodedCommand <Base64EncodedCommand>]
       [-ExecutionPolicy <ExecutionPolicy>]
       [-File <FilePath> [<Args>]]
       [-InputFormat {Text | XML}]
       [-Mta]
       [-NoExit]
       [-NoLogo]
       [-NonInteractive]
       [-NoProfile]
       [-OutputFormat {Text | XML}]
       [-PSConsoleFile <FilePath> | -Version <PowerShell version>]
       [-Sta]
       [-WindowStyle <style>]

PowerShell[.exe] -Help | -? | /?

-Command之后的任何文本都作为单个命令行发送到PowerShell。

...

-Command的值是一个字符串时,Command必须是指定的最后一个参数,因为在命令之后键入的任何字符都被解释为命令参数。

使用echoargs可以轻松查看子PowerShell实例实际收到的内容:

PS > echoargs .\TestQuotes.ps1 -Config "A B C"
Arg 0 is <.\TestQuotes.ps1>
Arg 1 is <-Config>
Arg 2 is <A B C>

子实例进一步解析为:

'.\TestQuotes.ps1' '-Config' 'A' 'B' 'C'

这就是你得到“错误”结果的地方:Config = A

如果指定-File参数,您将获得所需的结果:

PS >  PowerShell -File .\TestQuotes.ps1 -Config 'A B C'
Config = A B C

PS >  PowerShell -Command .\TestQuotes.ps1 -Config 'A B C'
Config = A

4
投票

tl;博士

如果要从PowerShell调用另一个PowerShell实例,请使用脚本块({ ... })来获取可预测的行为:

Windows PowerShell:

powershell.exe { .\TestQuotes.ps1 -Config "A B C" }

PowerShell核心:

pwsh { .\TestQuotes.ps1 -Config "A B C" }

这将使参数的引用按预期工作 - 并且它甚至将从调用返回具有近似类型保真度的对象,因为使用类似于用于PowerShell远程处理的序列化。

但是,请注意,从PowerShell外部调用时,这不是一个选项,例如来自cmd.exebash

继续阅读,了解在没有脚本块的情况下所看到的行为。


PowerShell CLI(调用powershell.exe(Windows PowerShell)/ pwsh.exe(PowerShell Core)仅支持一个接受位置参数的参数(即,不带参数名称的值,如-Command)。

  • 在Windows PowerShell中,该(隐含)参数是-Command
  • 在PowerShell Core中,它是-File。 必须更改默认值以支持在Unix shebang lines中使用CLI。

第一个位置参数后的任何参数(如果有)都被认为是:

  • 在Windows PowerShell中:传递给(隐含的)PowerShell源代码片段的一部分 -Command参数。
  • 在PowerShell Core中:将各个参数作为文字传递给第一个位置参数(隐含的-File参数)中指定的脚本文件。

传递给-Command的参数 - 无论是隐式还是显式 - 都经过PowerShell的两轮解析,这可能很棘手:

  • 在第一轮中,包含单个参数的"..."(双引号)被剥离。 如果您从PowerShell调用,这甚至适用于最初'...'-enclosed(单引号)的参数,因为在后台,PowerShell重新引用这些参数以在调用外部程序时使用"..."(包括PowerShell CLI)本身)。
  • 在第二轮中,剥离的参数与空格连接以形成单个字符串,然后将其解释为PowerShell源代码。

适用于您的调用,这意味着PowerShell .\TestQuotes.ps1 -Config "A B C"PowerShell .\TestQuotes.ps1 -Config 'A B C'都会导致PowerShell最终解析并执行以下代码:

.\TestQuotes.ps1 -Config A B C

也就是说,由于2轮解析,原始引用丢失,导致三个不同的参数通过,这解释了您的症状。


如果必须在没有脚本块的情况下使命令工作,则有两种选择:

  • 使用-File,它只应用一轮解析: powershell.exe -File .\TestQuotes.ps1 -Config "A B C" 也就是说,除了剥离封闭的"..."之外,结果参数被视为文字 - 然而,这通常是你想要的。
  • 使用(隐含)-Command,应用额外的引用层: powershell.exe -Command .\TestQuotes.ps1 -Config '\"A B C\"'

请注意PowerShell如何需要"字符。要在传递给CLI的参数中作为\"进行转义,而在PowerShell中,必须使用`"(或"")。

© www.soinside.com 2019 - 2024. All rights reserved.