我执行了以下三个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
开关:
-
如果没有
-Wait
,Start-Process
异步运行。 -
没有
-PassThru
,Start-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
通常不是正确的工具,除非在异常情况下 - 请参阅此答案。
将msiexec
与Start-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
,并且 - 与逐字(单引号)字符串 ('...'
) 字符串一样 - 根据需要在嵌入式参数周围使用嵌入的双引号。