Come dire a PowerShell di attendere la fine di ciascun comando prima di iniziare il successivo?


212

Ho uno script di PowerShell 1.0 per aprire solo un sacco di applicazioni. La prima è una macchina virtuale e le altre sono applicazioni di sviluppo. Voglio che la macchina virtuale finisca l'avvio prima che vengano aperte le altre applicazioni.

In bash potrei solo dire "cmd1 && cmd2"

Questo è quello che ho ...

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

Risposte:


367

Normalmente, per i comandi interni PowerShell attende prima di iniziare il comando successivo. Un'eccezione a questa regola è EXE basato su sottosistema Windows esterno. Il primo trucco è pipeline per Out-Nullamare così:

Notepad.exe | Out-Null

PowerShell attenderà fino alla chiusura del processo Notepad.exe prima di continuare. È carino ma un po 'sottile da leggere leggendo il codice. Puoi anche usare Start-Process con il parametro -Wait:

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

Se si utilizza la versione di PowerShell Community Extensions è:

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

Un'altra opzione in PowerShell 2.0 è utilizzare un processo in background:

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

2
Colpa mia. Start-Process -Wait funziona alla grande, ma ora lo vedo non è quello che stavo cercando ... In realtà sto cercando di aspettare fino a quando il vm termina l'avvio. Immagino che sarà dura. Suppongo che dovrò trovare un nuovo thread per quello. Grazie ma.
John Mee,

7
Fantastico, ha | out-nullfatto proprio quello di cui avevo bisogno. Start-JobHo provato a usare ma poiché sto passando i risultati delle funzioni come parametri, mi è venuto un po 'di skitzoid, quindi non ho potuto usare l'ultimo suggerimento ...
jcolebrand

6
Come nota a margine, se è necessario passare più argomenti con -ArgumentList, separarli con virgole come -ArgumentList /D=test,/S.
sschuberth,

1
Grazie per la semplice soluzione "<percorso verso exe> | Out-Null"! Il problema con il metodo "Start-Process <percorso verso exe> -NoNewWindow -Wait" è che PowerShell si interrompe fino al completamento di tutti i processi figlio generati dal padre, anche se il padre termina prima di loro. Ciò ha causato problemi al nostro programma di installazione.
zax,

Questo è ciò che uso per attendere l'avvio di una VM Start-AzureRmVM -ResourceGroupName $ ResourceGroupName -Name $ VmName while ((Get-AzureRmVM -ResourceGroupName $ ResourceGroupName -Name $ VmName -Status | `select -ExpandProperty Statuses |` { _.Code -match "PowerState"} | `select -ExpandProperty DisplayStatus) -ne" VM running ") {Start-Sleep -s 2} Start-Sleep -s 5 ## Dare alla VM il tempo di venire in modo che possa accettare richieste remote
andrewmo,

47

Oltre all'utilizzo Start-Process -Wait, il piping dell'output di un eseguibile farà attendere Powershell. A seconda delle necessità, io di solito tubo Out-Null, Out-Default, Out-Stringo Out-String -Stream. Ecco un lungo elenco di alcune altre opzioni di output.

# 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

Mi mancano gli operatori in stile CMD / Bash a cui hai fatto riferimento (&, &&, ||). Sembra che dobbiamo essere più prolissi con Powershell .


Questa è una soluzione incredibilmente buona se devi analizzare l'output!
Jan Rothkegel,

L' indicazione dell'elenco dei redirector Out-xxxx mi ha permesso rapidamente di capire perché dovrei usare Out-Default invece di Out-Null , poiché avevo bisogno di mantenere l'output della console.
Julio Nobre

Si noti che non è necessario alcun lavoro aggiuntivo per eseguire le applicazioni della console in modo sincrono - come in qualsiasi shell, questo è il comportamento predefinito. Il piping per Out-String modificare l'output in una stringa singola a più righe , mentre PowerShell per impostazione predefinita restituisce una matrice di righe . Start-Processdovrebbe essere evitato per le applicazioni console (a meno che non si desideri veramente eseguirle in una nuova finestra ) perché non sarà possibile acquisire o reindirizzare il loro output.
mklement0

In realtà, se un comando nativo viene eseguito in modo sincrono (con output) o in modo asincrono dipende dall'eseguibile. Ad esempio, senza catturare l'output, il seguente produce solo "bingo". & 'C: \ Programmi \ Mozilla Firefox \ firefox.exe' -? ; 'bingo'
Nathan Hartley,

12

Basta usare "Wait-process":

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

il lavoro è fatto


8

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

È inoltre possibile utilizzare l' -PassThruopzione per l'eco dell'output.


Si noti che -PassThrunon riecheggia l' output (un'applicazione non console per definizione non produrrà output console), genera System.Diagnostics.Processun'istanza che rappresenta il processo appena avviato, quindi è possibile esaminare le sue proprietà e attendere che termini in seguito.
mklement0

6

Alcuni programmi non riescono a elaborare molto bene il flusso di output, utilizzando pipe per Out-Nullnon bloccarlo.
E ha Start-Processbisogno del -ArgumentListpassaggio per passare argomenti, non così conveniente.
C'è anche un altro approccio.

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

1
come funzionano più argomenti in quella chiamata? come sono delimitati? come si fa a gestire la fuga di varie stringhe nidificate? ty!
AnneTheAgile,

1
@AnneTheAgile doc usa lo spazio per separare gli argomenti, per evadere dal carattere usa la barra rovesciata
ifree

A proposito di @ifree, ho fatto il test completo per funzionare in quel modo! Ho usato virgolette singole intorno all'elenco di argomenti delimitati da spazi. [1]; ma ora echo $ exitcode = false, quale non era il mio codice di ritorno dal processo? [1] $ exitCode = [Diagnostics.Process] :: Start ("c: \ Programmi (x86) \ SmartBear \ TestComplete 10 \ Bin \ TestComplete.exe", '"c: \ Users \ ME \ Documents \ TestComplete 10 Progetti \ hig4TestProject1 \ hig4TestProject1.pjs "/ run / project: myProj / test:" KeywordTests | zTdd1_Good "/ exit ') .WaitForExit (60)
AnneTheAgile

3

L'inclusione dell'opzione -NoNewWindowmi dà un errore:Start-Process : This command cannot be executed due to the error: Access is denied.

L'unico modo per farlo funzionare era chiamare:

Start-Process <path to exe> -Wait

0

Portandolo oltre potresti persino analizzare al volo

per esempio

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

0

C'è sempre cmd. Potrebbe essere meno fastidioso se hai problemi a citare gli argomenti per avviare il processo:

cmd /c start /wait notepad
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.