Як сказати 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.