从 powershell.exe 向脚本传递参数

passing parameters to script from powershell.exe

我有这样的脚本:

param(
[string]$root,
[string]$bin,
[string]$out,
[string]$zdir
)


echo "args..."
echo "Root: $root", "zdir: $zdir", "out: $out", "bin: $bin"

我调用它如下:

powershell.exe -nologo -noprofile -file "C:\Users\arun_jayapal\Documents\Visual Studio 2013\Projects\OutlookCompass\OutlookCompass\zip.ps1" -root "C:\Users\arun_jayapal\Documents\Visual Studio 2013\Projects\OutlookCompass\OutlookCompass\" -zdir "Zip" -out "output.zip" -bin "C:\Users\arun_jayapal\Documents\Visual Studio 2013\Projects\OutlookCompass\OutlookCompass\bin\Debug\" 

但我的输出恰恰相反:

C:\code\misc>powershell.exe -nologo -noprofile -file "C:\Users\arun_jayapal\Docu
ments\Visual Studio 2013\Projects\OutlookCompass\OutlookCompass\zip.ps1" -root "
C:\Users\arun_jayapal\Documents\Visual Studio 2013\Projects\OutlookCompass\Outlo
okCompass\" -zdir "Zip" -out "output.zip" -bin "C:\Users\arun_jayapal\Documents\
Visual Studio 2013\Projects\OutlookCompass\OutlookCompass\bin\Debug\"
args...
Root: C:\Users\arun_jayapal\Documents\Visual Studio 2013\Projects\OutlookCompas
s\OutlookCompass" -zdir Zip -out output.zip -bin C:\Users\arun_jayapal\Document
s\Visual
zdir:
out: 2013\Projects\OutlookCompass\OutlookCompass\bin\Debug"
bin: Studio

您的问题是您从 cmd.exe 调用 powershell 脚本,对于许多遗留的 .exe 程序,序列 \" 用于将引号转义为参数。 Powershell 遵守此约定,因此当您调用 Powershell.exe 时,您必须遵循此转义约定。

所以:

-root "something\" -zdir "Zip" -out "output.zip" -bin "something\"

是包含两个双引号的单个参数,用 \" 转义到字符串中。 cmd 删除了其他双引号,因此 Zipoutput.zip 是引号外的字符串,但由于它们不包含任何空格,因此不会拆分参数。

这应该有效:

-root "something\" -zdir "Zip" -out "output.zip" -bin "something\"

双引号前的反斜杠意味着通过了一个反斜杠并且引号失去了它的特殊含义。不要将任何其他反斜杠加倍,因为 cmd 仅当一个或多个反斜杠序列在双引号之前时才将反斜杠视为特殊反斜杠。

或者省略尾部的反斜杠并将它们插入脚本中需要的位置。

或者只使用 powershell 本身作为你的主要命令提示符并完全放弃 cmd

顺便说一句,如果你从内部调用 powershell 的另一个副本,它会被识别为特殊的东西,并且参数以 base64 编码并使用 -EncodedCommand command-line 选项传递,所以在这种情况下无需担心转义引号。

Duncan's helpful answer 包含关键指针(以及有用的背景信息):参数值末尾的 \" 被解释为 转义 ",导致参数边界被误解.

您的选项是:

  • 在每个参数值的末尾使用 \" 而不是 \",正如 Duncan 所建议的(例如,"c:\foo bar\"
  • 从路径中完全省略尾随 \(例如,"c:\foo bar" 而不是 "c:\foo bar\"
  • 如果您想避免必须修改参数值,请使用以下single-quoted解决方案(已验证v3).

Single-quoted解法:

这假设您是从 cmd.exe 调用它,无论是从批处理文件还是在命令提示符下(在 PowerShell 中,您可以只使用 & <script> ...

  • 使用单引号而不是双引号
  • 使用 -Command 参数代替 -File
  • & 作为脚本路径的前缀(用 ^ 转义以使 cmd.exe 将其视为文字)
powershell.exe -noprofile -command ^& 'C:\Users\arun_jayapal\Documents\Visual Studio 2013\Projects\OutlookCompass\OutlookCompass\zip.ps1' -root 'C:\Users\arun_jayapal\Documents\Visual Studio 2013\Projects\OutlookCompass\OutlookCompass\' -zdir 'Zip' -out 'output.zip' -bin 'C:\Users\arun_jayapal\Documents\Visual Studio 2013\Projects\OutlookCompass\OutlookCompass\bin\Debug\'
  • 这是可行的,因为通过使用 -Command(和 PowerShell 的 &(调用)运算符来调用路径中嵌入空格的脚本),命令行的其余部分可以用不受解释的 single-quoted 字符串引用 PowerShell-style(甚至不通过作为 PowerShell 自身启动 command-line 解析基础的 C-style 参数解析,除了嵌入 " 个字符。- 见下文)。

  • 唯一需要用这种方法转义的字符是:

    • 使用 '' 在参数中嵌入文字 '
    • 使用 \" 在参数中嵌入文字 "
    • 如果您需要转义 % 个字符。为了保护它们不被 cmd.exe 解释为 environment-variable 引用的一部分(无论您使用单字符串还是 double-quoted 字符串,您都必须这样做),请参阅 this answer我的。
  • 请注意,为了在当前目录中执行脚本,您必须在脚本文件名前加上.\前缀,就像在 PowerShell 中一样。