WMI进程监视使用太多的CPU! 有更好的方法吗?

我需要观察在Windows机器上启动或停止某些进程的时间。 我目前正在进入WMI系统并每隔5秒查询一次,但由于WMI是WMI,因此每5秒就会产生一次CPU峰值。 有更好的方法吗? 我可以只列出正在运行的进程并通过System.Diagnostics命名空间将Exited事件附加到它们,但是没有用于创建的事件处理程序。

在我退出/清理时无法从事件中正确分离的情况下,我在收听WMI事件时遇到CPU峰值。 您可能想要检查您是否“泄漏”WMI事件订阅。 以防万一从事件中脱离,并确保你总是这样做。

为了进一步说明,这是我的PowerShell书籍中使用PSEventing库监听WMI事件的示例:

Add-PSSnapin PSEventing -ErrorAction SilentlyContinue

$ queryString = @’SELECT * FROM __InstanceModificationEvent WITHIN 10 WHERE TargetInstance ISA’Win32_Service’AND TargetInstance.Name =’w3svc’AND TargetInstance.State =’Stopped”@

$ query = New-Object System.Management.WQLEventQuery`-argumentList $ queryString

$ watcher = New-Object System.Management.ManagementEventWatcher($ query)

Connect-EventListener观察者EventArrived

$ watcher.Start()

echo“等待W3CSVC服务停止……”Get-Event -wait | foreach { Write-Host -foreground Red“W3SVC服务已停止!” }

$ watcher.Stop()

Disconnect-EventListener观察者EventArrived

回声“完成”

如果我在脚本退出时没有执行Disconnect-EventListener位,我会在第三次或第四次附加到事件时获得CPU峰值。 我的猜测是系统仍然试图传递事件。

如果您只是在寻找进程的PID /名称,您可能希望使用WQL查询来获取Win32_ProcessTrace事件,例如“SELECT * FROM Win32_ProcessTrace WHERE TargetInstance.ProcessName =’name’”( 如果适用)*

使用“SELECT * FROM __InstanceModificationEvent WITHIN 10 WHERE TargetInstance ISA’Win32Process’AND TargetInstance.Name =’name’”的缺陷在于它在后端的工作原理。 如果检查%windir%\ system32 \ wbem \ logs目录中的wbemess.log,您将注意到以下日志(使用__InstanceDeletionEvent):

 (Wed Jul 22 13:58:31 2009.73889577):在名称空间//./root/CIMV2中的TargetInstance ISA'Win32_Process'中,从__InstanceDeletionEvent中注册查询select *的通知接收器。
 (Wed Jul 22 13:58:31 2009.73889577):激活filter047209E0,查询选择*来自__InstanceDeletionEvent 10,其中TargetInstance ISA'Win32_Process'在命名空间//./root/CIMV2中。
 (Wed Jul 22 13:58:31 2009.73889577):使用查询select *从__ClassOperationEvent激活filter0225E560,其中TargetClass是名称空间//./root/CIMV2中的“Win32_Process”。
 (Wed Jul 22 13:58:31 2009.73889577):激活filter'select * from __ClassOperationEvent其中TargetClass是一个带有提供者$ Core的“Win32_Process”'
 (Wed Jul 22 13:58:31 2009.73889587):激活filter'select * from __InstanceDeletionEvent 10 in TargetInstance ISA'Win32_Process''with provider $ Core
 (Wed Jul 22 13:58:31 2009.73889587):从Win32_Process创建轮询查询select *以满足事件查询select * from __InstanceDeletionEvent 10 in TargetInstance ISA'Win32_Process'
 (Wed Jul 22 13:58:31 2009.73889587):在命名空间'//./root/CIMV2'中执行轮询查询'select * from Win32_Process'
 (Wed Jul 22 13:58:31 2009.73889697):轮询查询'select * from Win32_Process'完成
 (Wed Jul 22 13:58:41 2009.73899702):在命名空间'//./root/CIMV2'中执行轮询查询'select * from Win32_Process'
 (Wed Jul 22 13:58:41 2009.73899792):轮询查询'select * from Win32_Process'完成

如您所见,远程计算机上的实际事件实现是在由WITHIN子句中的值指定的时间间隔内对Win32_Process执行查询。 因此,在该轮询中启动和停止的任何进程都不会触发事件。

您可以将WITHIN子句设置为较小的值以尝试最小化此效果,但更好的解决方案是使用Win32_ProcessTrace之类的真实事件,该事件应始终触发。

*请注意,MSDN表示Win32_ProcessTrace需要客户端计算机上的最低Windows XP和服务器计算机上的Windows 2003才能工作。 如果您使用的是较旧的操作系统,则可能会遇到使用__InstanceModificationEvent查询的问题。

我的答案在这里提到了除WMI之外的其他选择: https: //stackoverflow.com/a/50315772/3721646如果设计不当,WMI查询可能会导致CPU性能过高。 如果使用Win32_Process类中的内部事件来跟踪进程创建事件,则会严重影响性能。 另一种方法是利用安全审计日志。 您可以使用本地安全策略启用进程跟踪,或者在多台计算机的情况下使用GPO。 进程跟踪开始后,您可以使用自定义XML查询订阅安全事件日志,以监控您感兴趣的某些进程。 进程创建事件ID是4688.`