PowerShell 调用外部程序


这几天试着把之前写的 bat 脚本改写成 powershell ,遇到了一些坑,在这里列一下,希望能帮到后来的人。

首先,如果你不在乎外部程序的输入输出,只是需要调用它,那么直接用 Start-Process 就可以了,当然这种办法启动的程序也可以重定向输入输出,但是会比较麻烦。好处是 bat 里面拼接的字符串,把变量的 %…% 换成 $… 以后可以直接正常工作。

如果需要外部程序的输出又不想多写东西,也可以使用 调用操作符 & ,但是一定要注意,这个符号会“忠实”的执行你写的代码,具体表现就是,如果你像原先 bat 里面那样拼接一个超长的字符串,argv 里程序收到的只是一个超长的字符串而已,argc 是 1。而不是按空格分离(*实际规则复杂一些,处理带 ” 字符串)好的参数列表。

这个特性导致如果想要调用一个外部程序,实际要做的事会复杂一些,假如本来 .bat 里是这么写的

SET EXE=foo.exe
SET OPTIONS=%OPTIONS% -var1 value1
SET OPTIONS=%OPTIONS% -switch1
SET OPTIONS=%OPTIONS% -var2 value2
SET OPTIONS=%OPTIONS% %FILENAME%
%EXE% %OPTIONS%
::这个程序按照普通的逻辑改写以后
::& $EXE $OPTIONS
::外部程序收到的参数只有一个,就是 %OPTIONS%

改写成 .ps1 要这样写才会工作

$EXE="foo.exe"
$OPTIONS+=@("-var1") # $OPTIONS 需要为 [string[]] 类型,不然最后还是会拼接成一个字符串
$OPTIONS+=@("value1") # 键和值需要分开,不然就会被当作一个字符串整体传给外部程序
$OPTIONS+=@("-switch1")
$OPTIONS+=@("-var2")
$OPTIONS+=@("value2")
# ------- 这样
$OPTIONS+=@("$FILENAME")
& $EXE $OPTIONS
# ------- 或者这样
& $EXE $OPTIONS $FILENAME

到这里读者应该看明白为什么调外部程序变得很麻烦了,我的建议是,如果你传的参数项是固定的,可以考虑把调用的形式写成这样

$EXE="foo.exe"
& $EXE "-var1" $value1 "-var2" $value2 $FILENAME

其余情况,统统都拼接字符串以后用 Start-Process 吧

理论上来说 Invoke-Expression 可以像 bat 那样拼接字符串用,因为执行的时候空格会被作为参数的分隔,使参数的解释变正常了,只是官方不建议用这个

EchoArgs.exe

上边的结论都是我照着这个程序的输出得出的,在这里必须要感谢一下它的开发者们。

调用其他 ps 脚本

你可能打算用 hashtable 来传递参数,我得在这里提醒一下,至少在 powershell 5.1 (windows 自带的这个版本)里,如果被调用的脚本里有 switch 类型的参数,hashtable 的字符串是没法自动做隐式类型转换的,并不会有一个自动把空字符串转换成false的设定,你得想办法自己写一个,或者别用 hashtable 传参/别用 switch 类型声明参数


发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注