Bagaimana cara memberitahu PowerShell untuk menunggu setiap perintah berakhir sebelum memulai selanjutnya?


212

Saya memiliki skrip PowerShell 1.0 untuk hanya membuka banyak aplikasi. Yang pertama adalah mesin virtual dan yang lainnya adalah aplikasi pengembangan. Saya ingin mesin virtual menyelesaikan booting sebelum sisa aplikasi dibuka.

Dalam bash aku hanya bisa mengatakannya "cmd1 && cmd2"

Inilah yang saya punya ...

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

Jawaban:


367

Biasanya, untuk perintah internal, PowerShell menunggu sebelum memulai perintah berikutnya. Satu pengecualian untuk aturan ini adalah EXE berbasis subsistem Windows eksternal. Trik pertama adalah menyalurkan ke saluran Out-Nullseperti itu:

Notepad.exe | Out-Null

PowerShell akan menunggu sampai proses Notepad.exe telah keluar sebelum melanjutkan. Itu bagus tapi agak halus untuk mengambil dari membaca kode. Anda juga dapat menggunakan Mulai-Proses dengan parameter -Tunggu:

Start-Process <path to exe> -NoNewWindow -Wait

Jika Anda menggunakan versi PowerShell Community Extensions, itu adalah:

$proc = Start-Process <path to exe> -NoNewWindow -PassThru
$proc.WaitForExit()

Opsi lain di PowerShell 2.0 adalah menggunakan pekerjaan latar belakang:

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

2
Salahku. Mulai-Proses -Tunggu bekerja dengan baik, tapi sekarang saya melihatnya bukan yang saya cari ... Saya sebenarnya ingin menunggu sampai vm selesai booting. Saya membayangkan itu akan sulit. Saya kira saya harus menemukan utas baru untuk itu. Terimakasih tapi.
John Mee

7
Cemerlang, | out-nullmelakukan apa yang saya butuhkan. Start-JobSudah mencoba menggunakan tetapi karena saya melewati hasil fungsi sebagai parameter, itu membuat skitzoid kecil pada saya, jadi saya tidak bisa menggunakan saran terakhir ...
jcolebrand

6
Sebagai catatan tambahan, jika Anda harus memberikan beberapa argumen -ArgumentList, pisahkan dengan koma like -ArgumentList /D=test,/S.
sschuberth

1
Terima kasih atas solusi "<path to exe> | Out-Null" yang sederhana! Masalah dengan metode "Start-Process <path to exe> -NoNewWindow -Wait" adalah bahwa PowerShell berhenti sampai semua proses anak yang dihasilkan oleh induk selesai, bahkan jika induk berakhir sebelum mereka. Ini menyebabkan masalah program pengaturan kami.
zax

Ini yang saya gunakan untuk menunggu VM memulai Start-AzureRmVM -ResourceGroupName $ ResourceGroupName -Name $ VmName sementara ((Get-AzureRmVM -ResourceGroupName $ ResourceGroupName -Name $ VmName -Status | `select -ExpandProperty {|? _.Code -match "PowerState"} | `pilih -ExpandProperty DisplayStatus) -ne" VM running ") {Start-Sleep -s 2} Start-Sleep -s 5 ## Beri waktu VM untuk tampil sehingga dapat menerima permintaan jarak jauh
andrewmo

47

Selain menggunakan Start-Process -Wait, mem-piping output dari executable akan membuat Powershell menunggu. Tergantung pada kebutuhan, saya biasanya akan pipa untuk Out-Null, Out-Default, Out-Stringatau Out-String -Stream. Berikut adalah daftar panjang beberapa opsi keluaran lainnya.

# 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

Saya sangat merindukan operator gaya CMD / Bash yang Anda referensikan (&, &&, ||). Sepertinya kita harus lebih bertele-tele dengan Powershell .


Ini adalah solusi yang sangat bagus jika Anda perlu mengurai output!
Jan Rothkegel

Menunjukkan daftar redirectors xxxx dengan cepat membuat saya mengerti mengapa saya harus menggunakan Out-Default bukan Out-Null , karena saya perlu menjaga output konsol.
Julio Nobre

Perhatikan bahwa tidak ada pekerjaan tambahan yang diperlukan untuk menjalankan aplikasi konsol secara sinkron - seperti pada shell apa pun, itu adalah perilaku default. Perpipaan untuk Out-String mengubah output menjadi string multi-baris tunggal , sedangkan PowerShell secara default mengembalikan array baris . Start-Processharus dihindari untuk aplikasi konsol (kecuali jika Anda benar-benar ingin menjalankannya di jendela baru ) karena Anda tidak akan dapat menangkap atau mengarahkan outputnya.
mklement0

Sebenarnya, apakah perintah asli berjalan secara sinkron (dengan output) atau asinkron tergantung pada yang dapat dieksekusi. Sebagai contoh, tanpa menangkap output, berikut ini hanya menghasilkan "bingo". & 'C: \ Program Files \ Mozilla Firefox \ firefox.exe' -? ; 'bingo'
Nathan Hartley

12

Cukup gunakan "Tunggu-proses":

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

pekerjaan sudah selesai


8

Jika Anda menggunakan Start-Process <path to exe> -NoNewWindow -Wait

Anda juga dapat menggunakan -PassThruopsi untuk menggema output.


Perhatikan bahwa output-PassThru gema (aplikasi non-konsol dengan definisi tidak akan menghasilkan output konsol), itu output contoh yang mewakili proses yang baru diluncurkan, sehingga Anda dapat memeriksa propertinya dan menunggu untuk keluar nanti. System.Diagnostics.Process
mklement0

6

Beberapa program tidak dapat memproses aliran keluaran dengan sangat baik, menggunakan pipa untuk Out-Nullmungkin tidak memblokirnya.
Dan Start-Processperlu -ArgumentListberalih untuk menyampaikan argumen, tidak begitu nyaman.
Ada juga pendekatan lain.

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

1
bagaimana beberapa argumen berfungsi dalam panggilan itu? bagaimana mereka dibatasi? bagaimana seseorang menangani berbagai string bersarang yang keluar? ty!
AnneTheAgile

1
@AnneTheAgile doc menggunakan ruang untuk memisahkan argumen, untuk menghindari penggunaan backslash
ifree

ty @ifree, saya mendapatkan testcomplete untuk menjalankannya! Saya menggunakan tanda kutip tunggal di sekitar daftar argumen yang dibatasi ruang. [1]; tapi sekarang echo $ exitcode = false, yang bukan kode pengembalian saya dari proses? [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 '). TungguForExit (60)
AnneTheAgile

3

Termasuk opsi -NoNewWindowmemberi saya kesalahan:Start-Process : This command cannot be executed due to the error: Access is denied.

Satu-satunya cara saya dapat membuatnya bekerja adalah dengan menelepon:

Start-Process <path to exe> -Wait

0

Mengambil lebih jauh Anda bahkan bisa mengurai dengan cepat

misalnya

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

0

Selalu ada cmd. Mungkin kurang menjengkelkan jika Anda kesulitan mengutip argumen untuk memulai proses:

cmd /c start /wait notepad
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.