Подписка на временные потребители событий WMI

Подписка на временные потребители событий WMI WMI - администрирование Windows

В этой статье  хочу рассмотреть подписку на события WMI, а точнее временные потребители событий. В данном случае, подписка на события не требует внедрения в саму систему, так как обработка будет происходить лишь до тех пор, пока работает сценарий. Подписка на временные потребители событий может производиться в трёх режимах: синхронный, полусинхроный и асинхронный.

Давайте рассмотрим каждый режим в отдельности.

Подписка на события в синхронном режиме

Как уже упоминалось в прошлой статье «События WMI«, при подписке на внутренние события используются, в зависимости от надобности, три разных класса – для работы с экземплярами, для работы с пространством имен и с самими классами, непосредственно. Каждый из этих классов позволяет реагировать на три типа событий: создание, изменение и уничтожение объекта.

Подписка на события - синхронный режим

Давайте сделаем так, ниже, я приведу два примера на языке VBScript и JScript, которые будут производить подписку на события, логика их работы идентична – реагировать на запуск процесса в системе:

'*********************************************
' Имя: process_creation_sync.vbs
' Подписка на события в синхронном режиме (запуск процесса)
'*********************************************
Option Explicit
 
Dim objService, objEventSource, objEvent, strResult
Set objService = GetObject("WinMgmts:\\.\Root\CIMV2")
Set objEventSource = objService.ExecNotificationQuery ("SELECT * FROM __InstanceCreationEvent " &  _
             "WITHIN 2 WHERE TargetInstance ISA 'Win32_Process'")          
 
                             'Ждем наступления события WMI и записываем в переменную objEvent
Set objEvent = objEventSource.NextEvent
WScript.Echo "Был запуск процесса " & objEvent.TargetInstance.Name
//*********************************************
// Имя: process_creation_sync.js
// Подписка на события в синхронном режиме (запуск процесса)
//*********************************************
 
var objService, objEventSource, objEvent, strResult;
objService = GetObject("WinMgmts:\\\\.\\Root\\CIMV2");
objEventSource = objService.ExecNotificationQuery ("SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_Process'");        
//Ждем наступления события WMI и записываем в переменную objEvent
objEvent = objEventSource.NextEvent();
WScript.Echo ("Был запуск процесса " + objEvent.TargetInstance.Name);

Теперь давайте разберем все по пунктам.

Set objService = GetObject(«WinMgmts:\.RootCIMV2») — Сперва с помощью функции GetObject мы подключаемся к нужному нам пространству имен, переменная objService  будет хранить ссылку на экземпляр объекта SWbemServices (Он возвращается каждый раз, когда происходит подключение к пространству WMI).

С помощью метода ExecNotificationQuery объекта SWbemServices мы выполняем WQL запрос в синхронном режиме, он собственно и производит подписку на события:

«SELECT * FROM __InstanceCreationEvent WITHIN 2 ISA ‘Win32_Process'»

Давайте разберем суть данного WQL запроса:

SELECT * FROM __InstanceCreationEvent – подключаемся к классу __InstanceCreationEvent (он отвечает за то, был ли создан экземпляр заданного класса).

WITHIN 2 – указываем временный интервал в 2 секунды – проверка, не произошло ли событие.

WHERE TargetInstance – тут свойство TargetInstance описывает текущее состояние управляемого ресурса, что бы просмотреть предыдущее состояние, надо использовать свойство PreviousInstance.

ISA ‘Win32_Process’ – запрос будет применен к подклассу Win32_Process.

В предпоследней строчке:

Set objEvent = objEventSource.NextEvent

Мы вызываем метод NextEvent объекта SWbemEventSource, ссылка на него хранится в переменной objEventSource. Метод NextEvent ждет наступления события, которому соответствует объект SWbemEventSource, после чего возвращается объект swbemobject с опи­санием произошедшего события (переменная objEvent).

После запуска сценария ничего не произойдет, просто появится процесс wscript.exe, как только произойдёт запуск какого-то процесса (приложения, программы), сценарий выдаст сообщение и завершит свою работу.

Подписка на события в полусинхронном режиме

Порядок подписки на события в полусинхронном режиме

Процесс подписки на события в полусинхронном режиме практически идентичен предыдущим примерам, разница лишь в том, что тут у метода ExecNotificationQuery есть дополнительные числовые параметры, их значение равно сумме двух констант: wbemFlagForwardOnly (значение 32) и wbemFlagReturnImmediately (значение 16). Ниже привожу пример для подписки на события в полусинхронном режиме на запуск любого процесса:

'*********************************************
' Имя: process_creation_polusync.vbs
' Подписка на события в полусинхронном режиме (запуск процесса)
'*********************************************
Option Explicit
Dim objService, objEventSource, objEvent, strResult
 
Const wbemFlagForwardOnly =32
Const wbemFlagReturnImmediately =16
 
'Подключвемся к пространству имен
Set objService = GetObject("WinMgmts:\\.\Root\CIMV2")
'Выполняем WQL запросс
Set objEventSource = objService.ExecNotificationQuery ("SELECT * FROM __InstanceCreationEvent " & _
             "WITHIN 2 WHERE TargetInstance ISA 'Win32_Process'",,wbemFlagReturnImmediately+wbemFlagForwardOnly)          
