考虑一下powershell命令:
cmd.exe "/c start notepad.exe"
使用powershell.exe(控制台)此命令在启动cmd / notepad进程后立即完成,并且不等待notepad / cmd退出。如果我希望它等待完成,我必须将输出传递给Out-Null。
使用powershell ISE,此命令会阻止执行,直到notepad / cmd关闭。
此外,如果我使用System.Diagnostics.Process在powershell.exe中运行的脚本中创建一个新进程(powershell.exe)并重定向标准输出,则脚本现在会阻止执行,直到关闭notepad / cmd。如果我不重定向输出,它不会阻止执行。
但是如果我使用c#创建一个具有相同设置/开始信息的新进程,并使用重定向输出运行相同的脚本,则不会阻止执行。
我在这里不知所措。显然它与执行和输出的设置有关,也许与“cmd.exe”有关。我希望有人能理解在这些情况下幕后发生的根本不同的事情。我知道ISE和cmd.exe不完全支持,但我不知道为什么其他3不一致。
为什么脚本不能以相同的行为运行(特别是powershell控制台)以及如何使用它们?
编辑:
经过一些故障排除后,我能够让所有的powershell.exe版本运行相同(ISE对我来说并不重要)。 cmd.exe "/c start notepad.exe"
阻止执行的奇数球是在powershell中创建新进程以使用System.Diagnostics.Process
运行powershell.exe时。如果输出被重定向(我首先使用System.Diagnostics.Process
的原因,Start-Process
不支持重定向除了文件),那么在进程对象上调用WaitForExit()
会导致阻塞发生。
简单地用WaitForExit()
替换Wait-Process
(和进程ID)会导致在新的powershell.exe中运行的powershell脚本按预期执行,并在运行命令后退出。希望这些信息与@ mklement0答案相结合对于其他有类似问题的人来说已经足够了。
答案 0 :(得分:1)
要在常规控制台和ISE中获得可预测的行为:
异步启动GUI应用程序 (立即返回提示/继续执行脚本):
notepad.exe
直接调用记事本使其以异步方式运行,因为它是一个GUI子系统应用程序。
如果您仍希望 跟踪该流程,稍后检查它是否仍在运行,以及终止时退出代码是,请使用{{1} },这使-PassThru
返回[System.Diagnostic.Process]
个实例:
Start-Process
$process = Start-Process -PassThru notepad.exe
稍后会告诉您该进程是否仍在运行。$process.HasExited
会告诉您退出代码(对于GUI应用程序,这可能不会告诉您太多)。要等待同步(在某些时候):
$process.ExitCode
等待(无限期)终止进程。Wait-Process $process.ID
值以限制等待时间;如果流程未在超时期限内终止,则会报告非终止错误,导致-Timeout
反映$?
。同步启动GUI应用程序 (阻止应用程序终止):
$False
Start-Process -Wait notepad.exe
告诉Start-Process
等待创建的进程终止;这相当于-Wait
。
请注意,对于 控制台 - 子系统应用程序(例如cmd /c 'start /wait notepad.exe'
), 同步执行是默认< /强>;只有GUI应用程序才需要findstr.exe
,包括显式创建新控制台窗口以运行命令。
要以异步方式运行控制台应用程序或shell命令 (无需打开新的控制台窗口),您有以下选择:
[首选] 使用Start-Job
启动命令,Receive-Job
稍后接收其输出/成功状态。
Start-Process
要同步等待此作业完成(并自动将其删除),请使用
$j = Start-Job { sleep 2; 'hi' }
在 PowerShell 核心 中,您可以使用更简单Receive-Job -Wait -AutoRemoveJob $j
语法(如
类似POSIX的Unix shell,例如... &
)代替bash
; e.g:
Start-Job
[不可取]您可以使用$j = & { sleep 2; 'hi!' } &
之类的内容,但这是不明智的:
Start-Process -NoNewWindow powershell -Args ...
将shell命令传递给powershell
,需要根据晦涩的规则进行错综复杂的引用 - 请参阅我的this answer了解背景信息。Start-Process
和RedirectStandardOutput
(并通过-RedirectStandardError
输入stdin)将这些流重定向到文件,然后您可以使用-RedirectStandardInput
要获取流程信息对象以确定流程的状态和退出代码,-PassThru
和Start-Job
是一种更简单,更方便的替代方案。 P.S。:我没有解释为什么Receive-Job
在ISE中阻塞但在常规控制台中没有阻止。然而,鉴于上述解决方案,可能不需要找到这种差异的底部。