Windowsでほとんどのアクションを監視できることを知っていましたか? いいえ、高価なソフトウェアを購入する必要はありません。インフラストラクチャは、Windows Management Instrumentation(WMI)イベントを介して、サービスの開始や停止、ファイルやフォルダの作成など、さまざまなイベントを監視しています。
WMIイベントはPowerShell固有の機能ではありませんが、WMIイベントを活用して便利なツールを作成するための最も簡単な方法の1つがPowerShellです。このステップバイステップのチュートリアルでは、PowerShellを使ってWMIイベントを活用し、便利なモニタリングツールを作成するスキルを身につける方法を学びます!
さあ、始めましょう!
前提条件
この実践的なチュートリアルでは、多くのデモがあります。デモに合わせて進めるには、以下のものが必要です:
- Windows 7+またはWindows Server 2012+ – このチュートリアルではWindows Server 2019を使用します。
- ローカル管理者グループのユーザーとしてログインしています。
- Windows PowerShell 5.1またはPowerShell 6+ – このチュートリアルではPowerShell v7.1.2を使用します。
WMIとCIMの理解
WMIイベントに入る前に、まず、それらが構築されているインフラストラクチャを理解することが重要です。このチュートリアルではWMIについて詳しく説明しませんが、必要に応じて、MicrosoftのWMIドキュメントを参照して詳細を学ぶことができます。
WMIとその関連データモデルCommon Information Model(CIM)は、Windowsに組み込まれたモデルであり、Windowsの内部動作や実行中のプログラムに関連するほぼすべての情報を格納するためのリポジトリです。
WMIとCIMは、管理者がWindowsをローカルおよびリモートで管理するための強力なツールです。WMIまたはCIMを使用して、管理者はインストールされたアプリケーション、サービスの状態、ファイルシステム上のファイルなど、Windowsシステムに関する情報をクエリできます。
WMIとCIMは、多くのエンタープライズモニタリングソリューションがオペレーティングシステムやアプリケーションの健全性情報を収集する方法です。ただし、WMIを活用するために高価なモニタリングツールを購入する必要はありません。PowerShellを使用できます!
基本的な要素から始めましょう。進めるにつれて、他の必要な要素も学んでいきます:
- クラス:クラスは、PowerShellなどのアプリケーションがデータを読み取りおよび更新するために呼び出すイベントとプロパティです。クラスは名前空間内に配置されています。
- 名前空間:名前空間は、WMI関連のクラスを格納するコンテナです。それは、写真関連のコンテンツを保持するマイピクチャーフォルダーと考えてください。複数の名前空間がありますが、最も一般的なものはCIMv2であり、ほとんどのOSクラスが含まれています。ただし、すべての名前空間は大きな単一の名前空間Rootの下に配置されています。

