WMI __InstanceModificationEvent过滤WMI、__InstanceModificationEvent

2023-09-06 15:39:55 作者:残留的回忆

我们在设计我们的系统监控解决方案,我们正在调查WMI作为一个可能的选项。

总之,我们要创建一个通用的系统,应能订阅到WMI数据实例多次更改。我们正在进入__InstanceModificationEvent做到这一点:

下面的原型code显示器在记事本的任何实例的所有变化:

 无效StartMonitor()
{
    VAR的查询=SELECT *
                +FROM __InstanceModificationEvent
                +在1
                +WHERE TargetInstance伊萨\Win32_PerfFormattedData_PerfProc_Process \
                +和TargetInstance.Name = \记事本\;

    VAR范围=新的管理范围(@ROOT \ CIMV2,NULL);
    scope.Connect();

    EventQuery QRY =新EventQuery(查询);

    ManagementEventWatcher W =新ManagementEventWatcher(范围,QRY);
    w.EventArrived + = EventArrived;
    w.Start();
}

无效EventArrived(对象发件人,EventArrivedEventArgs E)
{
    VAR targetInstance =(ManagementBaseObject)e.NewEvent [TargetInstance];

    的foreach(在targetInstance.Properties VAR P)
    {
        Console.WriteLine(p.Name +:\ T+(p.Value = NULL p.Value.ToString():{空})!?);
    }
}
 

所以当记事本的任何实例是变化,我们会得到这样的(节选)输出

  PageFileBytes:1499136
  PageFileBytesPeak:1740800
  PercentPrivilegedTime:0
  PercentProcessorTime:0
  PercentUserTime:0
  PoolNonpagedBytes:7040
  PoolPagedBytes:172856
 
WMI 01 wbemtest的使用

这是好的,但我们需要提高这一点。例如,我们的pretend我们只关心更改PercentProcessorTime。与目前的code,该事件将被解雇时的对象中的任何变化的。这还不够好,因为我们可以监控跨多台计算机上百道工序。

因此​​,我们需要一种方法来指定我们只希望事件被触发时这样或那样的属性更改,不是的整个实例的

使用WMI这可能吗?什么是实现我们想要的最好的做法是什么?

修改:我知道这是可以编写一个查询,例如下面的一个,cycically轮询的价值,但我们希望避免这种做法

  SELECT PercentProcessorTime
 从Win32_PerfFormattedData_PerfProc_Process
 其中name =记事本
 

解决方案

__ InstanceModificationEvent 有一个参考previous实例,所以你可能能够比较值之间的 previousInstance TargetInstance 。例如,要为PercentProcessorTime更改过滤

  VAR的查询=SELECT *
            +FROM __InstanceModificationEvent
            +在1
            +WHERE TargetInstance伊萨\Win32_PerfFormattedData_PerfProc_Process \
            +和TargetInstance.Name = \记事本\
            +!和previousInstance.PercentProcessorTime = TargetInstance.PercentProcessorTime;
 

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"

解决方案

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 ";

 
精彩推荐
图片推荐