はじめに
はじめまして、TIGの加藤剛です。2013年キャリア入社で、現在はTIG内に複数あるチームの1つのリーダーをしています。テクノロジー領域としてはインフラやデータベースが明るめの分野です。先日 納期間近の作業中に社用PC端末で少々トラブルがあり復帰対応を行ったのですが、今回はその際の話について、関連する技術要素を織り交ぜながら取り上げてみたいと思います。
問題の概要
社用PCのパッチ自動適用後、一時期から音声・ディスプレイ周辺の動作不良が続いていました。デバイスドライバーを当て直したいところなのですが、調査の中でPC構成情報を見ようとsysteminfoコマンドを実行すると、そこで見慣れないエラー。
c:\ systeminfo |
WindowsのApplicationイベントログにはWMIエラーが数回。**Microsoft-Windows-WMIプロバイダーで イベントID 10 (Error: 0×80041010)**、//./root/CIMV2
の名前空間へのクエリが失敗していることがわかります。無視してドライバーをインストールしようとしても、同様のエラーでインストーラが止まり、ここから進めない状態です。納期が迫る中で立ち往生、ということでWMIの構成を修復していきました。
+ System |
原因はWMIリポジトリ破損
パッチ自動適用の影響なのか真因は不明ながら、ある時点からWMIのリポジトリが破損していました。
尚これが原因で、前述のsysteminfo以外にもWMIベースでの実装されている情報収集機能系の機能は他も軒並みNGという状況でした。例えばmsinfo32のようなコマンド群や、ハードウェアメーカー製のアップデート管理ツールなど。
WMI(Windows Management Instrumentation)とは
そもそもWMIとは何でしょうか。超ざっくり要約するとWindows関連コンポーネントを管理するための汎用メカニズムです。Wikipediaではこのように説明されています。
Windows Management Instrumentation (WMI) は、Windows Driver Modelへの拡張の一種で、システムの構成要素について情報収集と通知を行うオペレーティングシステム (OS) のインターフェースを提供する。WMI はDistributed Management Task Force (DMTF) の定めた Web-Based Enterprise Management (WBEM) と Common Information Model (CIM) 標準のマイクロソフトによる実装である。
WMI により、Windowsを搭載したパーソナルコンピュータやサーバをVBScriptやPowerShellのようなスクリプト言語で(ローカルでもリモートでも)管理できるようになる。WMIはWindows Vista、Windows Server 2003、Windows XP、Windows Me、Windows 2000に最初から実装されている。Windows 95およびWindows 98向けのWMIはダウンロード可能である[1]。
また、マイクロソフトはWMIのキャラクタユーザインターフェースとして Windows Management Instrumentation Command-line (WMIC) を提供している[2]。^ [1] WMI Redistributable for Windows 95 and Windows 98
^ [2] Description of WMIC
WMI (Windows Management Instrumentation) の Instrumentationという単語は「計器」や「計器による測定」を意味します。自動車の計器類がエンジンに関する情報を示すように、WMIはコンピュータシステムの内部状態に関する情報を示します。WMIでは、Windowsシステム内に検出されたディスクやプロセスなどのオブジェクトをモデリングすることにより、計器情報を提供します。
WMIによるシステムオブジェクトのモデリングには、Win32_LogicalDisk
や Win32_Process
などのクラスが使用されます。クラス名から推察できるように、Win32_LogicalDisk
はコンピュータ上の論理ディスクをモデリングするクラス、Win32_Process
はコンピュータ上で現在稼動している任意のプロセスをモデリングするクラスです。クラスは、Common Information Model (CIM) と呼ばれる拡張可能スキーマに基づいています。CIM スキーマは、Distributed Management Task Force の公開規格です。
WMIには、上記のほか、イベント処理、リモート処理、クエリ処理、ビュー、スキーマのユーザー拡張、情報取得などの機能もあります。汎用メカニカズムですので、これに準拠することで全てのメーカーのハードウェアやソフトウェアで統一的に使えるようになります。
WMIのアーキテクチャ
続いて、WMIのアーキテクチャについて紐解いていきます。詳細はMicrosoftの WMI Architecture に纏まっています。
WMIはコンピュータ、ネットワーク、ローカルまたはリモートのアプリケーションやスクリプトに対して、統一インタフェースを提供するわけですが、ポイントはWMIクライアントアプリケーションとスクリプトが多数のOS-APIを呼び出す必要がないように設計された点でしょう。 WMI以外の多くのAPIは、スクリプトやVisual Basicアプリケーションなどのオートメーションクライアントから呼び出すことはできず、リモートコンピュータも呼び出しません。WMIからデータを取得するには、WMIクラスにアクセスするクライアントスクリプトまたはアプリケーションを作成するか、WMIプロバイダーを作成してWMIにデータを提供します。
- WMIアーキテクチャ構成図の概略と各層の役割を以下に示します。
1.WMI providers and managed objects
- WMIプロバイダー
- 1つ以上の管理対象オブジェクトのWMIを監視するCOMオブジェクトです。
- ドライバー同様に、プロバイダーはWMIに管理対象オブジェクトからのデータを提供し、WMIから管理対象オブジェクトへのメッセージを処理します。 DLLファイルと、プロバイダーがデータを返し、操作を実行するクラスを定義する管理対象オブジェクト形式(MOF)ファイルで構成され、WMI C++アプリケーションなどのプロバイダーは、WMI用のCOMAPIを使用します。
- 管理対象オブジェクト
- ハードディスクドライブ、ネットワークアダプター、データベースシステム、OS、プロセス、サービスなどの論理的または物理的なエンタープライズコンポーネントです。
- プロバイダーの例は、システムレジストリ内のデータにアクセスするプリインストールされたレジストリプロバイダーなどがあります。
プロバイダーによって、1クラス内のメソッドとプロパティの数的関係性は絶対のルールはなくマチマチです。
- 物理構造体の特徴
- WMI MOFおよびDLLファイルは、Winmgmt.exeやMofcomp.exeなどのWMIコマンドラインツールとともに
%WINDIR%\System32\Wbem
に置かれます。Win32_LogicalDisk
などのプロバイダークラスはMOFファイルで定義され、システムの起動時にWMIリポジトリにコンパイルされます。
- WMI MOFおよびDLLファイルは、Winmgmt.exeやMofcomp.exeなどのWMIコマンドラインツールとともに
2. WMI infrastructure
- WMIインフラストラクチャはWMIサービス(winmgmt)として知られるWindows OSコンポーネントで、 WMIリポジトリとWMIコアの2つのコンポーネントがあります。
- WMIリポジトリ
- WMI名前空間によって編成されます。名前空間はWMIサービスによってシステムの起動時に作成され、Win32クラス、WMIシステムクラスなどのクラス定義のデフォルトのセットをプレーンストールします。
- システム起動時に作成される名前空間には、
root\default
、root\cimv2
、root\Subscription
などがあります。システムにある残りの名前空間は、OSまたは製品の他の部分のプロバイダーによって作成されます。
- WMIコア
- プロバイダー、管理アプリケーション、およびWMIリポジトリ間の仲介役として機能します。プロバイダーによって定義されたクラスなど、オブジェクトに関する静的データのみがリポジトリに保存されます。 WMIはクライアントが要求したときにプロバイダーからほとんどのデータを動的に取得します。
- ちなみに上記は、Microsoftの説明原文(WMI Architecture)では以下のようにWMIコアではなく「WMI service」の説明として記載されていますが、内容の整合性を踏まえるとWMIコアの役割に関する説明と読み取るのが妥当なのではと思われます。
The WMI service acts as an intermediary between the providers, management applications, and the WMI repository. Only static data about objects is stored in the repository, such as the classes defined by providers. WMI obtains most data dynamically from the provider when a client requests it. You also can set up subscriptions to receive event notifications from a provider. For more information, see Monitoring Events.
3. WMI consumers (management applications)
- WMIインフラストラクチャと対話する管理アプリケーションあるいはスクリプトです。
- 管理アプリケーションは、WMI用のCOMAPIまたはWMI用のScriptingAPIのいずれかを呼び出すことにより、クエリ、データの列挙、プロバイダーメソッドの実行、またはイベントのサブスクライブを行うことができます。ディスクドライブやサービスなどの管理対象オブジェクトで使用できるデータまたはアクションは、プロバイダーが提供するものだけとなります。
WMIを扱うためのWindows標準ツール
WMIによる情報取得や管理操作を行うのに利用できるWindows標準ツールには、以下のような方法があります。
No | ツール名 | 概要説明 |
---|---|---|
1 | WMICコマンド (wmic) | Windows標準のCUIベースの情報走査ツール。コマンドラインからWMIにアクセスできる。データアクセスはWQLベースではない。外部記事によるコマンド具体例はこちら。アーキテクチャ階層の「WMI consumers」にあたる。 |
2 | WMIテスト (wbemtest) | Windows標準ツールのGUIベースの情報走査ツール。WQLエディターに相当。WMI名前空間への接続、クラス定義の確認、そしてクラスのメソッド実行をテストすることができる。また、MOFCOMPでCIMリポジトリに登録された情報を削除することも可能。アーキテクチャ階層の「WMI consumers」にあたる。 |
3 | WMIコントロール (wmimgmt.msc) | Windows標準のGUI管理ツール。WMIの構成と制御を行うツールで、WMIデータベースのバックアップと復元、WMIサービスに対するアクセスのセキュリティ設定を行うことができる。ただし、WMIデータにアクセスする機能はない。アーキテクチャ階層の「WMI infrastructure」にあたる。 |
上記以外だと、以前はMicrosoftのサイトで「WMI Administrative Tools」というWQLツールも配布されていたようですが、現在ではDLできないようになっています。WQLベースのツールとしては前述の表No.2の「wbemtest」と、軽量・簡易なフリーソフトとして、WMI Queryというものが知られています。
補足:WQL (WMI Query Language)について
最後に、WQLについて補足しておきます。
WQL(WMI Query Language)は「SQL for WMI」と記載されることある、WMI特有の拡張機能を複数持つ構造化照会言語 (SQL) の単純化されたサブセットです。 WMIの情報を取得するには、WMIクラスのインスタンスを取得し、取得したWMIクラスの各インスタンスのプロパティから情報を取得するという流れで作業します。この操作をWQLと呼ばれるSQL文を使い取得することが可能です。SQL文の場合、通常はデータベースやテーブルを操作しますが、WQLではWMIクラスが対象となります。
冒頭に出てきたイベントログでも、以下のようになっていましたね。
Query //./root/CIMV2 |
発生していた問題への対処
ではここまでの内容を頭に置きつつ、以降は話を戻し、不調な我がPCを復帰させていきます。
結論から言うと、最終的にWMIを再構成することで解決しました。
手順は至ってシンプルで、WMIサービスを止めて、リポジトリを再作成するのみです。今回は ディスプレイ制御がおかしく仕方なく カッコよく? GUIを使わずコマンドでやってみようということで、PowerShellのコマンドレットをベースに操作していきます。詳細は割愛しますがWindows標準コマンドのsc(sc.exe)も高機能でよく使うコマンドですので、もう忘れたという方は是非思い出してあげてください(というか、scでは簡単にできることでもPowerShellだと大変なことも割とあります)。
WMIサービス状態と構成の確認
まずはサービスの状態、設定を確認していきます。ここでは主にWMI(Windows Management Instrumentation
サービス)の起動状態とサービス実名を確認しています。なお以降PowerShellは基本的に 「管理者として実行」 しています。
PS C:\windows\system32> Get-Service | Where-Object { $_.displayname -eq "Windows Management Instrumentation"}|select-object status, starttype, name, displayname |
続いて依存関係も併せて確認していきます。コマンドレットのオプションの意味合いが少しわかりにくいのですが、意味は以下の通りです。
- -DependentServices:WinMgmt「に」依存しているサービス
- -RequiredServices:WinMgmt「が」依存しているサービス
PS C:\Windows\system32> Get-Service -DependentServices Winmgmt |
小技ですが、上記は横着するとこんな感じで一度に取得することも可能です。
PS C:\Windows\System32> Get-Service -Name WinMgmt | Where-Object {$_.RequiredServices -or $_.DependentServices} | |
実はこの後のWMIリポジトリ再作成時に少しだけハマった部分なのですが、当該サービス、Windowsサービスの回復設定で停止検知後(正確にはエラー検知)に自動で再度立ち上がってくる設定になっていることがわかります。
PS C:\Windows\System32> C:\Windows\System32\sc.exe qfailure Winmgmt |
なお、PowerShellで sc qfailure
相当の自動回復設定の確認方法がパッとわからなかったため、ここでは少しズル? をしてsc
コマンドをコールしています。sc.exe
をフルパスで呼んでいるのは、試したこのある方はニヤッとされるかもしれませんが、Powershellのコマンドレットである sc (Set-Content)
のエイリアスとsc.exe
の名前が重複して、Set-Content
が優先されるためです。
WMIサービスを停止
前述の手順で確認した通り、WMIサービスには依存関係のあるサービスがありますので-Force
で強制停止します。
PS C:\Windows\System32> Stop-Service -Name WinMgmt |
リポジトリ情報フォルダをリネーム
リポジトリの実体は %windir%\system32\repository
配下にあり、以下のようなファイルが格納されます。今回はこれらをリネームし、WMIサービスを改めて起動することでリポジトリを再作成(=プロバイダークラスをリコンパイル)していきます。
PS C:\windows\system32> Set-Location .\wbem\ |
モタモタしているとWMIサービスが自動起動で起き上がってきてリネームが失敗するので、クイックに。
PS C:\windows\system32\wbem> Move-Item -Path ".\repository\" .\repository.bk20210118A\ |
既にWMIサービスが自動起動されている場合にはアクセス拒否が返されます。この場合は、前述のWMIサービス停止をもう一度行ってからすぐにリネームしましょう。正常に実行できると画面上は応答メッセージなしとなります。
WMIサービス再起動、そして動作確認
あとは手動でサービスを起動すれば終わりです。サービスが起動してくると、%windir%\system32\wbem
配下に新たにrepositoryフォルダが作成され、再構成が完了します。サービス回復による自動起動が働くため、タイミング次第では以下にように既に起動中といったことになりますが、%windir%\system32\repository
フォルダが新たに作成されていることが確認できれば問題ありません。
PS C:\Windows\System32> Start-Service -Name WinMgmt |
これで解決です。この後、本来やりたかったデバイスドライバーを再適用をしてハードウェア制御が正常に戻りました(よかった)。
PS C:\windows\system32> systeminfo |
最後に
今回は、普段よく扱っているサーバサイドではなく自分のPC端末でのトラブルを契機に、WMIについて取り上げてみました。自分のメインPCがおかしくなるのは、ある意味 サーバトラブルとはまた一味違った焦りがあるものですね。クラウド上のサーバと違って、壊れたらすぐに替えがきかない機器ということで、少し緊張感の高い作業でした。折角の機会なので久方ぶりのWindowsのコマンド操作の復習をしつつ、WMIのアーキテクチャ面の基礎を改めて整理をしてみましたので、どこかで誰かのご参考になればと思います。
ところで、普段動いているのが当たり前の機能やサービスが、何か想定外トラブルでダウンしてしまうことってそれなりにありますよね。私のメインの守備範囲の1つはインフラですが、インフラでいうとどこかのクラウドサービスがまた別のクラウドサービスをバックボーンに動いていて、大元のサービスが障害になった時に「あ、こういう関係性で動いていたんだ…」とその時になって気付くことがあります。また、こうしたケースでは依存先のサービスが公称されていないことが大半で、その影響は事前になかなかわからないものです。
今回のPC上でのトラブル程度でもいざ起こってみると案外色々な機能に影響が出て混乱しましたが、エンタープライズ領域のシステムにおける影響は、ある端末で起きたWMIエラーのようなかわいいものではすみません。普段のシステムデザインにおける考慮事項として、こういった可能性は常に頭において考えていきたいものですね。
ではまた!
参考情報
- https://docs.microsoft.com/en-us/windows/win32/wmisdk/wmi-architecture
- https://docs.microsoft.com/ja-jp/powershell/scripting/samples/managing-services?view=powershell-7.1
- https://docs.microsoft.com/ja-jp/windows-hardware/drivers/kernel/implementing-wmi
- https://www.manageengine.jp/products/OpManager/how-to-rebuild-wmi.html
- https://websetnet.net/ja/how-to-repair-or-rebuild-the-wmi-repository-on-windows-10/