WMIとCIMの比較
WMIおよびCIMは、Windowsシステム上のリポジトリとやり取りし、WMIイベントと連携するためのメソッドです(詳細は後述します)。しかし、両者にはいくつかの違いがありますが、主な違いは管理者がリモートでそれらとやり取りする方法です。
WMIはWindows NT4で開始され、リポジトリとやり取りするための最初の(かつ唯一の)方法でした。WMIを使用してWindowsシステムを管理する場合、Windowsは分散コンポーネントオブジェクトモデル(DCOM)を使用します。DCOMは、Windowsマシンのデータリポジトリ内の情報を公開するためにWMIが使用するリモートプロトコルです。
ネットワーク上で動作するために、DCOMはリモートプロシージャコール(RPC)を使用します。ネットワーク上で通信するために、RPCは動的ポート範囲を使用しますが、これはファイアウォールやネットワークアドレス変換(NAT)デバイスにとって時々課題となることがあります。
RPCに問題がある場合は、記事「動的ポートでRPC接続をテストする」を参照してください。
マイクロソフトは、Windowsのデータリポジトリとの対話においてより現代的なアプローチを提供するためにCIMを活用することを決定しました。CIMはRPCの代わりにWS-MAN(ManagementのためのWebサービス)を使用し、リモート管理には適したHTTPプロトコルです。
この記事および他の記事では、WMIとCIMは同義語として使用されることがあります。両方の管理方法が対話するデータリポジトリは通常WMIリポジトリと呼ばれます。ほとんどの用語はWMIを指し、CIMは通常PowerShellのコマンドレットで言及されます。
WMI vs. CIM and PowerShell
幸運なことに、PowerShellではWMIとCIMの両方のデータリポジトリとの対話方法を選択することができます。PowerShellはデータリポジトリとの対話するための両方の方法をサポートしています。PowerShellでGet-Command
コマンドを実行すると、Get-WmiObject
、Invoke-WmiMethod
、Remove-WmiObject
、Register-WmiEvent
、Set-WmiInstance
などのさまざまなWmi
コマンドレットが表示されるかもしれません。
Windows PowerShell 3以降(それを使っていることを前提としています)、Get-CimInstance
、Get-CimClass
、Remove-CimInstance
など、似た名前のコマンドレットも表示されるでしょう。
どのPowerShellのコマンドレットを使用するべきですか?答えは簡単です。CIMコマンドレットを使用してください。CIMは、マイクロソフトが重点を置いている新しい標準です。WMIコマンドレットはPowerShell Coreでは使用できません!
WMIのクエリ: 基本
WMIイベントに入る前に、PowerShellでWMIをクエリする方法を理解する必要があります。WMIリポジトリから情報をクエリすることは、WMIデータの最も一般的な使用方法です。
PowerShellの世界では、WMIデータをクエリするためにGet-CimInstance
コマンドレットが便利です。このコマンドレットには、いくつかの異なる方法でWMIデータをクエリすることができます。しかし、このチュートリアルではQuery
パラメータに焦点を当てます。Query
パラメータを使用すると、Windows Query Language (WQL) クエリを提供してWMIをクエリすることができます。
例えば、おそらくWin32_Service
クラスのすべてのWMIインスタンスを見つけたいとします。SQLと同様に、以下に示すようにSelect * from Win32_Service
のクエリを使用します。アスタリスク(*
)は、WMIに対して見つかった各インスタンスのすべてのプロパティを返すように指示します。

上記の例では、すべてのサービスのインスタンスをWin32_Service
クラスで見つけましたが、もしそれらのうちのいくつかだけを見つけたい場合はどうでしょうか?その場合は、WHERE
句を使用します。WHERE
句は、特定の条件に一致するインスタンスのみを返すフィルタを作成します。
WHERE
句は、Get-CimInstance
に対して、インスタンスのプロパティが特定の値と一致する場合にのみインスタンスを返すように指示します。たとえば、State
プロパティがRunning
であるサービスインスタンスのみを検索したい場合は、以下のようにWHERE
句Where State='Running'
を定義します。
以下のように、Get-CimInstance
はState
プロパティがRunning
と等しいサービスインスタンスのみを返します。

