Як сказати PowerShell чекати, коли кожна команда закінчиться, перш ніж розпочати наступну?


212

У мене є сценарій PowerShell 1.0, щоб просто відкрити купу додатків. Перший - це віртуальна машина, а інші - програми для розвитку. Я хочу, щоб віртуальна машина закінчила завантаження до відкриття решти програм.

У баші я могла просто сказати "cmd1 && cmd2"

Це те, що я маю ...

C:\Applications\VirtualBox\vboxmanage startvm superdooper
    &"C:\Applications\NetBeans 6.5\bin\netbeans.exe"

Відповіді:


367

Зазвичай для внутрішніх команд PowerShell дійсно чекає перед запуском наступної команди. Винятком із цього правила є зовнішня підсистема Windows на базі EXE. Перший трюк - це зробити 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> -NoNewWindow -PassThru
$proc.WaitForExit()

Ще один варіант PowerShell 2.0 - використовувати фонове завдання:

$job = Start-Job { invoke command here }
Wait-Job $job
Receive-Job $job

2
Моє ліжко. Start-Process - Чекає чудово, але тепер я бачу, що це не те, що я шукав ... Я насправді прагну почекати, поки vm закінчить завантаження. Я думаю, що це буде важко. Я вважаю, що мені доведеться знайти нову нитку для цього. Дякую, але.
Джон Мей

7
Блискуче, | out-nullзробив саме те, що мені потрібно. Спробував за допомогою, Start-Jobале оскільки я передаю результати функцій як параметри, він отримав на мене трохи скитцоїд, тому я не міг використати останню пропозицію ...
jcolebrand

6
Як зауваження, якщо вам потрібно передати кілька аргументів -ArgumentList, відокремте їх комами -ArgumentList /D=test,/S.
sschuberth

1
Дякую за просте рішення "<шлях до exe> | Out-Null"! Проблема методу "Пуск-процес <шлях до exe> -NoNewWindow -Wait" полягає в тому, що PowerShell призупиняється, поки всі дочірні процеси, породжені батьком, не будуть завершені, навіть якщо батьківський шлях закінчується перед ними. Це спричинило проблеми з програмою налаштування.
zax

Це те, що я використовую, щоб зачекати, коли VM запустить Start-AzureRmVM -ResourceGroupName $ ResourceGroupName -Name $ VmName while ((Get-AzureRmVM -ResourceGroupName $ ResourceGroupName -Name $ VmName -Status | `select -Expandroperty _.Code -match "PowerState"} | `select -ExpandProperty DisplayStatus) -ne" VM running ") {Start-Sleep -s 2} Start-Sleep -s 5 ## Дайте час VM, щоб він міг прийняти віддалені запити
andrewmo

47

Крім використання 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 stackoverflow.com | where { $_ -match '^reply' }

# Using Start-Process affords the most control.
Start-Process -Wait SomeExecutable.com

Мені не вистачає операторів стилю CMD / Bash, на які ви посилалися (&, &&, ||). Здається, ми повинні бути більш багатослівними з Powershell .


Це неймовірно гарне рішення, якщо вам потрібно розібрати вихід!
Ян Роткегель

Вказавши список перенаправників Out-xxxx швидко дозволив мені зрозуміти, чому я повинен використовувати Out-Default замість Out-Null , оскільки мені потрібно було тримати вихід консолі.
Хуліо Нобре

Зверніть увагу , що немає додаткової роботи не потрібно виконувати консольні додатки синхронно - як і в будь-який оболонці, що це поведінка за умовчанням. Трубопровід Out-String змінює висновок на одну багаторядковий рядок, тоді як PowerShell за замовчуванням повертає масив рядків . Start-Processслід уникати консольних додатків (якщо ви справді не хочете запускати їх у новому вікні ), оскільки ви не зможете зафіксувати або перенаправити їх вихід.
mklement0

Насправді, чи працює нативна команда синхронно (з виходом) чи асинхронно, залежить від виконуваного файла. Як приклад, не фіксуючи вихід, наступні виводить лише "бінго". & 'C: \ Файли програм \ Mozilla Firefox \ firefox.exe' -? ; 'бінго'
Натан Хартлі

12

Просто використовуйте "Зачекайте-процес":

"notepad","calc","wmplayer" | ForEach-Object {Start-Process $_} | Wait-Process ;dir

робота виконана


8

Якщо ви використовуєте Start-Process <path to exe> -NoNewWindow -Wait

Ви також можете скористатися -PassThruопцією для отримання ехо-виводу.


Зауважте, що -PassThruне є ехо- виведенням (неконсольне додаток за визначенням не видасть консольний вихід), він виводить System.Diagnostics.Processекземпляр, який представляє нещодавно запущений процес, тож ви можете вивчити його властивості та чекати, поки він вийде пізніше.
mklement0

6

Деякі програми не можуть обробити вихідний потік дуже добре, використовуючи трубу, щоб Out-Nullне заблокувати його.
І Start-Processпотрібен -ArgumentListперемикач, щоб передавати аргументи, не так зручно.
Існує також інший підхід.

$exitCode = [Diagnostics.Process]::Start(<process>,<arguments>).WaitForExit(<timeout>)

1
як працюють кілька аргументів у цьому виклику? як вони розмежовані? як обробляти втечу різних вкладених рядків? ти!
AnneTheAgile

1
@AnneTheAgile doc використовує простір для розділення аргументів, а для втечі з
чару

ty @ifree, я отримав testcomplete для запуску таким чином! Я використав поодинокі лапки навколо списку аргументів, обмежених простором. [1]; але тепер echo $ exitcode = false, що це не мій зворотний код із процесу? [1] $ exitCode = [Діагностика.Процесс] :: Пуск ("c: \ програмні файли (x86) \ SmartBear \ TestComplete 10 \ Bin \ TestComplete.exe", "" c: \ Користувачі \ ME \ Документи \ TestComplete 10) Проекти \ hig4TestProject1 \ hig4TestProject1.pjs "/ run / project: myProj / test:" KeywordTests | zTdd1_Good "/ exit") .WaitForExit (60)
AnneTheAgile

3

Включаючи варіант -NoNewWindow дає мені помилку:Start-Process : This command cannot be executed due to the error: Access is denied.

Єдиний спосіб, як я міг змусити його працювати, - зателефонувати:

Start-Process <path to exe> -Wait

0

Взявши далі, ви навіть можете розібратися з льоту

напр

& "my.exe" | %{
    if ($_ -match 'OK')
    { Write-Host $_ -f Green }
    else if ($_ -match 'FAIL|ERROR')
    { Write-Host $_ -f Red }
    else 
    { Write-Host $_ }
}

0

Завжди є cmd. Це може бути менш прикро, якщо у вас виникнуть проблеми з цитуванням аргументів для запуску:

cmd /c start /wait notepad
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.