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"
John Mee
sumber

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
Keith Hill
sumber
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 .

Nathan Hartley
sumber
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

Flaviofire
sumber
8

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

Anda juga dapat menggunakan -PassThruopsi untuk menggema output.

Sandy Chapman
sumber
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>)
saya bebas
sumber
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
twasbrillig
sumber
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 $_ }
}
Justin
sumber
0

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

cmd /c start /wait notepad
js2010
sumber