'Ждем наступления события WMI и записываем в переменную objEvent
Set objEvent = objEventSource.NextEvent
WScript.Echo "Был запуск процесса " & objEvent.TargetInstance.Name
//*********************************************
// Имя: process_creation_polusync.js
// Подписка на события в полусинхронном режиме (запуск процесса)
//*********************************************
 
var objService, objEventSource, objEvent, strResult;
 
var wbemFlagForwardOnly = 0x20; //32
var wbemFlagReturnImmediately = 0x10; //16
 
//Подключвемся к пространству имен
objService = GetObject("WinMgmts:\\\\.\\Root\\CIMV2");
//Выполняем WQL запросс
objEventSource = objService.ExecNotificationQuery("SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_Process'","WQL",wbemFlagReturnImmediately | wbemFlagForwardOnly);        
//Ждем наступления события WMI и записываем в переменную objEvent
objEvent = objEventSource.NextEvent();
WScript.Echo ("Был запуск процесса " + objEvent.TargetInstance.Name);

Подписка на события в асинхронном режиме

Порядок подписки на события в асинхронном режиме

При выполнении подписки на события в асинхронном режиме после подключения к пространству имен нужно дополнительно создать ссылку на экземпляр объекта SWbemSink, после чего будет производиться обработка событий, которые будут возникать в данном объекте при выполнении и завершении асинхронной операции. Далее, подписка на событие происходит с помощью метода ExecNotificationQueryAsync объекта swbemservices (ссылка на него появляется автоматически после подключения к пространству имен WMI), для него в качестве первого параметра указывается переменная-объект SWbemSink, а уже в качестве второго параметра – строка, которая содержит нужный нам WQL запрос.

Что бы прояснить ситуацию, давайте посмотрим на пример ниже:

'*********************************************
' Имя: process_creation_async.vbs
' Подписка на событие в асинхронном режиме (запуск процесса)
'*********************************************
Option Explicit
Dim objService, objEventSource, objSink, bDone
Set objService = GetObject("WinMgmts:\\.\Root\CIMV2")
Set objSink = WScript.CreateObject("WbemScripting.SWbemSink", "Sink_")
objService.ExecNotificationQueryAsync objSink,"SELECT * FROM __InstanceCreationEvent " & _
             "WITHIN 2 WHERE TargetInstance ISA 'Win32_Process'"
 
WScript.Echo "Работает сценаий"
' Приостанавляваем выполнение сценария до наступления события
While Not bDone
WScript.Sleep 1000
Wend
 
' Как только произойдет событие, будет выполнена процедура  
Sub Sink_OnObjectReady(oOutParams,oContext)
     WScript.Echo "Был запуск процесса " & oOutParams.TargetInstance.Name
     bDone = True
End Sub

Тут мы видим, что сначала произошло подключение к пространству WMI.

Set objSink = WScript.CreateObject(«WbemScripting.SWbemSink», «Sink_») – тут мы создали ссылку на объект SWbemSink, параметр Sink_ говорит о том, что все процедуры должны начинаться с этого префикса.

Далее следует выполнение метода ExecNotificationQueryAsync, где в качестве первого параметра используется префикс objSink.

Цикл While Not bDone WScript.Sleep 1000 Wend будет работать до тех пор, пока переменная bDone не примет значение TRUE, фактически, с помощью данного цикла мы просто приостанавливаем выполнение сценария, если этого не сделать, то сценарий завершит свою работу не дождавшись появления события.

Процедура Sink_OnObjectReady относится непосредственно к объекту SWbemSink, как только подписка на событие произойдет, то управление передастся в тело данной процедуры. Параметр oOutParams будет хранить информацию о происшедшем событии. Как видим, как только событие произошло, то переменной bDone было присвоено значение True, если этого не сделать, то сценарий будет не один раз создавать подписку на события, а в бесконечном цикле.

Скачать архив с примерами

Ну и аналогичный пример на Jscript:

//*********************************************
// Имя: process_creation_async.js
// Подписка на событие в асинхронном режиме (запуск процесса)
//*********************************************
 
var objService, objEventSource, objEvent, strResult, objSink, bDone=false;
objService = GetObject("WinMgmts:\\\\.\\Root\\CIMV2");
objSink = WScript.CreateObject("WbemScripting.SWbemSink", "Sink_");
objEventSource = objService.ExecNotificationQueryAsync (objSink,"SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_Process'");
 
WScript.Echo ("Работает сценаий")
// Приостанавляваем выполнение сценария до наступления события
while (!bDone){
WScript.Sleep (1000);
}
 
// Как только произойдет событие, будет выполнена процедура  
function Sink_OnObjectReady(oOutParams,oContext){
     WScript.Echo ("Был запуск процесса " + oOutParams.TargetInstance.Name);
     bDone = true;
}
Оцените статью
Технологии программирования и ведение блога
Добавить комментарий