はじめに
「JScriptでWMI」も今回で4回目となりました。
こんなに、長くやる予定はなかったのですが、それなりにネタがあったのが驚きです。
今回は、イベントについてです。
個人的には、挙動がイマイチわかりづらいので、あまり利用しません。
イベント待ち合わせ
「ExecNotificationQuery」メソッドを利用して、「SWbemEventSource」オブジェクトを取得し、「NextEvent」メソッドでイベントを待ち合わせを行います。
まずは、サンプルです。
// クエリ設定
var query = "SELECT * FROM __InstanceCreationEvent WITHIN 5"
+ " WHERE TargetInstance ISA 'Win32_Process'"
+ " AND TargetInstance.Name = 'notepad.exe'";
// 「SWbemLocator」オブジェクト取得
var locator = new ActiveXObject("WbemScripting.SWbemLocator");
// 「SWbemServices」オブジェクト取得(ローカルコンピュータ、名前空間「root\CIMV2」)
var services = locator.ConnectServer(null, "root\\CIMV2");
// 「SWbemEventSource」オブジェクト取得
var eventSource = services.ExecNotificationQuery(query);
// 無限ループ
while (true) {
// イベント待ち
var event = eventSource.NextEvent();
// インスタンス取得
var object = event.TargetInstance;
// インスタンス存在チェック
if (object != null) {
// イベント結果
WScript.Echo("Event:" + event.Path_.Class + ",ProcessId=" + object.ProcessId + ",Name=" + object.Name);
}
}
「ExecQuery」メソッドと同じようにクエリ(WQL)を設定しますが、構文がだいぶ異なります。
FROM句に、イベントの種類__InstanceCreationEvent
と、監視間隔WITHIN 5
WHERE句に、インスタンスの指定TargetInstance ISA 'Win32_Process'
と、条件TargetInstance.Name = 'notepad.exe'
を指定します。
サンプルコードでは、「Win32_Process」クラスの「Name」が「notepad.exe」の物を、5秒間隔「WITHIN 5」で作られたら「__InstanceCreationEvent」イベントとして受信する。
といったクエリとなります。
監視間隔時間内に「notepad.exe」を起動→終了した場合は検知されません。
イベントの種類として、良く使うものを表にします。
クラス名 | 説明 |
---|---|
__InstanceOperationEvent | __InstanceCreationEvent __InstanceModificationEvent __InstanceDeletionEvent 全て |
__InstanceCreationEvent | インスタンスの追加時 |
__InstanceModificationEvent | インスタンスの変更時 |
__InstanceDeletionEvent | インスタンスの削除時 |
プロセスを監視したい場合
プロセスの追加、削除イベントを待ち合わせたい場合のサンプルコードです。
// クエリ設定
var query = "SELECT * FROM __InstanceOperationEvent WITHIN 5"
+ " WHERE TargetInstance ISA 'Win32_Process'"
+ " AND TargetInstance.Name = 'notepad.exe'";
// 「SWbemLocator」オブジェクト取得
var locator = new ActiveXObject("WbemScripting.SWbemLocator");
// 「SWbemServices」オブジェクト取得(ローカルコンピュータ、名前空間「root\CIMV2」)
var services = locator.ConnectServer(null, "root\\CIMV2");
// 「SWbemEventSource」オブジェクト取得
var eventSource = services.ExecNotificationQuery(query);
// 無限ループ
while (true) {
// イベント待ち
var event = eventSource.NextEvent();
// インスタンス取得
var object = event.TargetInstance;
// インスタンス存在チェック
if (object != null) {
// イベント種類判定
if (event.Path_.Class == "__InstanceCreationEvent"
|| event.Path_.Class == "__InstanceDeletionEvent") {
// イベント結果
WScript.Echo("Event:" + event.Path_.Class
+ ",ProcessId=" + object.ProcessId + ",Name=" + object.Name);
}
}
}
イベントの種類は__InstanceOperationEvent
で、追加、変更、削除といづれの場合にも受信します。
イベント種類判定処理で、イベントクラスが__InstanceCreationEvent
と`__InstanceDeletionEventだけイベント結果を出力しています。
サービスを監視したい場合
サービスの変更イベントを受信するサンプルです。
監視間隔を10秒としています。
// クエリ設定
var query = "SELECT * FROM __InstanceModificationEvent WITHIN 10"
+ " WHERE TargetInstance ISA 'Win32_Service'"
+ " AND TargetInstance.Name = 'wuauserv'";
// 「SWbemLocator」オブジェクト取得
var locator = new ActiveXObject("WbemScripting.SWbemLocator");
// 「SWbemServices」オブジェクト取得(ローカルコンピュータ、名前空間「root\CIMV2」)
var services = locator.ConnectServer(null, "root\\CIMV2");
// 「SWbemEventSource」オブジェクト取得
var eventSource = services.ExecNotificationQuery(query);
// 無限ループ
while (true) {
// イベント待ち
var event = eventSource.NextEvent();
// インスタンス取得
var object = event.TargetInstance;
// インスタンス存在チェック
if (object != null) {
// イベント結果
WScript.Echo("Event:" + event.Path_.Class
+ ",State=" + object.State + ",Name=" + object.Name);
}
}
その他のイベント待ち合わせ
いままで「InstanceOperationEvent」「InstanceCreationEvent」「InstanceModificationEvent」「InstanceDeletionEvent」などを利用していましたが、他にもイベント待ちのWMIクラスがあります。
その内の一つ、プロセス監視を使ってみます。
クラス名 | 説明 |
---|---|
Win32_ProcessTrace | Win32_ProcessStartTrace Win32_ProcessStopTrace 全て |
Win32_ProcessStartTrace | プロセス追加 |
Win32_ProcessStartTrace | プロセス削除 |
// クエリ設定
var query = "SELECT * FROM Win32_ProcessTrace WHERE ProcessName = 'notepad.exe'";
// 「SWbemLocator」オブジェクト取得
var locator = new ActiveXObject("WbemScripting.SWbemLocator");
// 「SWbemServices」オブジェクト取得(ローカルコンピュータ、名前空間「root\CIMV2」)
var services = locator.ConnectServer(null, "root\\CIMV2");
// 「SWbemEventSource」オブジェクト取得
var eventSource = services.ExecNotificationQuery(query);
// 無限ループ
while (true) {
// イベント待ち
var event = eventSource.NextEvent();
// イベント結果
WScript.Echo("Event:" + event.Path_.Class
+ ",ProcessId=" + event.ProcessID
+ ",Name=" + event.ProcessName);
}
インスタンスが取得出来るわけではなく、イベントのプロパティのみ使えます。
このサンプルの場合「Win32_ProcessTrace」を利用しているので「Win32_ProcessStartTrace」「Win32_ProcessStopTrace」両方のイベントを待ち合わせます。
懸念点
冒頭にも書きましたが、個人的にあまり利用しません。
その大きな理由は以下の二点です。
- 間隔指定なので、取りこぼす場合がある
(だったら、自前でポーリングする) - プロセスの正常な終了方法がわからない
(リソースが宙ぶらりんにならないか心配)