WMIイベント:WMIのアクション
WMIには、Windowsの数千のアイテムに関する大量の情報が含まれています。上記のようにクエリを使用してその情報にアクセスできますが、それ以外にもあまり知られていない機能があります。それがWMIイベントです。
Windowsでは、いつでも数百のイベントが発生する可能性があります。ファイルの作成、サービスの停止と開始、ソフトウェアのインストールなど、Windowsのさまざまな機能を使用すると、おそらくWMIイベントがトリガーされます。
Windowsで実行されるほとんどのアクションは、WMIイベントを介して公開できます。Windowsでアクションが実行されると、Windowsは内部のインフラストラクチャを介してイベントをトリガーします。デフォルトでは、これらのイベントは表示されません。バックグラウンドで発生しています。これらのイベントを表示するには、それらに登録する必要があります。
PowerShellを使用したサービスモニタリングスクリプトの作成
WMIイベントの動作を説明するために、たくさんの情報を退屈させる代わりに、便利なツールを作成しましょう。WMIイベントは、Windowsでイベントが発生するときに発生するため、それらを使用して便利な監視ツールを作成することができます。
おそらく、重要なサーバー上で Windows サービスのステータスが変更されたときにログファイルにメッセージを書き込みたいと思うかもしれません。その後、それらのアクションがトリガーする WMI イベントにサブスクライブすることができます。イベントにサブスクライブし、イベントがトリガーされると、PowerShell を使用してファイルにログを記録したり、メールを送信したり、その他のアクションを実行することができます。
高価なモニタリングソリューションを購入する代わりに、シンプルな PowerShell スクリプトは貧乏人の優れたモニタリングツールになるかもしれません!準備ができたら、PowerShell コンソールを開いて、始めましょう!
CIM クラスの検索
静的なインスタンスと同様に、WMI 内ではイベントはクラスに含まれています。これらのクラスには、上記でクエリしたすべての静的データと、それらのインスタンスの変更がトリガーされる場所が含まれています。Microsoft のドキュメンテーションには、すべての CIM クラスのリストがあります。
すべての CIM クラスを検索するには、パラメータなしで Get-CimClass
コマンドレットを実行します。デフォルトでは、Get-CimClass
コマンドレットは ROOT/cimv2
名前空間内のすべてのクラスを返します。 ROOT/cimv2
名前空間は、ほとんどの興味深い Windows クラスが格納されている「メイン」の名前空間です。
下記のように、たくさんのクラスが返されることがわかります。

おそらく、少し調べて、WindowsのサービスがすべてWin32_Service
に保存されていることに気づいたと思います。ですので、クラス名がわかった時は、以下に示すようにClassName
パラメータを使用して名前を指定します。

CIMクラスのプロパティの検索
調べるべきクラスがわかったら、次にどのプロパティを見るべきかを決めなければなりません。インスタンスプロパティの値が変更される(または全体のインスタンスが作成または削除される)と、イベントが発火します。その状態変化をキャプチャしなければなりません。そのためには、どのプロパティを監視したいのかを知る必要があります。
そのプロパティを見つけるためには、前のセクションで問い合わせたCIMクラスインスタンスのCimClassProperties
PowerShellオブジェクトプロパティを調査します。
以下に示すように、そのプロパティの1つがState
プロパティです。

これで、監視したいCIMクラスとプロパティがわかったので、WMIイベントへのサブスクリプションを開始する時です!
WMIイベントサブスクリプションの作成:概要
WMIイベントのサブスクリプションを作成することは、初めて作成する場合は混乱を招くかもしれません。行動を整理するために、まずは全体像を把握するために基本的なステップを概説しましょう。
WMIイベントサブスクリプションの作成には大まかに四つのステップが必要です:
- WQLクエリの作成 – 静的データをクエリする場合と同様に、表示したいWMIイベントのタイプに一致するWQLクエリを作成する必要があります。ただし、データストアをクエリする場合とは異なり、システムクラスやチェックサイクルなど、クエリにはより複雑な構成要素を使用する必要があります(これについては後で説明します)。
- イベントフィルタの作成 – WQLクエリを作成したら、イベントフィルタを作成する必要があります。イベントフィルタは、WQLクエリをCIMに登録します。
- コンシューマの作成 – コンシューマは、イベントフィルタクエリがクラスの変更を返した場合に実行するアクションを定義します。例えば、サービスのステータスが開始、停止、作成、削除されるたびに、コンシューマはアクションをトリガーします。
- イベントフィルタをコンシューマにバインドする – Windows WMIクエリをコンシューマにリンクする接着剤です。バインドは、イベントフィルタが一致を受け取ったことをコンシューマに通知する役割を果たします。
これらのアイテムを組み合わせると、サブスクリプションが作成されます。

