3

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

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

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

Get-Process:找不到名为“excel”的进程。验证进程名称并再次调用 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 $_}
4

3 回答 3

6

您可以使用该-ErrorAction参数,告诉 PowerShell 到SilentlyContinue您的脚本,无论结果Get-Process是什么;之后,$?将根据最终存在的错误进行设置(因此也没有您正在寻找的过程):

$excel = Get-Process excel -ErrorAction SilentlyContinue
if (-not $?) { 'Excel is not running.' }
于 2013-10-27T10:25:37.050 回答
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 的回答:这是处理这种特殊情况的另一种有效方法。

于 2013-10-27T10:36:57.127 回答
2

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

Get-Process 'exce[l]'

将完全按照您的要求进行。

怪癖解释

Get-Processcmdlet 和许多其他 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])]"

(好吧,这很丑陋,但它有效,如果你愿意,你可以把它拆开。)

一些替代品。

@埃弗兰的:

$excel = Get-Process excel -ErrorAction SilentlyContinue

很好(我赞成),但是在 $error 中添加了一个错误。在一些较大的系统中,我看到了稍后检查或处理 $error 的脚本,因此我通常更喜欢使用-ErrorAction Ignore

$excel = Get-Process excel -ErrorAction Ignore

文档说:

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

但也要记住:

Ignore 值是在 Windows PowerShell 3.0 中引入的。

但这变得越来越不重要了。

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

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

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

于 2015-09-09T09:27:55.487 回答