如何告诉 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 感谢您提供简单的“ | Out-Null”解决方案! “Start-Process -NoNewWindow -Wait”方法的问题在于 PowerShell 会暂停,直到父进程产生的所有子进程都完成,即使父进程在它们之前终止。这导致了我们的安装程序问题。 这是我用来等待 VM 启动 Start-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VmName while((Get-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VmName -Status | ` select -ExpandProperty Statuses | ` ? $_.Code -match "PowerState" | ` select -ExpandProperty DisplayStatus) -ne "VM running") Start-Sleep -s 2 Start-Sleep -s 5 ##给VM是时候来了,这样它就可以接受远程请求了【参考方案2】:

除了使用Start-Process -Wait,通过管道输出可执行文件将使Powershell 等待。根据需要,我通常会通过管道发送到Out-NullOut-DefaultOut-StringOut-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 &lt;path to exe&gt; -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扩展——PowerShell从零开始系列之三

Windows Azure PowerShell之管理虚拟机

Powershell管理系列(三十)PowerShell操作之统计邮箱的用户信息