Как заставить PowerShell ждать завершения каждой команды, прежде чем начинать следующую?
У меня есть сценарий PowerShell 1.0, чтобы просто открыть кучу приложений. Первая - это виртуальная машина, а остальные - приложения для разработки. Я хочу завершить загрузку виртуальной машины до того, как откроются остальные приложения.
В баш я могу просто сказать "cmd1 && cmd2"
Это то, что у меня есть...
C:\Applications\VirtualBox\vboxmanage startvm superdooper
&"C:\Applications\NetBeans 6.5\bin\netbeans.exe"
11 ответов
Обычно для внутренних команд PowerShell действительно ждет, прежде чем запустить следующую команду. Единственным исключением из этого правила является EXE-файл на основе внешней подсистемы Windows. Первый трюк заключается в том, чтобы Out-Null
вот так:
Notepad.exe | Out-Null
PowerShell будет ожидать завершения процесса Notepad.exe, прежде чем продолжить. Это изящно, но довольно тонко, чтобы разобраться с чтением кода. Вы также можете использовать Start-Process с параметром -Wait:
Start-Process <path to exe> -NoNewWindow -Wait
Если вы используете версию PowerShell Community Extensions, это:
$proc = Start-Process <path to exe> -NoWindow
$proc.WaitForExit()
Другой вариант в PowerShell 2.0 - использовать фоновое задание:
$job = Start-Job { invoke command here }
Wait-Job $job
Receive-Job $job
Помимо использования Start-Process -Wait
Передача выходных данных исполняемого файла заставит Powershell ждать. В зависимости от необходимости я, как правило, Out-Null
, Out-Default
, Out-String
или же Out-String -Stream
, Вот длинный список некоторых других вариантов вывода.
# Saving output as a string to a variable.
$output = ping.exe example.com | Out-String
# Filtering the output.
ping stackru.com | where { $_ -match '^reply' }
# Using Start-Process affords the most control.
Start-Process -Wait SomeExecutable.com
Я скучаю по операторам в стиле CMD/Bash, на которые вы ссылались (&, &&, ||). Кажется, мы должны быть более многословны с Powershell.
Просто используйте "Wait-process":
"notepad","calc","wmplayer" | ForEach-Object {Start-Process $_} | Wait-Process ;dir
работа сделана
Если вы используете Start-Process <path to exe> -NoNewWindow -Wait
Вы также можете использовать -PassThru
возможность вывода на экран.
Некоторые программы не могут обработать поток вывода очень хорошо, используя Out-Null
может не блокировать это.
А также Start-Process
нуждается в -ArgumentList
переключаться на передачу аргументов, не очень удобно.
Есть и другой подход.
$exitCode = [Diagnostics.Process]::Start(<process>,<arguments>).WaitForExit(<timeout>)
Включая опцию -NoNewWindow
дает мне ошибку: Start-Process : This command cannot be executed due to the error: Access is denied.
Единственный способ заставить его работать - позвонить:
Start-Process <path to exe> -Wait
Основываясь на ответах @Justin и @Nathan Hartley:
& "my.exe" | Out-Null #go nowhere
& "my.exe" | Out-Default # go to default destination (e.g. console)
& "my.exe" | Out-String # return a string
трубопровод вернет его в режиме реального времени
& "my.exe" | %{
if ($_ -match 'OK')
{ Write-Host $_ -f Green }
else if ($_ -match 'FAIL|ERROR')
{ Write-Host $_ -f Red }
else
{ Write-Host $_ }
}
Примечание. Если исполняемая программа возвращает что-либо, кроме кода выхода 0, конвейер не будет работать. Вы можете заставить его работать с операторами перенаправления, такими как
2>&1
& "my.exe" 2>&1 | Out-String
источники:
Вопрос был задан давно, но поскольку ответы здесь являются своего рода ссылками, я могу упомянуть об актуальном использовании. При текущей реализацииPowerShell
(его7.2 LTS
на момент написания) вы можете использовать&&
как вы бы сделали вBash
.
Условно выполните правый конвейер на основе успеха левого конвейера.
# If Get-Process successfully finds a process called notepad, # Stop-Process -Name notepad is called Get-Process notepad && Stop-Process -Name notepad
Дополнительная информация о документации
Принимая это дальше, вы можете даже разобрать на лету
например
& "my.exe" | %{
if ($_ -match 'OK')
{ Write-Host $_ -f Green }
else if ($_ -match 'FAIL|ERROR')
{ Write-Host $_ -f Red }
else
{ Write-Host $_ }
}
Всегда есть cmd. Это может быть менее неприятно, если у вас есть проблемы с цитированием аргументов для start-process:
cmd /c start /wait notepad
Я думаю, мы все не помним ;это самый простой способ заставить сценарий ждать предыдущей команды, старого DOS ';'. Я использую этот ALLOT для преобразования длинных сценариев для запуска в удаленном сеансе с помощью Enter-pssession, потому что Microsoft решила сделать удаленный сеанс PowerShell неудобным ограничением. Я написал множество сценариев для запуска в TaskMgr, и разработка этого может оказаться довольно трудоемким процессом, поэтому я использую -command «команда для запуска; затем еще одна; затем еще одна» и так далее.
Я помню удивительно полезную команду «Вызов» в сценариях пакетного файла DOS, и она выглядит как то, что делает «wait-process», но не совсем, поскольку она специально ожидает обозначенного процесса, а не строки выше, как это и было изначально заданный вопрос много лет назад (какая старая все еще открытая тема!).
Итак, напоминаем (обновление), что в новых версиях PowerShell (не PS 1, боже мой, не используйте ЭТО!) есть множество (новых) опций для остановки внутри консоли, а не выхода из нее, например, «выход». , как некоторые думали, исходный вопрос был (вы можете просто «сломаться», чтобы остановиться на этом этапе...
- Командлет Disable-PSBreakpoint Microsoft.PowerShell.U... Отключает точки останова в текущей консоли.
- Командлет Enable-PSBreakpoint Microsoft.PowerShell.U... Включает точки останова в текущей консоли.
- Командлет Get-PSBreakpoint Microsoft.PowerShell.U... Получает точки останова, установленные в текущем сеансе.
- Командлет Remove-PSBreakpoint Microsoft.PowerShell.U... Удаляет точки останова из текущей консоли.
- Командлет Set-PSBreakpoint Microsoft.PowerShell.U... Устанавливает точку останова на строке, команде или переменной.
Но Break - это не то, о чем спрашивали, правильные предыдущие ответы перед mselmany ( user15224124)?
Итак, ответ на вопрос How to to use a single script to run and then wait for the next command
заключается в использовании && или ;или |out-null или даже |$null
Примечание. Если вам когда-нибудь понадобится что-то найти, используйте команду get-help или find-command. Вот почему вам необходимо регулярно обновлять файлы справки — см. команду ниже.
#Update-Windows_Powerhell.ps1
$modules = $null
$modules = (Get-Module -ListAvailable).name
foreach ($module in $modules) {
Write-Output $module
Import-Module $module -NoClobber -Verbose -ErrorAction SilentlyContinue;
if((Get-Module -ListAvailable $module).Version -lt (Get-Module $module).Version){
Update-Help -Module $module -Confirm:$false
}
}
** вы можете изменить «listAvailable», чтобы найти конкретный модуль, например «-ListAvailable Graph . Более подробную информацию о регулярном обновлении теперь можно найти в моем техническом блоге: нажмите www.Burwell.tech!