WMI __InstanceModificationEvent filtering

2019-08-03 20:15发布

We are designing a monitoring solution for our system, and we're looking into WMI as a possible option.

In short, we want to create a generic system where it shall be possible to subscribe to multiple changes in WMI data instances. We're looking into the __InstanceModificationEvent to do this:

The following prototype code monitors all changes on any instance of notepad:

void StartMonitor()
{
    var query =   "SELECT * "
                + "FROM __InstanceModificationEvent "
                + "WITHIN 1 "
                + "WHERE TargetInstance Isa \"Win32_PerfFormattedData_PerfProc_Process\" "
                + "AND TargetInstance.Name = \"notepad\"";

    var scope = new ManagementScope(@"root\cimv2", null);
    scope.Connect();

    EventQuery qry = new EventQuery(query);

    ManagementEventWatcher w = new ManagementEventWatcher(scope, qry);
    w.EventArrived += EventArrived;
    w.Start();
}

void EventArrived(object sender, EventArrivedEventArgs e)
{
    var targetInstance = (ManagementBaseObject)e.NewEvent["TargetInstance"];

    foreach (var p in targetInstance.Properties)
    {
        Console.WriteLine(p.Name + ":\t" + (p.Value != null ? p.Value.ToString() : "{null}"));
    }
}

So whenever any instance of notepad is changes, we will get an output like this (excerpt)

  PageFileBytes:          1499136
  PageFileBytesPeak:      1740800
  PercentPrivilegedTime:  0
  PercentProcessorTime:   0
  PercentUserTime:        0
  PoolNonpagedBytes:      7040
  PoolPagedBytes:         172856

This is fine, however we need to improve this a bit. For example, let's pretend we are only interested in the changes to PercentProcessorTime. With the current code, the event will be fired whenever anything in the object changes. This is not good enough, because we might monitor hundreds of processes across multiple computers.

Thus, we need a way to specify that we only want the event to be triggered whenever this or that property changes, not the entire instance

Is this possible using WMI? What's the best practice to achieve what we want?

Edit: I know that it is possible to write a query such as the one below and cycically poll for the value, however we were hoping to avoid that approach.

 SELECT PercentProcessorTime 
 FROM Win32_PerfFormattedData_PerfProc_Process 
 WHERE Name = "notepad"

1条回答
倾城 Initia
2楼-- · 2019-08-03 20:41

The __InstanceModificationEvent has a reference to the previous instance so you might be able to compare values between the PreviousInstance and TargetInstance. For example, to filter for PercentProcessorTime changes:

var query =   "SELECT * "
            + "FROM __InstanceModificationEvent "
            + "WITHIN 1 "
            + "WHERE TargetInstance Isa \"Win32_PerfFormattedData_PerfProc_Process\" "
            + "AND TargetInstance.Name = \"notepad\" "
            + "AND PreviousInstance.PercentProcessorTime != TargetInstance.PercentProcessorTime ";
查看更多
登录 后发表回答