Powershell - 如果进程未运行,请启动它

时间:2012-01-12 11:25:49

标签: powershell

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

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

4 个答案:

答案 0 :(得分:28)

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

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

答案 1 :(得分:10)

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

在我看来,如果您将流程过滤掉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 抛出错误这一事实的人感到困惑找不到具有指定名称的进程。

答案 2 :(得分:5)

请记住,PowerShell处理对象而不仅仅是文本。在普通批处理文件中,您可以将变量设置为字符串,然后将其用作命令:

set Foo=dir /b
%Foo%

...这在PowerShell中不起作用。因此,$Start的分配已经创建了新的流程,因为在运行=并将其结果分配给$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仍然是一个shell,因此启动程序本身就能很好地工作: - )

你甚至可以内联$running变量,但我想一个评论是为了澄清你的所作所为。

答案 3 :(得分:4)

$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. 时才继续管道
  6. 开始流程
  7. 不要让foreach最终让你失望。 measure对象将只返回一个将返回1或0的项。 foreach仅用于在结果为零时执行。它不会启动多个进程。 :)