2012-01-12 33 views
19

Aiuto Noob per favore. Sto provando a scrivere uno script che verificherà se un processo è in esecuzione e, in caso contrario, avviarlo. Se il processo è in esecuzione, non dovrebbe fare nulla. Finora ho seguito quanto segue, ma sta avviando una nuova istanza del processo, indipendentemente dal fatto che sia già in esecuzione. Qualsiasi aiuto è apprezzato.PowerShell: se un processo non è in esecuzione, avviarlo

$Prog = "C:\utilities\prog.exe" 
$Running = Get-Process prog -ErrorAction SilentlyContinue 
$Start = ([wmiclass]"win32_process").Create($Prog) 
if($Running -eq $null) 
{$Start} 
else 
{} 

risposta

24

Prima di tutto, ecco cosa c'è di sbagliato nel codice. Nel codice, viene creato il processo prima di valutare se il programma è già in esecuzione

$Prog = "C:\utilities\prog.exe" 
$Running = Get-Process prog -ErrorAction SilentlyContinue 
$Start = ([wmiclass]"win32_process").Create($Prog) # the process is created on this line 
if($Running -eq $null) # evaluating if the program is running 
{$Start} 

E 'possibile creare un blocco di codice che deve essere valutato ulteriormente nel codice avvolgendolo in {} (un scriptblock):

$Prog = "C:\utilities\prog.exe" 
$Running = Get-Process prog -ErrorAction SilentlyContinue 
$Start = {([wmiclass]"win32_process").Create($Prog)} 
if($Running -eq $null) # evaluating if the program is running 
{& $Start} # the process is created on this line 

Tuttavia, se siete alla ricerca di una breve one-liner per risolvere il problema:

if (! (ps | ? {$_.path -eq $prog})) {& $prog} 
+0

OK grazie per la spiegazione chiara. – Charlotte

+0

Non capisco come la soluzione risolverà il problema. La riga '$ Start = ...' avvierà comunque il processo ogni volta. Ho eseguito il test del codice e sono stati avviati i multipli dello stesso processo. (assicurati di testare con un programma che permetta diversi istanti di se stesso) – LosManos

+0

Ciao @LosManos, è possibile che tu abbia dimenticato il {} (scriptblock)? –

3
$path = "C:\utilities\prog.exe"   
$list = get-process | where-object {$_.Path -eq $path }  
if ($list -eq $null) { start-process -filepath $path } 

O

$path = "C:\utilities\prog.exe" 
get-process | where-object {$_.Path -eq $path } | measure-object | where-object { $_.Count -eq 0} | foreach-object {start-process -filepath $path } 

Questo vi farà risparmiare l'istruzione if e una dichiarazione delle variabili. Può essere un comando una riga così:

  1. Get processi
  2. scegliere quelli con il percorso che ti interessa
  3. Usa misura oggetto per ottenere le statistiche sulla lista avete
  4. Continua la tubazione solo se il valore di conteggio di statistiche è 0
  5. processo di avvio

non lasciare che il foreach alla fine scoraggiare. L'oggetto indicatore restituirà solo un articolo il cui valore restituirà uno o zero. Il metodo foreach viene utilizzato solo se il risultato è zero. Non inizierà più di un processo. :)

+1

Non è necessario utilizzare misura/conteggio. Un valore di 0 viene considerato come $ false, diverso da zero è $ true. Guarda la fine della risposta di jon-z per l'implementazione pratica. – x0n

+0

Hai ragione. Grazie per il suggerimento; Ho imparato qualcosa di nuovo. L'ultimo esempio di jon-z sembra essere il più bello. –

9

Nel Get-Process cmdlet, l'argomento del nome del processo deve essere il nome dell'eseguibile senza l'estensione del file. Prova a sostituire $Prog = "C:\utilities\prog.exe" con $Prog = "prog".

A mio parere, la tua sceneggiatura sarebbe più leggibile se hai filtrato il processo in uscita using the Where-Object cmdlet. Ecco un esempio:

$programName = "prog" 
$isRunning = (Get-Process | Where-Object { $_.Name -eq $programName }).Count -gt 0 

if ($isRunning) 
# ... 
else 
# ... 

In questo modo è possibile eliminare l'argomento -ErrorAction SilentlyContinue, che può essere fonte di confusione a qualcuno che non è a conoscenza del fatto che Get-Processgetta un errore se non riesce a trovare un processo con il nome specificato.

+0

OK Non avevo pensato di farlo in quel modo, grazie! – Charlotte

+0

+1 perché il mio errore che mi ha portato qui era che includevo l'estensione. – rbwhitaker

5

Tenere presente che PowerShell gestisce gli oggetti e non solo il testo. Mentre in normali file batch è possibile impostare una variabile in una stringa e poi basta usarlo come un comando:

set Foo=dir /b 
%Foo% 

... questo non funziona in PowerShell.Pertanto, l'assegnazione di $Start crea già il nuovo processo dal comando dopo l'esecuzione dello = e il suo risultato assegnato a $Start.

Inoltre stai complicando le cose inutilmente. Io suggerirei il seguente invece:

$Running = Get-Process prog -ErrorAction SilentlyContinue 
if (!$Running) { Start-Process C:\utilities\prog.exe } 

Dal Get-Process restituisce un oggetto (che restituisce $true) o $null (che restituisce $false) è possibile semplificare il controllo, come mostrato sopra. Si chiama coercizione di tipo, poiché la dichiarazione if prevede un valore booleano e le regole su ciò che verrà trattato come $true e $false sono molto coerenti in questi casi come sopra. E legge meglio.

Ho anche utilizzato il cmdlet Start-Process anziché WMI per creare il nuovo processo. Si potrebbe anche utilizzare il seguente:

if (!$Running) { C:\utilities\prog.exe } 

se l'applicazione non è un'applicazione di console (e quindi potrebbe bloccare lo script PowerShell fino a quando non esce). PowerShell è ancora una shell, quindi avviare i programmi è qualcosa che funziona in modo nativo molto bene :-)

Si potrebbe persino allineare la variabile $running, ma suppongo che un commento sarebbe per chiarire cosa si fa, quindi.

+0

Hai menzionato le regole vero/falso ... Un bel post per aiutarti a capirle da Jeffrey può essere trovato [qui] (http://blogs.msdn.com/b/powershell/archive/2006/12/24/ booleani-valori-e-operators.aspx). –

+0

Penso che la parte più confusa su questo sia la regola con gli array di un elemento, ma hanno senso se si considerano cose come '@ (...)' e si comportano così ingenuamente attesi :-) – Joey

Problemi correlati