接收 WMI 事件

WMI 包含一个事件基础结构,用于生成有关 WMI 数据和服务更改的通知。 WMI 事件类可在发生特定事件时提供通知。

本主题包括以下部分:

事件查询

可以创建半同步异步查询来监视对事件日志、进程创建、服务状态、计算机可用性或磁盘驱动器可用空间以及其他实体或事件的更改。 在编写中,SWbemServices.ExecNotificationQuery 方法用于订阅事件。 在 C++ 中,使用 IWbemServices::ExecNotificationQuery。 有关详细信息,请参阅调用方法

如果是通知标准 WMI 数据模型中发生的变化,则称为内在事件。 内部事件的示例有 __InstanceCreationEvent__NamespaceDeletionEvent。 如果是通知提供程序为了定义提供程序事件而做出的更改,则称为外在事件。 例如,系统注册表提供程序电源管理事件提供程序Win32 提供程序都定义自己的事件。 有关详细信息,请参阅确定要接收的事件类型

示例

下面的脚本代码示例是针对事件类 Win32_NTLogEvent 的内在 __InstanceCreationEvent 的查询。 可以在后台运行此程序,有事件时就会显示一条消息。 如果关闭“等待事件”对话框,程序将停止等待事件。 请注意,必须启用 SeSecurityPrivilege。

Sub SINK_OnObjectReady(objObject, objAsyncContext)
    WScript.Echo (objObject.TargetInstance.Message)
End Sub

Set objWMIServices = GetObject( _
    "WinMgmts:{impersonationLevel=impersonate, (security)}") 

' Create the event sink object that receives the events
Set sink = WScript.CreateObject("WbemScripting.SWbemSink","SINK_")
 
' Set up the event selection. SINK_OnObjectReady is called when
' a Win32_NTLogEvent event occurs
objWMIServices.ExecNotificationQueryAsync sink,"SELECT * FROM __InstanceCreationEvent " & "WHERE TargetInstance ISA 'Win32_NTLogEvent' "

WScript.Echo "Waiting for events"

# Define event Query
$query = "SELECT * FROM __InstanceCreationEvent 
          WHERE TargetInstance ISA 'Win32_NTLogEvent' "

<# Register for event - also specify an action that
displays the log event when the event fires.#>

Register-WmiEvent -Source Demo1 -Query $query -Action {
                Write-Host "Log Event occured"
                $global:myevent = $event
                Write-Host "EVENT MESSAGE"
                Write-Host $event.SourceEventArgs.NewEvent.TargetInstance.Message}
<# So wait #>
"Waiting for events"

以下 VBScript 代码示例演示注册表提供程序定义的外在事件 __RegistryValueChangeEvent。 该脚本使用对 SWbemServices.ExecNotificationQueryAsync 的调用创建临时使用者,并且仅在脚本运行时接收事件。 以下脚本将无限期运行,直到计算机重启、WMI 停止或脚本停止。 若要手动停止脚本,请使用任务管理器来停止进程。 若要以编程方式停止它,请在 Win32_Process 类中使用 Terminate 方法。 有关详细信息,请参阅设置异步调用的安全性

strComputer = "."

Set objWMIServices=GetObject( _
    "winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\default")

set objSink = WScript.CreateObject("WbemScripting.SWbemSink","SINK_")


objWMIServices.ExecNotificationQueryAsync objSink, _
    "Select * from RegistryValueChangeEvent Where Hive = 'HKEY_LOCAL_MACHINE' and KeyPath = 'SYSTEM\\ControlSet001\\Control' and ValueName = 'CurrentUser'"

WScript.Echo "Waiting for events..."

While (True) 
     WScript.Sleep (1000)
Wend

 
WScript.Echo "Listening for Registry Change Events..." & vbCrLf 

While(True) 
    WScript.Sleep 1000 
Wend 

