Recepción de un evento WMI

WMI contiene una infraestructura de eventos que genera notificaciones sobre los cambios en los datos y servicios de WMI. Las clases de eventos WMI proporcionan notificaciones cuando se producen eventos específicos.

En este tema se describen las secciones siguientes:

Consultas de eventos

Puede crear una consulta semisincrónica o asincrónica para supervisar los cambios en los registros de eventos, la creación de procesos, el estado del servicio, la disponibilidad del equipo o el espacio libre de la unidad de disco, y otras entidades o eventos. En el scripting, el método SWbemServices.ExecNotificationQuery se usa para suscribirse a eventos. En C++, se usa IWbemServices::ExecNotificationQuery. Para más información, consulte Llamada a un método.

La notificación de un cambio en el modelo de datos WMI estándar se denomina evento intrínseco. __InstanceCreationEvent o __NamespaceDeletionEvent son ejemplos de eventos intrínsecos. La notificación de un cambio que un proveedor realiza para definir un evento de proveedor se denomina evento extrínseco. Por ejemplo, el proveedor del registro del sistema, el proveedor de eventos de administración de energía y el proveedor de Win32 definen sus propios eventos. Para más información, consulte Determinar el tipo de evento que se va a recibir.

Ejemplo

El siguiente ejemplo de código de script es una consulta para el evento intrínseco __InstanceCreationEvent de la clase de eventos Win32_NTLogEvent. Puede ejecutar este programa en segundo plano y, cuando haya un evento, aparecerá un mensaje. Si cierra el cuadro de diálogo Esperando eventos, el programa deja de esperar eventos. Tenga en cuenta que SeSecurityPrivilege debe estar habilitado.

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"

En el siguiente ejemplo de código de VBScript se muestra el evento extrínseco __RegistryValueChangeEvent que define el proveedor del registro. El script crea un consumidor temporal mediante la llamada a SWbemServices.ExecNotificationQueryAsync y solo recibe eventos cuando se ejecuta el script. El siguiente script se ejecuta indefinidamente hasta que se reinicia el equipo, se detiene WMI o se detiene el script. Para detener el script manualmente, use el Administrador de tareas para detener el proceso. Para detenerlo mediante programación, use el método Terminate en la clase Win32_Process. Para más información, consulte Establecer la seguridad en una llamada asincrónica.

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

Consumidores de eventos

Puede supervisar o consumir eventos mediante los siguientes consumidores mientras se ejecuta un script o una aplicación:

  • Consumidores de eventos temporales

    Un consumidor temporal es una aplicación cliente WMI que recibe un evento WMI. WMI incluye una interfaz única que usa para especificar los eventos de WMI que se van a enviar a una aplicación cliente. Un consumidor de eventos temporales se considera temporal porque solo funciona cuando un usuario lo carga específicamente. Para más información, consulte Recepción de eventos durante la duración de la aplicación.

  • Consumidores de eventos permanentes

    Un consumidor permanente es un objeto COM que puede recibir un evento WMI en todo momento. Un consumidor de eventos permanente usa un conjunto de objetos persistentes y filtros para capturar un evento WMI. Al igual que un consumidor de eventos temporales, configura una serie de objetos WMI y filtros que capturan un evento WMI. Cuando se produce un evento que coincide con un filtro, WMI carga el consumidor de eventos permanente y lo notifica al evento. Dado que un consumidor permanente se implementa en el repositorio WMI y es un archivo ejecutable que se registra en WMI, el consumidor de eventos permanentes opera y recibe eventos después de creado e incluso después de reiniciar el sistema operativo siempre que WMI se esté ejecutando. Para más información, consulte Recepción de eventos en todo momento.

Los scripts o aplicaciones que reciben eventos tienen consideraciones de seguridad especiales. Para más información, consulte Protección de eventos WMI.

Una aplicación o script puede usar un proveedor de eventos WMI integrado que proporciona clases de consumidor estándar. Cada clase de consumidor estándar responde a un evento con una acción diferente mediante el envío de un mensaje de correo electrónico o la ejecución de un script. No es necesario escribir código de proveedor para usar una clase de consumidor estándar para crear un consumidor de eventos permanente. Para más información, consulte Supervisión y respuesta a eventos con consumidores estándar.

Proporcionar eventos

Un proveedor de eventos es un componente COM que envía un evento a WMI. Puede crear un proveedor de eventos para enviar un evento en una aplicación de C++ o C#. La mayoría de los proveedores de eventos administran un objeto para WMI, por ejemplo, una aplicación o elemento de hardware. Para más información, consulte Escritura de un proveedor de eventos.

Un evento programado o periódico es un evento que se produce en un momento predeterminado.

WMI proporciona las siguientes maneras de crear eventos programados o periódicos para las aplicaciones:

  • La infraestructura de eventos estándar de Microsoft.
  • Una clase de temporizador especializada.

Para más información, consulte Recepción de un evento programado o periódico. Al escribir un proveedor de eventos, tenga en cuenta la información de seguridad identificada en Proporcionar eventos de forma segura.

Se recomienda que las suscripciones de eventos permanentes se compilen en el espacio de nombres \root\subscription. Para más información, consulte Implementación de suscripciones de eventos permanentes entre espacios de nombres.

Cuotas de suscripción

El sondeo de eventos puede degradar el rendimiento de los proveedores que admiten consultas en conjuntos de datos enormes. Además, cualquier usuario que tenga acceso de lectura a un espacio de nombres con proveedores dinámicos puede realizar un ataque por denegación de servicio (DoS). WMI mantiene cuotas para todos los usuarios combinados y para cada consumidor de eventos en la única instancia de __ArbitratorConfiguration ubicada en el espacio de nombres \root. Estas cuotas son globales en lugar de para cada espacio de nombres. No se pueden cambiar las cuotas.

WMI aplica actualmente cuotas mediante las propiedades de __ArbitratorConfiguration. Cada cuota tiene una versión por usuario y una versión total que incluye todos los usuarios combinados, no por espacio de nombres. En la tabla siguiente se enumeran las cuotas que se aplican a las propiedades __ArbitratorConfiguration.

Total/PerUser Quota
TemporarySubscriptionsTotal
TemporarySubscriptionsPerUser
10 000
1,000
PermanentSubscriptionsTotal
PermanentSubscriptionsPerUser
10 000
1,000
PollingInstructionsTotal
PollingInstructionsPerUser
10 000
1,000
PollingMemoryTotal
PollingMemoryPerUser
10 000 000 bytes (0x989680)
5 000 000 bytes (0x4CB40)

Un administrador o un usuario con el permiso FULL_WRITE en el espacio de nombres puede modificar la instancia singleton de __ArbitratorConfiguration. WMI realiza un seguimiento de la cuota por usuario.

Uso de WMI