Empfangen eines WMI-Ereignisses

WMI enthält eine Ereignisinfrastruktur, die Benachrichtigungen zu Änderungen in WMI-Daten und -Diensten erzeugt. WMI-Ereignisklassen bieten Benachrichtigungen, wenn bestimmte Ereignisse auftreten.

In diesem Thema werden die folgenden Abschnitte behandelt:

Ereignisabfragen

Sie können eine halbsynchrone oder asynchrone Abfrage erstellen, um Änderungen an Ereignisprotokollen, Prozesserstellung, Dienststatus, Computerverfügbarkeit oder freiem Speicherplatz auf Datenträgern sowie andere Entitäten oder Ereignisse zu überwachen. Bei der Skripterstellung wird die Methode SWbemServices.ExecNotificationQuery verwendet, um Ereignisse zu abonnieren. In C++ wird IWbemServices::ExecNotificationQuery verwendet. Weitere Informationen finden Sie unter Aufrufen einer Methode.

Die Benachrichtigung über eine Änderung im WMI-Standarddatenmodell wird als systeminternes Ereignis bezeichnet. __InstanceCreationEvent oder __NamespaceDeletionEvent sind Beispiele für systeminterne Ereignisse. Die Benachrichtigung über eine Änderung, die ein Anbieter zum Definieren eines Anbieterereignisses vornimmt, wird als extrinsisches Ereignis bezeichnet. Beispielsweise definieren der Systemregistrierungsanbieter, der Power Management-Ereignisanbieter und der Win32-Anbieter ihre eigenen Ereignisse. Weitere Informationen finden Sie unter Bestimmen des Typs des zu empfangenden Ereignisses.

Beispiel

Das folgende Skriptcodebeispiel ist eine Abfrage für das systeminterne __InstanceCreationEvent der Ereignisklasse Win32_NTLogEvent. Sie können dieses Programm im Hintergrund ausführen, und wenn ein Ereignis vorliegt, wird eine Meldung angezeigt. Wenn Sie das Dialogfeld Warten auf Ereignisse schließen, wartet das Programm nicht mehr auf Ereignisse. Beachten Sie, dass das SeSecurityPrivilege aktiviert sein muss.

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"

Das folgende VBScript-Codebeispiel zeigt das extrinsische Ereignis __RegistryValueChangeEvent, das der Registrierungsanbieter definiert. Das Skript erstellt einen temporären Consumer mithilfe des Aufrufs von SWbemServices.ExecNotificationQueryAsync und empfängt nur Ereignisse, wenn das Skript ausgeführt wird. Das folgende Skript wird unbegrenzt ausgeführt, bis der Computer neu gestartet, WMI beendet oder das Skript beendet wird. Um das Skript manuell zu beenden, beenden Sie den Prozess mithilfe des Task-Managers. Verwenden Sie zum programmgesteuerten Beenden die Methode Terminate in der Win32_Process-Klasse. Weitere Informationen finden Sie unter Festlegen der Sicherheit für einen asynchronen Aufruf.

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

Ereignisconsumer

Sie können Ereignisse mit den folgenden Consumern überwachen oder nutzen, während ein Skript oder eine Anwendung ausgeführt wird:

  • Temporäre Ereignisconsumer

    Ein temporärer Consumer ist eine WMI-Clientanwendung, die ein WMI-Ereignis empfängt. WMI enthält eine eindeutige Schnittstelle, die verwendet wird, um die Ereignisse anzugeben, die WMI an eine Clientanwendung senden soll. Ein temporärer Ereignisverbraucher gilt als temporär, da er nur funktioniert, wenn er von einem Benutzer speziell geladen wird. Weitere Informationen finden Sie unter Empfangen von Ereignissen über die Dauer der Anwendung.

  • Permanente Ereignisconsumer

    Ein permanenter Consumer ist ein COM-Objekt, das jederzeit ein WMI-Ereignis empfangen kann. Ein permanenter Ereignisconsumer verwendet einen Satz persistenter Objekte und Filter, um ein WMI-Ereignis zu erfassen. Wie ein temporärer Ereignis-Consumer richten Sie eine Reihe von WMI-Objekten und Filtern ein, die ein WMI-Ereignis erfassen. Wenn ein Ereignis auftritt, das einem Filter entspricht, lädt WMI den permanenten Ereignisconsumer und benachrichtigt ihn über das Ereignis. Da ein permanenter Consumer im WMI-Repository implementiert ist und eine ausführbare Datei ist, die in WMI registriert ist, wird der permanente Ereignis-Consumer ausgeführt und empfängt Ereignisse nach der Erstellung und auch nach einem Neustart des Betriebssystems, solange WMI ausgeführt wird. Weitere Informationen finden Sie unter Empfangen von Ereignissen zu jeder Zeit.

