I need to watch when certain processes are started or stopped on a Windows machine. I'm currently tapped into the WMI system and querying it every 5 seconds, but this causes a CPU spike every 5 seconds because WMI is WMI. Is there a better way of doing this? I could just make a list of running processes and attach an Exited event to them through the System.Diagnostics Namespace, but there is no Event Handler for creation.
相关问题
- Sorting 3 numbers without branching [closed]
- Graphics.DrawImage() - Throws out of memory except
- Why am I getting UnauthorizedAccessException on th
- 求获取指定qq 资料的方法
- How to know full paths to DLL's from .csproj f
My answer here mentions an alternative other than WMI:https://stackoverflow.com/a/50315772/3721646 WMI queries can cost heavy CPU performance if not designed properly. If an intrinsic event from Win32_Process class is used to track process creation event, this impacts performance heavily. An alternate approach is to leverage Security Audit logs. You can enable Process Tracking using Local Security Policy or using a GPO in case of multiple machines. Once the process tracking starts, you can subscribe to security event logs with a custom XML query to monitor certain processes of your interest. The process creation event ID is 4688. `
I've had CPU spikes when listening to WMI events in cases where I have failed to detach properly from my events on exit/cleanup. You might want to check you are not "leaking" WMI event subscriptions. Just in case detach from the event as early as possible and make sure you always do it.
To illustrate further, here's an example from my PowerShell book that listens to WMI events using the PSEventing library:
If I do not do the Disconnect-EventListener bit upon script exit, I get CPU spikes the third or fourth time I attach to the event. My guess is that the system still tries to deliver events.
If you are only looking for PID/Name of your processes, you may instead wish to pick up on Win32_ProcessTrace events, using a WQL query such as "SELECT * FROM Win32_ProcessTrace WHERE TargetInstance.ProcessName = 'name'" if applicable*.
The pitfall of using "SELECT * FROM __InstanceModificationEvent WITHIN 10 WHERE TargetInstance ISA 'Win32Process' AND TargetInstance.Name = 'name'" is in how it works on the back end. If you inspect wbemess.log within your %windir%\system32\wbem\logs directory, you will notice the following logs (using __InstanceDeletionEvent):
As you can see, the actual event implementation on the remote machine is to perform a query against Win32_Process on an interval that is specified by your value in the WITHIN clause. As a result, any processes that start and stop within that poll will never fire an event.
You can set the WITHIN clause to a small value to try and minimize this effect, but the better solution is to use a true event like Win32_ProcessTrace, which should always fire.
*Note that MSDN indicates Win32_ProcessTrace requires a minimum of Windows XP on a client machine and Windows 2003 on a server machine to work. If you are working with an older OS, you may be stuck using the __InstanceModificationEvent query.
This is not exactly how you'd do it in the real world but should help. This seems not to drive my CPU much at all.