WQLクエリの作成
A WQL query for a WMI event looks a bit different than performing a simple query with Get-CimInstance
. Below you’ll find a typical WMI event query.
最初はWQLクエリが複雑に見えるかもしれませんので、それぞれのコンポーネントがどのように機能するかを理解するために分解してみましょう。
システムクラス
Get-CimInstance
の例では、Win32_Service
クラスのインスタンスに変更があった場合に通知を受ける必要があることがわかりました。このクラスはまだ必要ですが、次のようなWQLクエリではなく、
代わりに、クエリは以下のように始まります。クエリしたいメインクラスは、通知を受けたいインスタンスを含んでいるクラスではありません。代わりに、クラスはシステムクラスです。
システムクラスは、イベントによって発生する変更の種類を表す内部クラスです。WMIイベントには、4つのタイプのシステムクラスがあります:
- InstanceModificationEvent – クラス内のインスタンスのプロパティ値の変更をチェックします。このクラスを使用する理由は、
Win32_Service
クラスのインスタンス(サービス)のプロパティ値Status
を監視したいからです。 - InstanceCreationEvent – 新しいインスタンスの作成をチェックします。たとえば、新しく作成されたサービスを監視したい場合は、このシステムクラスを使用します。
- InstanceDeletionEvent – 削除されたインスタンスをチェックします。たとえば、削除されたサービスを監視したい場合は、このシステムクラスを使用します。
- InstanceOperationEvent – このシステムクラスは、変更、作成、削除のすべてのイベントタイプをチェックします。
監視スクリプトでは、WQLクエリの先頭は以下のようになります。
WMIシステムクラス名は常に2つのアンダースコア(__)で始まり、その後にクラスの名前が続きます。
チェックサイクル
次に、チェックサイクルがあります。チェックサイクルには、キーワードwithin
と秒単位で表されるポーリング間隔の値が含まれます。
WMIイベントはリアルタイムではないため、変更をチェックするためにサブスクリプションに特定の間隔を定義する必要があります。例えば、チェックサイクルを10に設定すると、サブスクリプションは前回のポーリングサイクルからの変更を10秒ごとにチェックします。変更が見つかった場合、コンシューマがトリガーされます。
ポーリング間隔内でインスタンスが変更、作成、または削除された場合、変更は検出されません!必要な頻度を考慮しながら、CPUとメモリの使用量に注意してください。
チュートリアルのサービスモニタリングの例では、Windowsサービスの変更を検出するためにWMIを10秒ごとにポーリングするため、チェックサイクルを10に設定しましょう。WQLクエリは増えています!
フィルタ
最後に、WQLクエリを完成させるために、システムクラスから返されるインスタンスを制限するためのフィルタを定義する必要があります。以下の形式でそのフィルタを定義する必要があります。この場合、モニタリングしたいCIMクラスはTargetInstance
と呼ばれています。
ISA
は、指定されたクラスのサブクラスにクエリを適用する演算子です。
チュートリアルではWindowsサービスをモニタリングするためのサブスクリプションを作成しているため、以下のようにフィルタを作成します。
現在のフィルタは、Win32_Service
のすべてのインスタンスを検索します。AND
演算子を使用して、特定のサービスなど、単一のプロパティのみを監視する場合は、
チュートリアルのフィルタ(およびクエリ全体)は、以下のコードスニペットのようになります。
イベントフィルタの作成
クエリフィルタを使用するために、イベントフィルタを作成する必要があります。イベントフィルタは実際にはRoot/subscription
名前空間内の__EventFilter
クラスの別のCIMインスタンスです。
以下に、必要なすべてのものが含まれたコードのスニペットがあります。以下のスクリプトでは、WQLクエリが$FilterQuery
変数に割り当てられます。それから、必要なプロパティと値を含むハッシュテーブルを作成し、イベントフィルタに必要なものです。最後に、New-CimInstance
コマンドレットを実行してイベントフィルタを作成します。
その結果得られるCIMインスタンスオブジェクトは、後で使用するために変数($CIMFilterInstance
)に格納されます。
次に、Get-CimInstance
を実行して、__EventFilter
の新しいCIMインスタンスが作成されたことを確認します。