Skripts oder Anwendungen, die Ereignisse empfangen, haben besondere Sicherheitsaspekte. Weitere Informationen finden Sie unter Schützen von WMI-Ereignissen.

Eine Anwendung oder ein Skript kann einen integrierten WMI-Ereignisanbieter verwenden, der Standard-Consumerklassen bereitstellt. Jede Standard-Consumerklasse reagiert auf ein Ereignis mit einer anderen Aktion, indem sie eine E-Mail-Nachricht sendet oder ein Skript ausführt. Sie müssen keinen Anbietercode schreiben, um eine Standard-Consumerklasse zum Erstellen eines permanenten Ereignis-Consumers zu verwenden. Weitere Informationen finden Sie unter Überwachen von und Reagieren auf Ereignisse mit Standardconsumern.

Bereitstellen von Ereignissen

Ein Ereignisanbieter ist eine COM-Komponente, die ein Ereignis an WMI sendet. Sie können einen Ereignisanbieter erstellen, um ein Ereignis in einer C++- oder C#-Anwendung zu senden. Die meisten Ereignisanbieter verwalten ein Objekt für WMI, z. B. eine Anwendung oder ein Hardwareelement. Weitere Informationen finden Sie unter Schreiben eines Ereignisanbieters.

Ein zeitbasiertes oder sich wiederholendes Ereignis ist ein Ereignis, das zu einem vorher festgelegten Zeitpunkt auftritt.

WMI bietet die folgenden Möglichkeiten zum Erstellen von zeit- oder wiederholten Ereignissen für Ihre Anwendungen:

  • Die standardmäßige Microsoft-Ereignisinfrastruktur.
  • Eine spezialisierte Timerklasse.

Weitere Informationen finden Sie unter Empfangen eines Timed- oder Repeating-Ereignisses. Berücksichtigen Sie beim Schreiben eines Ereignisanbieters die sicherheitsrelevanten Informationen unter Sichere Bereitstellung von Ereignissen.

Es wird empfohlen, dauerhafte Ereignisabonnements in den Namespace \root\subscription zu kompilieren. Weitere Informationen finden Sie unter Implementieren namespace-übergreifender permanenter Ereignisabonnements.

Abonnementkontingente

Das Abfragen nach Ereignissen kann die Leistung von Anbietern beeinträchtigen, die Abfragen über große Datasets unterstützen. Darüber hinaus kann jeder Benutzer, der Lesezugriff auf einen Namespace mit dynamischen Anbietern hat, einen Denial-of-Service-Angriff (DoS) ausführen. WMI verwaltet Kontingente für alle kombinierten Benutzer und für jeden Ereignisconsumer in der einzelnen Instanz von __ArbitratorConfiguration im \root-Namespace. Diese Kontingente sind global und nicht für jeden Namespace. Sie können die Kontingente nicht ändern.

WMI erzwingt derzeit Kontingente mithilfe der Eigenschaften von __ArbitratorConfiguration. Jedes Kontingent verfügt über eine Gesamtversion pro Benutzer und eine Gesamtversion, die alle Benutzer zusammen enthält, nicht pro Namespace. In der folgenden Tabelle sind die Kontingente aufgeführt, die für die Eigenschaften __ArbitratorConfiguration gelten.

Total/PerUser Kontingent
TemporarySubscriptionsTotal
TemporarySubscriptionsPerUser
10.000
1\.000
PermanentSubscriptionsTotal
PermanentSubscriptionsPerUser
10.000
1\.000
PollingInstructionsTotal
PollingInstructionsPerUser
10.000
1\.000
PollingMemoryTotal
PollingMemoryPerUser
10.000.000 (0x989680) Bytes
5.000.000 (0x4CB40) Bytes

Ein Administrator oder ein Benutzer mit Berechtigung FULL_WRITE im Namespace kann die Singletoninstanz von __ArbitratorConfiguration ändern. WMI verfolgt das Kontingent pro Benutzer nach.

Verwenden von WMI