正如Ansgar的评论所示:在Windows上,
Start-Process
默认情况下异步地在一个新的控制台窗口中运行控制台程序。
如果该程序很快完成,您可能只会看到新的控制台窗口闪现一下,因为它很快就会打开和关闭,或者您可能完全错过闪烁 - 无论哪种方式,其输出都不会显示在调用者的控制台窗口中。
在
Start-Process
调用中添加
-Wait
将使调用同步进行,添加
-NoNewWindow
将使其在同一控制台中运行,但调用PowerShell会话将无法捕获或重定向调用的程序的输出 - 参见下文。
退一步:如果要以同步方式运行控制台程序,并将其标准流连接到PowerShell的流,请
不要使用Start-Process
,而是直接调用此类程序。
packages/mdoc/tools/mdoc.exe --version
如果外部程序的路径/名称必须被引用(因为其路径包含空格)和/或存储在变量中,只需使用
&
,即调用运算符来调用它:
& "packages/mdoc/tools/mdoc.exe" --version
$exePath = "packages/mdoc/tools/mdoc.exe"
& $exePath --version
使用直接调用方法可以带给你以下好处:
- 默认同步执行
- 能够捕获和/或重定向被调用程序的标准输出和标准错误流。
- 通过PowerShell的自动变量
$LASTEXITCODE
获得对程序进程退出代码的访问。
综合你后来的评论所说:
nuget install mdoc -OutputDirectory packages -ExcludeVersion
$exePath = "packages/mdoc/tools/mdoc.exe"
& $exePath --version
"done"
这将在打印done
之前(在撰写本文时)打印版本号 - mdoc 5.7.2
- 在Microsoft Windows 10 Pro上的Windows PowerShell v5.1.17134.48(64位;版本1709,OS Build: 16299.371)上进行验证。
可选阅读:从外部程序中“捕获”stdout / stderr输出:
要捕获 stdout 输出,只需将调用分配给变量即可:
$version = & $exePath --version # $version receives stdout output as an *array of lines*
$version
接收一个字符串标量(单个字符串),如果只有1行输出,或者是表示输出行的字符串数组。
要同时捕获stderr输出,请使用重定向2>&1
:
[string[]] $allOutput = & $exePath --version 2>&1
请注意将 [string[]]
转换,以确保 stderr 行也被捕获为字符串。
默认情况下,它们被捕获为 [System.Management.Automation.ErrorRecord]
实例,在 Windows PowerShell 中会有些混淆,因为它们会打印为 PowerShell 错误-此问题已在 PowerShell Core 中得到解决。
相反,如果您不转换返回的数组元素的类型为字符串,您可以使用 -is [System.Management.Automation.ErrorRecord]
检查每个元素,以确定它是来自 stdout 还是 stderr。
- 此答案 使用此方法在与
2>&1
合并后将 stdout 行与 stderr 行分开,以便它们可以保存到单独的文件中(在 Windows PowerShell 中,这需要显式地将 [System.Management.Automation.ErrorRecord]
实例字符串化)。
注意: 当 PowerShell 与外部程序通信时,会涉及字符编码问题: 有关详细信息,请参见 此答案。
[1] 或者基于 .NET 的 API System.Diagnostics.Process
。
关于何时适合使用 Start-Process
,请参见GitHub 文档问题 #6239
Start-Process -NoNewWindow
命令来启动程序,也可以直接运行程序,命令如下:& "packages/mdoc/tools/mdoc.exe" --version
。 - Ansgar WiechersStart-Process
才能让 PowerShell 运行可执行文件。这似乎是一个普遍的误解。 - Bill_Stewart&
符号来执行程序,并获得了相同的结果。 - Joel Martinez