コンシューマの作成
次に、WindowsがWMIイベントをトリガしたときに発生するアクション、つまりコンシューマを作成する時が来ました。コンシューマを作成する際には、トリガするアクションのタイプに応じていくつかのオプションがあります。
- ActiveScriptEventConsumer – VBScriptなどの任意のスクリプト言語でスクリプトを実行します。
- CommandLineEventConsumer – プロセスを開始します。
悪意のあるバイナリでEXEが置き換えられることを防ぐために、実行可能ファイルのACLが正しく定義されていることを確認してください。
- LogFileEventConsumer – テキストログを作成します。
- NTEventLogEventConsumer – Windowsイベントログにイベントを書き込みます。
- SMTPEventConsumer – メールを送信します。
このチュートリアルでは、WQLクエリで一致するサービスが変更された場合に、LogFileEventConsumer
コンシューマータイプを使用してログファイルに書き込むことにしましょう。
各コンシューマクラスにはそれぞれのパラメータがありますので、各クラスの詳細については
CimClassProperties
をチェックしてください。例:(Get-CimClass -ClassName __NTEventLogEventConsumer).CimClassProperties
。
コンシューマを作成した後は、Get-Ciminstance
でその存在を再度確認してください。

イベントフィルタとコンシューマをバインドする
最後に、このサブスクリプションを完了させてイベントフィルタとコンシューマをバインドします!おそらくお察しの通り、バインディングを作成することは、さらに1つのCIMインスタンスを作成することを意味します。今回は、__FilterToConsumerBinding
クラスで新しいインスタンスを作成する必要があります。
以下のコードスニペットでは、以前に作成した2つのインスタンス(フィルタとコンシューマ)をハッシュテーブルとして使用し、新しいインスタンスを作成するために必要なプロパティを定義しています。それから、以前と同様にNew-CimInstance
に渡され、バインディングを作成します。
いつものように、Get-CimInstance
を実行してバインディングが作成されたことを確認してください。
ご覧のように、バインディングにはFilter
とConsumer
の情報が含まれています。

サブスクリプションのテスト
ついに完了しました!あなたの努力の成果をテストする時間です!今やるべきことは、BITSサービスの状態を変更し、PowerShellがC:\MyCIMMonitoring.txtにログファイルを書き込むかどうかを確認することです。
BITSサービスの状態に応じて、それを停止または開始するか、またはRestart-Service
コマンドレットを使用して再起動してください。
約10秒待って、C:\MyCIMMonitoring.txtを確認してください。今、コンシューマを作成する際に定義したログファイルのText
が表示されるはずです。

すべてのWMIイベントのアクティビティを監視するには、パスApplications and Services Log\Microsoft\Windows\WMI-Activity\OperationalにあるWindowsイベントログをチェックしてください。
サブスクリプションの停止とクリーンアップ
サブスクリプションを使用し終わったら、クリーンアップが必要です。WMIイベントのサブスクリプションを停止して削除するには、イベントフィルタ、コンシューマ、バインディングのインスタンスを削除する必要があります。
まず、Get-CimInstance
を使用してイベントフィルタのインスタンスを見つけ、削除します。

次に、同じ方法でコンシューマを削除します。

最後に、バインディングを削除します。バインディングを見つけるためのプロパティは少し異なります。バインディングのインスタンスにはName
プロパティではなく、実際にはName
プロパティを持つオブジェクトであるFilter
プロパティがあります。

まとめ
WMI/CIMは、Windowsに関する情報を見つけ、WMIイベントで監視するための便利で強力なシステムです。WMIイベントで変更を監視することで、問題が発生した場合の素早い対応と自動化された応答の容易さが得られます。
素晴らしい現実世界の例として、WMI イベントを使用して Active Directory の変更を追跡する方法をご覧ください。
Source:
https://adamtheautomator.com/your-goto-guide-for-working-with-windows-wmi-events-and-powershell/