Powershell – 添加赶上,如果没有Excel进程

有没有办法只添加一个if / else catch

$excelId = get-process excel | %{$_.Id} | ?{$before -notcontains $_} 

如果没有excel进程运行? 例如,如果Excel正在运行,则获取进程ID,如果没有,则忽略它。

Get-Process:找不到名称为“excel”的进程。 validation进程名称并再次调用该cmdlet。 在run.ps1:3 char:24 + $ before = @(get-process <<<< excel |%{$ _ .Id})+ CategoryInfo:ObjectNotFound:(excel:String)[Get-Process],ProcessCommandException + FullyQualifiedErrorId:NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand

我的代码行3-5如下:

 $before = @(get-process excel | %{$_.Id} ) $excel=new-object -com excel.application $excelId = get-process excel | %{$_.Id} | ?{$before -notcontains $_} 

我会这样做:

 $before = Get-Process | % { $_.Id } $excel=new-object -com excel.application $excelId = Get-Process excel | % { $_.Id } | ? { $before -notcontains $_ } 

通过预先收集所有进程的ID,避开了这个问题。 这样,无论是否存在Excel进程,我们都遵循相同的步骤。 如果没有,那么filter? { $before -notcontains $_ } ? { $before -notcontains $_ }不会匹配并排除任何进程,我们将只返回新进程的PID。

不过,我并不反对Efran Cobisi的回答 :这是处理这种特殊情况的另一种有效方法。

您可以使用-ErrorAction参数,无论Get-Process的结果如何,都可以SilentlyContinue告诉PowerShell继续执行脚本。 之后, $? 将根据最终出现的错误来设置(因此您也正在查找过程的缺失):

 $excel = Get-Process excel -ErrorAction SilentlyContinue if (-not $?) { 'Excel is not running.' } 

这个问题已经有了很好的答案,但是我还有一个基于Get-Process(和其他几个cmdlet)的怪癖:

 Get-Process 'exce[l]' 

会做你所问的。

奇怪的解释

Get-Process cmdlet和许多其他cmdlet使用不同的通配符处理名称。 而:

 Get-Process 'NonExistentProc' 

会产生一个错误,使用:

 Get-Process 'NonExistentProc*' 

将通配符'*'添加到最后,不会生成错误。 您可能会猜测在这种情况下返回一个空数组。 这对我来说最有意义,但是当找不到匹配时,返回$ null。

对于你的情况,如果你使用:

 get-process 'excel*' 

如果excel没有运行,你不会得到一个错误,但是你会匹配'excelHelper'和任何以'excel'开头的可能是问题的进程名。 你可以通过使用非常窄的通配符模式来解决这个问题:

 get-process 'exce[l]' 

方括号通配符将匹配括号中的任何一个字符。 通常给定一个集合或范围,但在这里我们使用单个字符的退化情况。 只有'excel'会被匹配,但是因为使用通配符,所以找不到匹配不会产生错误。

如果要将其推广到任何给定的进程名称,可以计算该模式:

 $procName = 'excel' Get-Process "$($procName.Substring(0, $procName.length-1))[$($procName[-1])]" 

(好吧,这很丑陋,但是很有效,如果你愿意的话,你可以分解它。)

一些替代品。

@ Efran的:

 $excel = Get-Process excel -ErrorAction SilentlyContinue 

是好的(我upvoted它),但错误被添加到$错误。 在一些较大的系统中,我已经看到$ error被检查或稍后处理的脚本,所以我通常更喜欢使用-ErrorAction Ignore

 $excel = Get-Process excel -ErrorAction Ignore 

该文件说:

与SilentlyContinue不同,Ignore不会将错误消息添加到$ Error自动variables中。

但是也要记住:

忽略值是在Windows PowerShell 3.0中引入的。

但是这个问题已经越来越less了。

@彼得的回答很简单,在逻辑上是正确的(忽略可能的竞争条件,见下文)。 我高举了它。 虽然在这种情况下没有真正的性能问题(我刚刚testing过,并且在我的机器上运行了200个进程,但他的代码仍然能够立即运行),但是我却错误地创build了199个不需要的进程对象。

真正的潜在问题是使用更大的一组PID(对于我允许看到的所有进程使用PID),碰撞的机会更大,其中一个捕获的PID用于终止进程并且PID被重用目标进程开始。 在那种不太可能的情况下(因为时间窗口太小)而是可能发生的事件,目标进程将被忽略(因为它的PID将在$之前的列表中),并且看起来没有进程开始。

这是一个非常小的窗口,可能不用担心,但是您可以跟踪进程StartTime属性以及ID,以使碰撞的几率变得很小。 您可以使用[System.Diagnostics.Process]::GetProcessById来打开进程(返回一个包含系统句柄的Process对象)来消除PID重用的可能性,但这可能不值得(但是如果你这样做的话,一定要通过调用Process对象的Close方法closures句柄)。