Как заставить 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

источники:

/questions/37775548/kak-zastavit-powershell-zhdat-zaversheniya-kazhdoj-komandyi-prezhde-chem-nachinat-sleduyuschuyu/37775590#37775590

https://social.technet.microsoft.com/forums/windowsserver/en-US/b6691fba-0e92-4e9d-aec2-47f3d5a17419/start-process-and-redirect-output-to-powershell-window

Вопрос был задан давно, но поскольку ответы здесь являются своего рода ссылками, я могу упомянуть об актуальном использовании. При текущей реализации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!

Другие вопросы по тегам