电源外壳管道操作员



我执行了以下三个powershell命令。前两个命令未返回任何结果,第三个命令返回结果。这三个命令之间的主要区别在于使用 wait 参数和括号。

PS C:\Users> Start-Process -FilePath 'msiexec' -ArgumentList '/I C:\Users\Downloads\Everything-1.4.1.1015.x64.msi -quiet' -PassThru |Foreach-Object -Process { $_.exitcode }

PS C:\Users> Start-Process -FilePath 'msiexec' -ArgumentList '/I C:\Users\Downloads\Everything-1.4.1.1015.x64.msi -quiet' -PassThru -wait |Foreach-Object -Process { $_.exitcode }

PS C:\Users> (启动进程 -文件路径 'msiexec' -argumentList '/I C:\Users\Downloads\Everything-1.4.1.1015.x64.msi -quiet' -passthru -wait) |Foreach-Object -Process { $_.exitcode }

1619

我测试了另外两个命令,它们之间的区别在于括号的使用。无论括号如何,这两个命令都返回结果。

PS C:\Users> Start-Process -FilePath 'msiexec' -ArgumentList '/I C:\Users\Downloads\Everything-1.4.1.1015.x64.msi -quiet' -PassThru |Foreach-Object -Process { $_.id }

22980

PS C:\Users> (启动进程 -文件路径 'msiexec' -argumentList '/I C:\Users\Downloads\Everything-1.4.1.1015.x64.msi -quiet' -passthru -wait) |Foreach-Object -Process { $_.id }

8064

感谢您对 -wait 参数的解释。我仍然对括号造成的差异感到困惑。希望得到更多回复。

这三个命令之间的主要区别在于使用-Wait参数和括号

在Mathias R. Jessen的有益评论的基础上:

主要需要使用Start-Process-Wait开关

  • 如果没有-WaitStart-Process异步运行。

  • 没有-PassThruStart-Process不会产生任何输出

虽然-PassThru使Start-Process输出一个表示新启动进程的System.Diagnostics.Process实例,但除非-Wait存在,否则该实例的.ExitCode属性还没有值,因为启动的进程通常尚未退出

此外,括号 ((...)) 也是必需的,因为Start-Process立即将代表新启动进程的System.Diagnostics.Process实例发送到管道(由ForEach-Object接收),然后等待进程退出。通过使用分组运算符(...),您可以强制等待Start-Process本身退出,此时Process' 实例.ExitCode属性可用,这要归功于-Wait

通常,将命令包装在(...)中会强制在结果通过管道传递之前预先收集其输出(包括等待它退出)(而不是默认的流式处理(逐个输出)行为,该行为发生在命令仍在运行时)。

因此,以下方法有效 - 但请参阅底部以获取更简单的替代方案

# Note: With (...), you could also pipe the output to ForEach-Object, as in
#       your question, but given that there's by definition only *one* 
#       output object, that is unnecessary.
(
Start-Process -PassThru -Wait -FilePath 'msiexec' -ArgumentList '/i C:UsersDownloadsEverything-1.4.1.1015.x64.msi -quiet' 
).ExitCode

从上面可以看出,使用两个单独的语句也可以工作(假设任何语句在执行下一个语句之前运行完成):

$process = Start-Process -PassThru -Wait -FilePath 'msiexec' -ArgumentList '/i C:UsersDownloadsEverything-1.4.1.1015.x64.msi -quiet' 
$process.ExitCode 

msiexec.exe不寻常之处在于:

  • 它是一个GUI(-subsystem) 可执行文件(与console(-subsystem) 可执行文件相反),因此 - 即使直接调用 - 也是异步运行的。

  • 但是,它报告调用方可能感兴趣的有意义的进程退出代码,要求调用方等待其退出(终止)以确定此退出代码

顺便说一句:对于调用控制台应用程序,Start-Process通常不是正确的工具,除非在异常情况下 - 请参阅此答案。


msiexecStart-Process -PassThru -Wait一起使用的更简单的替代方法是通过cmd /c使用直接调用,这确保了(a)同步调用和(b)PowerShell在其自动$LASTEXITCODE变量中反映msiexec的退出代码:

cmd /c 'msiexec /i C:UsersDownloadsEverything-1.4.1.1015.x64.msi -quiet'
$LASTEXITCODE  # output misexec's exit code

注意:如果msiexec命令行需要包含 PowerShell 变量值,请将可扩展(双引号)字符串 ("...") 传递给cmd /c,并且 - 与逐字(单引号)字符串 ('...') 字符串一样 - 根据需要在嵌入式参数周围使用嵌入的双引号。

最新更新