Twitter を見ていて、イベントログに特定の文字列を含むログが出力された場合に、タスクスケジューラーのトリガーを実行させるためにはというような内容のつぶやきがあり、自分も今まではイベント ID ぐらいでしか制御をしたことがなく、どのように実装できるのか気になったので調べてみました。
次の情報を参考にさせていただきました。
- イベントの使用 (Windows ログ)
- Advanced XML filtering in the Windows Event Viewer
- XPath Reference
- Event Selection
- EventTrigger.ValueQueries プロパティ
- System.windows.eventtrigger> プロパティ
- Scheduled Task – Trigerred by Event – Getting data into the scripts as parameters…- Question
- 20220216: Windows – タスクスケジューラで順位指定の要素値を拾えない
イベントログのフィルター構文
タスクスケジューラーのイベントをトリガーとした場合の基本的な設定画面は次のようなものとなります。
特定のイベントのログが出力された際に、タスクを実行するというトリガーを設定することができますが「カスタム」を選択した場合は、「イベントフィルター」を設定することができ、イベントフィルターは XML で手動で記述することができます。
これはイベントログをフィルターする際にも同様の記述を行うことができます。
この XML のフィルター構文は Get-WinEvent を使用する際にも活用することができ、このコマンドレットの FilterXML オプションを使用した場合などには、XML の内容を活用することができます。
フィルターを考える場合は、コマンドレットで確認してから、トリガーに設定すると効率が良いかもしれませんね。
フィルターの際に使用するのは、XPath 1.0 のサブセットになり、使用できる構文については XPath 1.0 の制限事項 に記載されています。
XPath であれば contains / start-with のような関数を使用することで、文字列のフィルターを柔軟に実行することができますが、イベントログのフィルターで使用できる関数については、次のような関数に限定されており、文字列の曖昧一致はサポートされていないようです。
- position
- Band
- timediff
メッセージが完全一致の場合の検知は = の述語で対応できるのですが、あいまい検索についてはパッと見た感じではサポートされている構文がなさそうだったのですよね…。
特定の文字を含む場合に有効な処理を実行するには?
トリガーのフィルター単体では XPath の構文の制限で、「イベントログに書き込まれたメッセージに特定の文字列を含む場合にタスクを実行」というのは難しそうでした…。
トリガーには、EventTrigger.ValueQueries プロパティ で記載されているように、XPath によって返される値をプロパティとして使用できる機能があります。
例えば、次のような内容がイベントログに出力されたとします。(eventcreate /L Application /T Error /id 100 /D "Test 9999"を実行)
この場合、トリガーでは「Event/EventData/Data」を取得することで、メッセージの内容を取得することができます。
GUI からはこの値を取得するような設定はできないようなのですが、Scheduled Task – Trigerred by Event – Getting data into the scripts as parameters…- Question で説明が行われているような、
- 作成したタスクを XML に出力
- 出力した XML のトリガーの設定に「<ValueQueries></ValueQueries>」のタグを追加し、プロパティとして XML 内の特定の情報を取得
- タスクの実行時引数としてプロパティの値を渡す
というような設定とすることで、タスクに指定した処理の引数として、メッセージの内容を渡すことができます。
実際の XML の変更箇所が次のようになるのですが、「EventTrigger」に次のような「ValueQueries」の設定を追加します。
<ValueQueries> <Value name="TargetData">Event/EventData/Data</Value> </ValueQueries>
この設定で「TargetData」というプロパティ名で XPath の「Event/EventData/Data」の値 (今回の例であれば Test 9999) を取得することができます。
設定したプロパティについては「$(プロパティ名)」という形式で、タスク (操作) の中で利用することができますので、次のような指定ができます。
この指定をした場合は、Test.ps1 のオプションとして、情報を渡すことができますので、PowerShell としては次のようなスクリプトを用意しておくと、メッセージの中に「9999」という文字が含まれている場合だけ処理を実行することができるかと。(ユーザーログイン時のみ実行されているタスクでテストをしているので、適当に Read-Host が入っていますが)
Param( $TargetData ) if($TargetData -match "9999"){ Write-host "TEST" } Read-Host
eventcreate を "Test 9999" というメッセージで実行した場合は、Write-Host が実行されますが、
"Test 1111" というメッセージで出力した場合は、Write-Host が実行されておらず、イベントログに出力されたメッセージの内容でフィルターして何らかの処理が実行できています。
イベント ID が同一で複数のメッセージが出力される可能性があり、特定のメッセージが出力された場合のみ、処理を実行したいという場合は、トリガーでの制御は難しそうなので、トリガーではイベント ID でのみタスクを実行するようなフィルターとしておき、タスク側で、ログに出力されたメッセージを受け取り制御をかけるという方法で実現はできそうな感じでしょうかね。