从 powershell.exe 将参数传递给脚本

Posted

技术标签:

【中文标题】从 powershell.exe 将参数传递给脚本【英文标题】:passing parameters to script from powershell.exe 【发布时间】:2016-05-04 11:06:28 【问题描述】:

我有一个这样的脚本:

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

【问题讨论】:

变量$root 持有整个应该只是持有"C:\Users\arun_jayapal\Documents\Visual Studio 2013\Projects\OutlookCompass\OutlookCompass\" 但那不是什么输出... 【参考方案1】:

您的问题是您正在从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 命令行选项传递,因此在这种情况下无需担心转义引号。

【讨论】:

我在 Visual Studio 中运行它...那么你建议我现在做什么? 您是从程序生成命令行吗?如果是这样,您也许可以使用 -EncodedCommand 命令行参数并传递您的参数字符串 base64 编码。 @mklement0,是的,我已经尝试改进我的答案的那一部分。 \" 的奇怪处理实际上来自 Microsoft 的 C 运行时库,因此它对大多数 .exe 程序很常见,但它是此类可执行文件的约定,而不是 cmd.exe 本身的一个方面。 很高兴知道在从 PowerShell 调用另一个 PowerShell 实例时隐式使用 -EncodedCommand - 方便的东西。关于谁来解释:我还建议修改*cmd* only regards the backslash as special - 再次是 PowerShell (可能通过 C 运行时库,如您所述)。在 Windows 上,命令行的解释完全取决于 调用的程序 - cmd.exe 确实 not 将命令行分解为参数(参数) Unix shell 可以。【参考方案2】:

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

您的选项是:

如 Duncan 建议的那样,在每个参数值的末尾使用 \\" 而不是 \"(例如,"c:\foo bar\\") 从路径中完全省略结尾的 \(例如,"c:\foo bar" 而不是 "c:\foo bar\") 如果您想避免修改参数值,请使用以下单引号解决方案(已在 v3 上验证)。

单引号解决方案:

这假定您从 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 的 &(调用)运算符来调用路径具有嵌入空格的脚本),命令行的其余部分可以用 PowerShell 样式引用- 引用的字符串不受解释(即使是 C 风格的参数解析,它也是 PowerShell 自己的启动命令行解析的基础,嵌入的 " 字符除外。 - 见下文)。

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

使用'' 在参数中嵌入文字'。 使用\" 在参数中嵌入文字"。 如果您需要转义% 字符。为了保护它们不被 cmd.exe 解释为环境变量引用的一部分(无论您使用单引号还是双引号字符串,您都必须这样做),请参阅我的 this answer。

请注意,要在当前目录中执行脚本,您必须像在 PowerShell 中那样为脚本文件名添加.\-前缀。

【讨论】:

以上是关于从 powershell.exe 将参数传递给脚本的主要内容,如果未能解决你的问题,请参考以下文章

将参数从批处理文件传递到 PowerShell 脚本

从 Web 应用程序将参数传递给 Python 脚本?

使用 argparser 将参数传递给入口点 python 脚本

从 subprocess.Popen 将参数传递给 argparse

无法将参数传递给配置单元脚本

将参数传递给输入文件的 shell 脚本