Powershell - 如果没有Excel进程,添加catch以获取

时间:2013-10-27 10:18:13

标签: excel powershell com

是否可以仅将

添加到if / else catch中
$excelId = get-process excel | %{$_.Id} | ?{$before -notcontains $_}

如果没有excel进程在运行?例如如果 Excel 正在运行,那么get-process id,如果没有,则忽略它。

  

Get-Process:找不到名为“excel”的进程。验证   进程名称并再次调用cmdlet。在run.ps1:3 char:24 + $之前   = @(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 $_}

3 个答案:

答案 0 :(得分:5)

您可以使用-ErrorAction参数,告诉PowerShell SilentlyContinue您的脚本Get-Process的结果是什么;之后,$?将根据最终出现的错误进行设置(因此也缺少您正在寻找的流程):

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

答案 1 :(得分:2)

我会这样做:

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

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

但是,我并不反对Efran Cobisi's answer:这是处理这种特定情况的另一种有效方式。

答案 2 :(得分:1)

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

Get-Process 'exce[l]'

完全按照你的要求行事。

Quirk解释

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' S:

$excel = Get-Process excel -ErrorAction SilentlyContinue

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

$excel = Get-Process excel -ErrorAction Ignore

文档说:

  

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

但请记住:

  

Windows PowerShell 3.0中引入了Ignore值。

但是这个问题变得越来越少了。

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

真正的潜在问题是使用更大的PID集(我允许看到的所有进程的PID),其中一个捕获的PID用于进程的冲突的可能性更大终止,并在目标进程启动时重用PID。在那种不太可能的情况下(因为时间窗口太小)但是可能的事件,目标进程将被排除在考虑之外(因为它的PID将在$ before列表中)并且看起来似乎没有启动进程。

这是一个非常小的窗口,可能并不担心,但您可以跟踪进程StartTime属性以及ID,以使碰撞的机会消失得很小。您可以使用[System.Diagnostics.Process]::GetProcessById消除PID重用的可能性来打开进程(返回包含系统句柄的Process对象),但它可能不值得(但如果这样做,请务必关闭)通过调用Process对象的Close方法来处理句柄。