จะบอก PowerShell ให้รอให้แต่ละคำสั่งสิ้นสุดก่อนที่จะเริ่มถัดไปได้อย่างไร


212

ฉันมีสคริปต์ PowerShell 1.0 เพื่อเปิดแอปพลิเคชันจำนวนมาก ที่แรกก็คือเครื่องเสมือนและอื่น ๆ ที่มีการพัฒนาโปรแกรม ฉันต้องการให้เครื่องเสมือนบูตเสร็จก่อนที่จะเปิดแอปพลิเคชั่นที่เหลือ

ในทุบตีฉันสามารถพูดได้ "cmd1 && cmd2"

นี่คือสิ่งที่ฉันมี ...

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

คำตอบ:


367

โดยปกติสำหรับคำสั่งภายใน 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> -NoNewWindow -PassThru
$proc.WaitForExit()

ตัวเลือกอื่นใน PowerShell 2.0 คือการใช้งานพื้นหลัง:

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

2
ความผิดฉันเอง. Start-Process - รอได้ผลดี แต่ตอนนี้ฉันเห็นแล้วนี่ไม่ใช่สิ่งที่ฉันกำลังมองหา ... ฉันกำลังรอจนกว่า vm จะบูตเสร็จสิ้น ฉันคิดว่ามันจะยาก ฉันคิดว่าฉันจะต้องค้นหาหัวข้อใหม่สำหรับที่ ขอบคุณ แต่
John Mee

7
ยอดเยี่ยม| out-nullทำในสิ่งที่ฉันต้องการ พยายามใช้Start-Jobแต่เนื่องจากฉันผ่านผลลัพธ์ของฟังก์ชั่นเป็นพารามิเตอร์จึงมี skitzoid เล็กน้อยกับฉันดังนั้นฉันจึงไม่สามารถใช้คำแนะนำสุดท้าย ...
jcolebrand

6
ขณะที่ทราบด้านถ้าคุณต้องการที่จะผ่านการขัดแย้งหลายที่มีให้คั่นด้วยเครื่องหมายจุลภาคเช่น-ArgumentList -ArgumentList /D=test,/S
sschuberth

1
ขอบคุณสำหรับวิธีง่ายๆ "<path to exe> | Out-Null"! ปัญหาเกี่ยวกับ "กระบวนการเริ่มต้น <เส้นทางสู่ exe> -NoNewWindow -Wait" วิธีการคือ PowerShell หยุดชั่วคราวจนกว่ากระบวนการลูกทั้งหมดจะเกิดโดยผู้ปกครองจะเสร็จสมบูรณ์แม้ว่าผู้ปกครองจะยุติก่อน สิ่งนี้ทำให้เกิดปัญหาในโปรแกรมการตั้งค่าของเรา
zax

นี่คือสิ่งที่ฉันใช้เพื่อรอ VM เพื่อเริ่ม Start-AzureRmVM -ResourceGroupName $ ResourceGroupName -Name $ VmName ขณะที่ ((Get-AzureRmVM -ResourceGroupName $ ResourceGroupName -Name $ VmName -Status | `เลือก -ReportProperty สถานะ '? {$} _.Code - จับคู่ "PowerState"} | `select-ExpandProperty DisplayStatus) - หนึ่ง" VM กำลังทำงาน ") {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 ให้ละเอียดยิ่งขึ้น


นี่เป็นทางออกที่ดีอย่างเหลือเชื่อถ้าคุณต้องการแยกวิเคราะห์ผลลัพธ์!
Jan Rothkegel

การระบุรายการตัวเปลี่ยนเส้นทางOut-xxxxทำให้ฉันเข้าใจได้อย่างรวดเร็วว่าทำไมฉันจึงควรใช้Out-DefaultแทนOut-Nullเนื่องจากฉันต้องการเก็บเอาท์พุทของคอนโซล
Julio Nobre

โปรดทราบว่าไม่จำเป็นต้องทำงานพิเศษใด ๆ ในการเรียกใช้แอปพลิเคชั่นคอนโซลแบบซิงโครนัส - เช่นเดียวกับเชลล์ใด ๆ ซึ่งเป็นลักษณะการทำงานเริ่มต้น ท่อเพื่อOut-String การเปลี่ยนแปลงที่ส่งออกไปเพียงครั้งเดียว, หลายสายสตริงขณะ PowerShell โดยผลตอบแทนที่เริ่มต้นของอาร์เรย์ของสาย Start-Processควรหลีกเลี่ยงสำหรับแอปพลิเคชั่นคอนโซล (เว้นแต่คุณต้องการเรียกใช้ในหน้าต่างใหม่ ) เนื่องจากคุณจะไม่สามารถดักจับหรือเปลี่ยนทิศทางเอาต์พุต
mklement0

ที่จริงแล้วไม่ว่าคำสั่งเนทีฟจะทำงานแบบซิงโครนัส (พร้อมเอาต์พุต) หรือแบบอะซิงโครนัสขึ้นอยู่กับไฟล์สั่งการ ตัวอย่างเช่นหากไม่มีการดักจับเอาต์พุตเอาต์พุตต่อไปนี้จะเป็น "bingo" เท่านั้น & 'C: \ Program Files \ Mozilla Firefox \ firefox.exe' -? ; 'bingo'
Nathan Hartley

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
อาร์กิวเมนต์หลายตัวทำงานอย่างไรในการโทรนั้น พวกเขาเป็นตัวคั่นอย่างไร หนึ่งจะจัดการกับสตริงที่ซ้อนกันหลายวิธีหนีได้อย่างไร TY!
AnneTheAgile

1
@AnneTheAgile doc ใช้พื้นที่ในการแยกอาร์กิวเมนต์เพื่อใช้อักขระแบ็กสแลชเพื่อหลบหนี
ifree

ty @ifree ฉันได้รับ testcomplete เพื่อใช้วิธีนั้น! ฉันใช้เครื่องหมายคำพูดเดี่ยวรอบรายการอาร์กิวเมนต์ที่คั่นด้วยช่องว่าง [1]; แต่ตอนนี้ echo $ exitcode = false ซึ่ง returncode ของฉันไม่ได้จากกระบวนการ? [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 ') .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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.