2012-01-12 89 views
19

请Noob帮忙。我试图编写一个脚本来检查一个进程是否正在运行,如果没有,请启动它。如果这个过程正在运行,它应该什么也不做。到目前为止,我已经提出了以下内容,但它正在启动流程的新实例,无论它是否已经运行。任何帮助表示赞赏。Powershell - 如果一个进程没有运行,启动它

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

回答

24

首先,这是你的代码有什么问题。 在你的代码,您评估程序是否已经运行之前创建的过程

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

有可能通过在{}包装它创建了应该进一步在你的代码进行计算的代码块(一脚本块):

$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 

不过,如果你正在寻找一个简短的一行来解决问题:

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

好的谢谢你的明确解释。 – Charlotte 2012-01-13 13:00:09

+0

我不明白你的解决方案将如何解决问题。 '$ Start = ...'这一行仍然会每次启动该进程。我测试了代码并开始了同一过程的多个部分。 (确保使用允许数个instanses自己的程序进行测试) – LosManos 2017-04-04 05:50:00

+0

Hi @LosManos,是否有可能忘记{}(scriptblock)? – 2017-04-04 09:33:55

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

或者

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

这将节省您的if语句和一个变量声明。它可以是一个命令行的还有:

  1. 获取处理
  2. 与你有兴趣
  3. 使用度量对象,以获取有关列表中的统计数据的路径选择那些你有
  4. 继续管道只有统计的计数值是0
  5. 启动过程

不要让在末尾的foreach把你赶走。度量对象将只返回一个项,其中返回1或0。如果结果为零,则foreach仅用于执行。它不会启动更多的一个进程。 :)

+1

不需要使用度量/计数。值0被视为$ false,非零值为$ true。看看jon-z的答案是否能够实际实施。 – x0n 2012-01-12 17:14:33

+0

你说得对。感谢小费;我学到了一些新东西。 jon-z的最后一个例子似乎是最好的。 – 2012-01-13 09:22:25

9

Get-Process cmdlet,进程名称参数必须是没有文件扩展名可执行文件的名称。用$Prog = "prog"代替$Prog = "C:\utilities\prog.exe"

在我看来,如果您过滤的过程中出using the Where-Object cmdlet,而不是你的脚本会更具可读性。这里有一个例子:

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

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

这样,你可以摆脱-ErrorAction SilentlyContinue的说法,这可能会造成混淆的人谁不知道的事实,Get-Process抛出一个错误,如果它不能找到一个过程与指定的名称。

+0

好的,我没有想过这样做,谢谢! – Charlotte 2012-01-13 14:41:02

+0

+1,因为我在这里导致我的错误是我包括扩展名。 – rbwhitaker 2013-12-24 22:41:56

5

请记住,PowerShell中处理对象,而不仅仅是文字。而在正常的批处理文件,你可以一个变量设置为一个字符串,然后只是把它作为一个命令:

set Foo=dir /b 
%Foo% 

...这不PowerShell的工作。因此,的分配已经创建新过程,因为=运行后的命令以及其结果分配给$Start

此外,你正在不必要地使事情变得复杂。我建议代替以下:

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

Get-Process由于返回的对象(其计算为$true)或$null(其计算为$false)可以简化像上面所示的检查。这称为类型强制,因为if语句期望布尔值,并且在上述情况下关于什么将被视为$true$false的规则是非常一致的。它读得更好。

我还使用了Start-Process cmdlet而不是WMI来创建新进程。你甚至可以使用下列内容:

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

如果应用程序是不是一个控制台应用程序(并因此会阻止PowerShell脚本直到它退出)。 PowerShell的仍然是一个外壳,使启动程序是一些作品本身非常好:-)

你甚至可以内嵌的$running变量,但我想评论是为了澄清你做什么,然后。

+0

您提到了真实/虚假的规则......一个很好的小贴子可以帮助理解Jeffrey,他们可以在这里找到(http://blogs.msdn.com/b/powershell/archive/2006/12/24/布尔值 - 和 - operators.aspx)。 – 2012-01-12 14:29:34

+0

我认为最令人困惑的部分是单元素数组的规则,但如果您考虑诸如'@(...)'之类的行为并且因此表现得天真预期:-) – Joey 2012-01-12 16:05:43