Sub SINK_OnObjectReady(wmiObject, wmiAsyncContext) 
    WScript.Echo "Received Registry Value Change Event" & vbCrLf & wmiObject.GetObjectText_() 
End Sub

事件使用者

在运行脚本或应用程序时,可以使用以下使用者监视或使用事件:

  • 临时事件使用者

    临时使用者是接收 WMI 事件的 WMI 客户端应用程序。 WMI 包含一个唯一接口,用于指定 WMI 要发送到客户端应用程序的事件。 临时事件使用者被视为临时事件,因为仅在用户专门加载时才有效。 有关详细信息,请参阅接收应用程序持续运行期间发生的事件

  • 永久事件使用者

    永久使用者是一个 COM 对象,随时可以接收 WMI 事件。 永久事件使用者使用一组永久性对象和筛选器来捕获 WMI 事件。 与临时事件使用者一样,你可以设置一系列 WMI 对象和筛选器来捕获 WMI 事件。 发生与筛选器匹配的事件时,WMI 将加载永久事件使用者,并向使用者通知该事件。 由于永久使用者是在 WMI 存储库中实现的,并且是在 WMI 中注册的可执行文件,因此永久事件使用者在创建后,甚至在重新启动操作系统后,只要 WMI 正在运行,它也会运行并接收事件。 有关详细信息,请参阅随时接收事件

接收事件的脚本或应用程序具有特殊的安全注意事项。 有关详细信息,请参阅保护 WMI 事件

应用程序或脚本可以使用提供标准使用者类的内置 WMI 事件提供程序。 每个标准使用者类通过发送电子邮件或执行脚本使用不同的操作响应事件。 无需编写提供程序代码即可使用标准使用者类创建永久事件使用者。 有关详细信息,请参阅借助标准使用者监视和响应事件

提供事件

事件提供程序是一个 COM 组件,负责将事件发送到 WMI。 可以创建事件提供程序以在 C++ 或 C# 应用程序中发送事件。 大多数事件提供程序管理 WMI 的对象,例如应用程序或硬件项。 有关详细信息,请参阅编写事件提供程序

计时或重复事件是在预定时间发生的事件。

WMI 提供以下方法来为应用程序创建计时或重复事件:

  • 标准 Microsoft 事件基础结构。
  • 专用计时器类。

有关详细信息,请参阅接收计时或重复事件。 编写事件提供程序时,请注意安全提供事件中标识的安全信息。

建议将永久事件订阅编译为 \root\subscription 命名空间。 有关详细信息,请参阅实现跨命名空间永久事件订阅

订阅配额

轮询事件可能会导致支持对大型数据集进行查询的提供程序出现性能降级的情况。 此外,只要用户对具有动态提供程序的命名空间具有读取访问权,便可以执行拒绝服务 (DoS) 攻击。 WMI 将为组合的所有用户以及位于 \root 命名空间中的单个__ArbitratorConfiguration 实例中的每个事件使用者维护配额。 这些配额是全局的,而不是针对每个命名空间的。 不能更改配额。

WMI 当前使用 __ArbitratorConfiguration 的属性强制实施配额。 每个配额都有一个每个用户和一个包含所有用户组合的总版本,而不是每个命名空间。 下表列出了应用于 __ArbitratorConfiguration 属性的配额。

总计/每个用户 Quota
TemporarySubscriptionsTotal
TemporarySubscriptionsPerUser
10,000
1,000
PermanentSubscriptionsTotal
PermanentSubscriptionsPerUser
10,000
1,000
PollingInstructionsTotal
PollingInstructionsPerUser
10,000
1,000
PollingMemoryTotal
PollingMemoryPerUser
10,000,000 (0x989680) 字节
5,000,000 (0x4CB40) 字节

管理员或是在命名空间中具有 FULL_WRITE 权限的用户可以修改 __ArbitratorConfiguration 的单一实例。 WMI 会跟踪每个用户的配额。

使用 WMI