Powershell-如果没有Excel进程,则添加要拾取的捕获

Powershell-如果没有Excel进程,则添加要拾取的捕获,excel,powershell,com,Excel,Powershell,Com,是否有方法将if/else捕获添加到only $excelId = get-process excel | %{$_.Id} | ?{$before -notcontains $_} 如果没有excel进程正在运行?e、 g.如果Excel正在运行,则获取进程id,如果没有,则忽略它 获取进程:找不到名为“excel”的进程。验证 进程名称,然后再次调用cmdlet。在run.ps1:3 char:24+之前 =@(get process您可以使用-ErrorAction参数,告诉PowerS

是否有方法将if/else捕获添加到only

$excelId = get-process excel | %{$_.Id} | ?{$before -notcontains $_}
如果没有excel进程正在运行?e、 g.如果Excel正在运行,则获取进程id,如果没有,则忽略它

获取进程:找不到名为“excel”的进程。验证 进程名称,然后再次调用cmdlet。在run.ps1:3 char:24+之前
=@(get process您可以使用
-ErrorAction
参数,告诉PowerShell继续
脚本,无论
get process
的结果是什么;之后,
$?
将根据最终出现的错误(以及您正在寻找的进程的缺失)进行设置:

我想这样做:

$before = Get-Process | % { $_.Id }
$excel=new-object -com excel.application
$excelId = Get-Process excel | % { $_.Id } | ? { $before -notcontains $_ }
这通过预先收集所有进程的ID来避免问题。这样,无论是否存在现有的Excel进程,我们都会遵循相同的步骤。如果没有,那么过滤器
?{$before-notcontains$}
将不匹配并排除任何进程,我们只会返回新进程的PID


但是,我并不反对:这是处理此特定场景的另一种有效方法。

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

我会照你说的做

怪癖得到了解释

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])]"
(好吧,这很难看,但它是有效的,如果你愿意,你可以把它拆开。)

一些备选方案。

@埃夫兰:

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

$excel = Get-Process excel -ErrorAction Ignore
文件说:

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

但也要记住:

Windows PowerShell 3.0中引入了忽略值

但这已经越来越不成问题了

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

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

这是一个非常小的窗口,可能不需要担心,但您可以跟踪进程StartTime属性和ID,以使冲突消失的可能性非常小。您可以使用
[System.Diagnostics.process]::GetProcessById
来打开进程,从而消除PID重用的可能性(返回一个包含系统句柄的流程对象),但这可能不值得(但如果需要,请确保通过调用流程对象的close方法来关闭句柄)

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