2012-01-12 28 views
19

Noob help please. Intento escribir un script que compruebe si un proceso se está ejecutando, y si no, inícielo. Si el proceso se está ejecutando, no debería hacer nada. Hasta ahora he llegado a lo siguiente, pero está comenzando una nueva instancia del proceso, independientemente de si ya se estaba ejecutando. Cualquier ayuda es apreciada.Powershell: si un proceso no se está ejecutando, inícielo

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

Respuesta

24

En primer lugar, esto es lo que está mal en su código. En su código, el proceso se crea antes de evaluar si su programa ya está en marcha

$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} 

Es posible crear un bloque de código que debe ser evaluado aún más en su código envolviéndolo en {} (una 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 

Sin embargo, si usted está buscando un corto de una sola línea para resolver su problema:

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

OK gracias por una explicación clara. – Charlotte

+0

No entiendo cómo su solución resolverá el problema. La línea '$ Start = ...' todavía comenzará el proceso cada vez. Probé se ejecutó el código y se iniciaron los múltiplos del mismo proceso. (asegúrese de probar con un programa que permita varios instantes de sí mismo) – LosManos

+0

Hola @LosManos, ¿es posible que hayas olvidado {} (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 } 

Esto le ahorrará la sentencia if y una declaración de variables. Puede ser un comando de una línea así:

  1. de obtener procesos
  2. elegir las que con el camino que está interesado en
  3. objeto Uso medida para obtener las estadísticas sobre la lista que tiene
  4. Continuar la tubería sólo si el valor de recuento de las estadísticas es 0
  5. proceso de inicio

no deje que el foreach al final te desanime. El objeto de medida devolverá solo un elemento donde devolverá uno o cero. El foreach solo se usa para ejecutar si el resultado es cero. No comenzará más de un proceso. :)

+1

No hay necesidad de utilizar la medida/cuenta. Un valor de 0 se trata como $ falso, distinto de cero es $ verdadero. Mire el final de la respuesta de jon-z para la implementación práctica. – x0n

+0

Tienes razón. Gracias por el consejo; Aprendí algo nuevo. El último ejemplo de jon-z parece ser el mejor. –

9

En el Get-Process cmdlet, el argumento del nombre del proceso debe ser el nombre del ejecutable sin la extensión de archivo. Intente sustituir $Prog = "C:\utilities\prog.exe" con $Prog = "prog".

En mi opinión, su secuencia de comandos sería más legible si filtrara el proceso fuera using the Where-Object cmdlet en su lugar. He aquí un ejemplo:

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

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

De esa manera usted puede deshacerse del argumento -ErrorAction SilentlyContinue, que puede ser confuso para alguien que no es consciente del hecho de que Get-Processgenera un error si no puede encontrar un proceso de con el nombre especificado.

+0

OK No había pensado en hacerlo de esa manera, ¡gracias! – Charlotte

+0

+1 porque mi error que me llevó aquí fue que estaba incluyendo la extensión. – rbwhitaker

5

Tenga en cuenta que PowerShell maneja objetos y no solo texto. Mientras que en los archivos por lotes normales se podría establecer una variable en una cadena y luego simplemente utilizarlo como un comando:

set Foo=dir /b 
%Foo% 

... esto no funciona en PowerShell.Así, su asignación de $Start ya se crea el nuevo proceso, ya que el comando después de la = se ejecuta y su resultado asignado a $Start.

Además eres complicar las cosas innecesariamente. Me gustaría sugerir lo siguiente en su lugar:

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

Desde Get-Process devuelve un objeto (que se evalúa como $true) o $null (que evalúa a $false) se puede simplificar el registro de entrada, como se muestra arriba. Esto se llama conversión de tipos, ya que la declaración if espera un valor booleano y las normas sobre lo que va a ser tratada como $true y $false son muy consistentes en tales casos que el anterior. Y se lee mejor.

También utilicé el Start-Process cmdlet en lugar de WMI para crear el nuevo proceso. Incluso se puede utilizar lo siguiente:

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

si la aplicación no es una aplicación de consola (y por lo tanto podría bloquear la secuencia de comandos PowerShell hasta que sale). PowerShell sigue siendo un shell, por lo que iniciar programas es algo que funciona de forma nativa muy bien :-)

Incluso podría alinear la variable $running, pero supongo que un comentario sería para aclarar lo que hace, entonces.

+0

Usted ha mencionado las verdaderas reglas/falso ... Un pequeño post para ayudar a entender por Jeffrey ellos se puede encontrar [aquí] (http://blogs.msdn.com/b/powershell/archive/2006/12/24/ boolean-values-and-operators.aspx). –

+0

Creo que la parte más confusa de eso es la regla con arreglos de un elemento, pero tienen sentido si se consideran cosas como '@ (...)' y se comportan así ingenuamente :-) – Joey

Cuestiones relacionadas