如何告诉 PowerShell 在开始下一个命令之前等待每个命令结束?
Posted
技术标签:
【中文标题】如何告诉 PowerShell 在开始下一个命令之前等待每个命令结束?【英文标题】:How to tell PowerShell to wait for each command to end before starting the next? 【发布时间】:2010-12-17 00:33:27 【问题描述】:我有一个 PowerShell 1.0 脚本来打开一堆应用程序。第一个是虚拟机,其他是开发应用程序。我希望虚拟机在其余应用程序打开之前完成启动。
在 bash 中我只能说 "cmd1 && cmd2"
这就是我所拥有的......
C:\Applications\VirtualBox\vboxmanage startvm superdooper
&"C:\Applications\NetBeans 6.5\bin\netbeans.exe"
【问题讨论】:
【参考方案1】:通常,对于内部命令,PowerShell 会在开始下一个命令之前等待。此规则的一个例外是基于外部 Windows 子系统的 EXE。第一个技巧是像这样流水线到Out-Null
:
Notepad.exe | Out-Null
PowerShell 将等到 Notepad.exe 进程退出后再继续。从阅读代码中可以看出这很漂亮,但有点微妙。您还可以将Start-Process
与-Wait
参数一起使用:
Start-Process <path to exe> -NoNewWindow -Wait
如果您使用的是 PowerShell 社区扩展版本,则为:
$proc = Start-Process <path to exe> -NoNewWindow -PassThru
$proc.WaitForExit()
PowerShell 2.0 中的另一个选项是使用background job:
$job = Start-Job invoke command here
Wait-Job $job
Receive-Job $job
【讨论】:
我的错。 Start-Process -Wait 效果很好,但现在我发现这不是我想要的......我实际上正在寻求等到 vm 完成启动。我想这将是艰难的。我想我必须为此找到一个新线程。谢谢,但是。 太棒了,| out-null
正是我所需要的。尝试使用Start-Job
,但因为我将函数的结果作为参数传递,它对我有点小气,所以我不能使用最后一个建议......
附带说明,如果您需要使用-ArgumentList
传递多个参数,请使用逗号分隔它们,例如-ArgumentList /D=test,/S
。
感谢您提供简单的“除了使用Start-Process -Wait
,通过管道输出可执行文件将使Powershell 等待。根据需要,我通常会通过管道发送到Out-Null
、Out-Default
、Out-String
或Out-String -Stream
。 Here 是一长串其他输出选项。
# Saving output as a string to a variable.
$output = ping.exe example.com | Out-String
# Filtering the output.
ping ***.com | where $_ -match '^reply'
# Using Start-Process affords the most control.
Start-Process -Wait SomeExecutable.com
我确实想念您引用的 CMD/Bash 样式运算符(&、&&、||)。它 看来我们必须是more verbose with Powershell。
【讨论】:
如果您需要解析输出,这是一个非常好的解决方案! 指出 Out-xxxx 重定向器列表很快让我明白为什么我应该使用 Out-Default 而不是 Out-Null,因为我需要保留控制台输出。 请注意,no 需要额外的工作来同步执行 console 应用程序 - 就像在任何 shell 中一样,这是默认行为。管道到Out-String
将输出更改为单行字符串,而PowerShell默认返回行数组。 Start-Process
应避免用于控制台应用程序(除非您真的想在 新窗口 中运行它们),因为您将无法捕获或重定向它们的输出。
其实,原生命令是同步运行(带输出)还是异步运行取决于可执行文件。例如,在不捕获输出的情况下,以下仅输出“bingo”。 & 'C:\Program Files\Mozilla Firefox\firefox.exe' -? ; '宾果游戏'【参考方案3】:
总是有 cmd。如果您在引用 start-process 的参数时遇到问题,可能会不那么烦人:
cmd /c start /wait notepad
或者
notepad | out-host
【讨论】:
【参考方案4】:更进一步,您甚至可以动态解析
例如
& "my.exe" | %
if ($_ -match 'OK')
Write-Host $_ -f Green
else if ($_ -match 'FAIL|ERROR')
Write-Host $_ -f Red
else
Write-Host $_
【讨论】:
【参考方案5】:有些程序不能很好地处理输出流,使用管道到Out-Null
可能不会阻塞它。
而Start-Process
需要-ArgumentList
开关来传递参数,不太方便。
还有另一种方法。
$exitCode = [Diagnostics.Process]::Start(<process>,<arguments>).WaitForExit(<timeout>)
【讨论】:
多个参数在该调用中如何工作?它们是如何划分的?如何处理各种嵌套字符串转义?太棒了! @AnneTheAgile doc 使用空格分隔参数,字符转义使用反斜杠 ty @ifree,我确实让 testcomplete 以这种方式运行!我在空格分隔的参数列表周围使用了单引号。[1];但是现在回显 $exitcode=false,这不是我从该过程中返回的代码? [1] $exitCode = [Diagnostics.Process]::Start("c:\Program Files (x86)\SmartBear\TestComplete 10\Bin\TestComplete.exe",'"c:\Users\ME\Documents\TestComplete 10 Projects\hig4TestProject1\hig4TestProject1.pjs" /run /project:myProj/test:"KeywordTests|zTdd1_Good" /exit').WaitForExit(60) Start-Process -Wait 在关闭应用程序后需要很长时间(如一分钟)才能返回脚本执行。这需要几秒钟。【参考方案6】:包含选项 -NoNewWindow
会给我一个错误:Start-Process : This command cannot be executed due to the error: Access is denied.
我可以让它工作的唯一方法是打电话:
Start-Process <path to exe> -Wait
【讨论】:
通常意味着它需要以管理员身份运行。管理员权限提升需要打开一个新窗口。无法将管理命令连接到非管理控制台。【参考方案7】:如果你使用Start-Process <path to exe> -NoNewWindow -Wait
您还可以使用-PassThru
选项来回显输出。
【讨论】:
请注意,-PassThru
不会回显 output(根据定义,非控制台应用程序不会产生控制台输出),它会输出一个 System.Diagnostics.Process
实例表示新启动的进程,因此您可以检查其属性并等待它稍后退出。【参考方案8】:
只需使用“等待过程”:
"notepad","calc","wmplayer" | ForEach-Object Start-Process $_ | Wait-Process ;dir
任务完成
【讨论】:
它不适用于 PowerShell 7.1.4(在 Windows 10 上)。以上是关于如何告诉 PowerShell 在开始下一个命令之前等待每个命令结束?的主要内容,如果未能解决你的问题,请参考以下文章
PowerShell管道和括号——PowerShell从零开始系列之六
PowerShell对象——PowerShell从零开始系列之五
PowerShell扩展——PowerShell从零开始系列之三