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

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

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

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

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

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

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

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

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

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

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

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

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

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

Тут мы видим, что сначала произошло подключение к пространству 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;}
Оцените статью
Технологии программирования и ведение блога
Добавить комментарий