フューチャー技術ブログ

不調PCを介抱しつつWMIに思いを馳せる

はじめに

はじめまして、TIGの加藤剛です。2013年キャリア入社で、現在はTIG内に複数あるチームの1つのリーダをしています。テクノロジー領域としてはインフラやデータベースが明るめの分野です。先日 納期間近の作業中に社用PC端末で少々トラブルがあり復帰対応を行ったのですが、今回はその際の話について、関連する技術要素を織り交ぜながら取り上げてみたいと思います。

問題の概要

社用PCのパッチ自動適用後、一時期から音声・ディスプレイ周辺の動作不良が続いていました。デバイスドライバーを当て直したいところなのですが、調査の中でPC構成情報を見ようとsysteminfoコマンドを実行すると、そこで見慣れないエラー。

c:\ systeminfo
オペレーティング システム情報を読み込んでいます... エラー: 無効なクラスです

WindowsのApplicationイベントログにはWMIエラーが数回。**Microsoft-Windows-WMIプロバイダーで イベントID 10 (Error: 0x80041010)**、//./root/CIMV2の名前空間へのクエリが失敗していることがわかります。無視してドライバーをインストールしようとしても、同様のエラーでインストーラが止まり、ここから進めない状態です。納期が迫る中で立ち往生、ということでWMIの構成を修復していきました。

Windows-Eventlog(Application)
  + System
- Provider
[ Name] Microsoft-Windows-WMI
(中略)
EventID 10
Version 2
Level 2
Task 0
Opcode 0
Keywords 0x8000000000000000
- TimeCreated
(中略)
- UserData
- data_0x8000003F
Query //./root/CIMV2
Namespace SELECT TargetInstance FROM __InstanceCreationEvent WITHIN 10 WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.Name = 'lync.exe'
Error 0x80041010

原因は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_LogicalDiskWin32_Process などのクラスが使用されます。クラス名から推察できるように、Win32_LogicalDisk はコンピュータ上の論理ディスクをモデリングするクラス、Win32_Process はコンピュータ上で現在稼動している任意のプロセスをモデリングするクラスです。クラスは、Common Information Model (CIM) と呼ばれる拡張可能スキーマに基づいています。CIM スキーマは、Distributed Management Task Force の公開規格です。

WMIには、上記のほか、イベント処理、リモート処理、クエリ処理、ビュー、スキーマのユーザー拡張、情報取得などの機能もあります。汎用メカニカズムですので、これに準拠することで全てのメーカーのハードウェアやソフトウェアで統一的に使えるようになります。

WMIのアーキテクチャ

続いて、WMIのアーキテクチャについて紐解いていきます。詳細はマイクロソフトの WMI Architecture に纏まっています。

WMIはコンピュータ、ネットワーク、ローカルまたはリモートのアプリケーションやスクリプトに対して、統一インターフェースを提供するわけですが、ポイントはWMIクライアントアプリケーションとスクリプトが多数のOS-APIを呼び出す必要がないように設計された点でしょう。 WMI以外の多くのAPIは、スクリプトやVBアプリケーションなどのオートメーションクライアントから呼び出すことはできず、リモートコンピュータも呼び出しません。WMIからデータを取得するには、WMIクラスにアクセスするクライアントスクリプトまたはアプリケーションを作成するか、WMIプロバイダーを作成してWMIにデータを提供します。

  • WMIアーキテクチャ構成図の概略と各層の役割を以下に示します。

1.WMI providers and managed objects

  • WMIプロバイダー
    • 1つ以上の管理対象オブジェクトのWMIを監視するCOMオブジェクトです。
    • ドライバー同様に、プロバイダーはWMIに管理対象オブジェクトからのデータを提供し、WMIから管理対象オブジェクトへのメッセージを処理します。 DLLファイルと、プロバイダーがデータを返し、操作を実行するクラスを定義する管理対象オブジェクト形式(MOF)ファイルで構成され、WMI C++アプリケーションなどのプロバイダーは、WMI用のCOMAPIを使用します。
  • 管理対象オブジェクト
    • ハードディスクドライブ、ネットワークアダプター、データベースシステム、オペレーティングシステム、プロセス、サービスなどの論理的または物理的なエンタープライズコンポーネントです。
    • プロバイダーの例は、システムレジストリ内のデータにアクセスするプリインストールされたレジストリプロバイダーなどがあります。
      プロバイダーによって、1クラス内のメソッドとプロパティの数的関係性は絶対のルールはなくマチマチです。
  • 物理構造体の特徴
    • WMI MOFおよびDLLファイルは、Winmgmt.exeやMofcomp.exeなどのWMIコマンドラインツールとともに%WINDIR%\System32\Wbem に置かれます。Win32_LogicalDisk などのプロバイダークラスはMOFファイルで定義され、システムの起動時にWMIリポジトリにコンパイルされます。

2. WMI infrastructure

  • WMIインフラストラクチャはWMIサービス(winmgmt)として知られるWindows OSコンポーネントで、 WMIリポジトリとWMIコアの2つのコンポーネントがあります。
  • WMIリポジトリ
    • WMI名前空間によって編成されます。名前空間はWMIサービスによってシステムの起動時に作成され、Win32クラス、WMIシステムクラスなどのクラス定義の既定のセットをプレインストールします。
    • システム起動時に作成される名前空間には、root\defaultroot\cimv2root\Subscriptionなどがあります。システムにある残りの名前空間は、オペレーティングシステムまたは製品の他の部分のプロバイダーによって作成されます。
  • WMIコア
    • プロバイダー、管理アプリケーション、およびWMIリポジトリ間の仲介役として機能します。プロバイダーによって定義されたクラスなど、オブジェクトに関する静的データのみがリポジトリに保存されます。 WMIはクライアントが要求したときにプロバイダーからほとんどのデータを動的に取得します。
    • ちなみに上記は、マイクロソフトの説明原文(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」にあたる。

上記以外だと、以前はマイクロソフトのサイトで「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クラスが対象となります。

冒頭に出てきたイベントログでも、以下のようになっていましたね。

Windows-EventLog(抜粋で再掲)
Query //./root/CIMV2
Namespace SELECT TargetInstance FROM __InstanceCreationEvent WITHIN 10 WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.Name = 'lync.exe'

発生していた問題への対処

ではここまでの内容を頭に置きつつ、以降は話を戻し、不調な我が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

Status StartType Name DisplayName
------ --------- ---- -----------
Running Automatic Winmgmt Windows Management Instrumentation

続いて依存関係も併せて確認していきます。コマンドレットのオプションの意味合いが少しわかりにくいのですが、意味は以下の通りです。

  • -DependentServices:WinMgmt「に」依存しているサービス
  • -RequiredServices:WinMgmt「が」依存しているサービス
PS C:\Windows\system32> Get-Service -DependentServices Winmgmt
Status Name DisplayName
------ ---- -----------
Stopped NcaSvc Network Connectivity Assistant
Running iphlpsvc IP Helper

PS C:\Windows\system32> Get-Service -RequiredServices Winmgmt
Status Name DisplayName
------ ---- -----------
Running RPCSS Remote Procedure Call (RPC)

小技ですが、上記は横着するとこんな感じで一度に取得することも可能です。

PS C:\Windows\System32> Get-Service -Name WinMgmt | Where-Object {$_.RequiredServices -or $_.DependentServices} |
Format-Table -Property Status, Name, RequiredServices, DependentServices -auto

Status Name RequiredServices DependentServices
------ ---- ---------------- -----------------
Running WinMgmt {RPCSS} {NcaSvc, iphlpsvc}

実はこの後のWMIリポジトリ再作成時に少しだけハマった部分なのですが、当該サービス、Windowsサービスの回復設定で停止検知後(正確にはエラー検知)に自動で再度立ち上がってくる設定になっていることがわかります。

PS C:\Windows\System32> C:\Windows\System32\sc.exe qfailure Winmgmt
[SC] QueryServiceConfig2 SUCCESS

SERVICE_NAME: Winmgmt
RESET_PERIOD (in seconds) : 86400
REBOOT_MESSAGE :
COMMAND_LINE :
FAILURE_ACTIONS : RESTART -- 遅延 = 120000 ミリ秒です。
RESTART -- 遅延 = 300000 ミリ秒です。

なお、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
Stop-Service : サービス 'Windows Management Instrumentation (WinMgmt)' には依存サービスが存在するため、停止できません。このサービスを停止できるのは、Force フラグが設定されている場合のみです。
発生場所 行:1 文字:1
+ Stop-Service -Name WinMgmt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.ServiceProcess.ServiceController:ServiceController) [Stop-Service]、ServiceCommandException
+ FullyQualifiedErrorId : ServiceHasDependentServices,Microsoft.PowerShell.Commands.StopServiceCommand

PS C:\Windows\System32> Stop-Service -Force -Name WinMgmt

リポジトリ情報フォルダをリネーム

リポジトリの実体は %windir%\system32\repository 配下にあり、以下のようなファイルが格納されます。今回はこれらをリネームし、WMIサービスを改めて起動することでリポジトリを再作成(=プロバイダークラスをリコンパイル)していきます。

PS C:\windows\system32> Set-Location .\wbem\
PS C:\windows\system32\wbem> Get-ChildItem C:\Windows\system32\wbem\repository\

ディレクトリ: C:\Windows\system32\wbem\repository

Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2021/01/18 15:36 5562368 INDEX.BTR
-a---- 2021/01/18 15:36 89108 MAPPING1.MAP
-a---- 2021/01/18 15:31 88800 MAPPING2.MAP
-a---- 2021/01/18 15:31 88892 MAPPING3.MAP
-a---- 2021/01/18 15:36 26796032 OBJECTS.DATA

モタモタしていると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> Get-Service -Name WInMgmt

Status Name DisplayName
------ ---- -----------
Running WInMgmt Windows Management Instrumentation

これで解決です。この後、本来やりたかったデバイスドライバーを再適用をしてハードウェア制御が正常に戻りました(よかった)。

PS C:\windows\system32> systeminfo

ホスト名: **********
OS 名: Microsoft Windows 10 Pro
OS バージョン: 10.0.18363 N/A ビルド 18363
OS 製造元: Microsoft Corporation
OS 構成: メンバー ワークステーション
OS ビルドの種類: Multiprocessor Free
登録されている所有者: Windows ユーザー
(後略)

最後に

今回は、普段よく扱っているサーバサイドではなく自分のPC端末でのトラブルを契機に、WMIについて取り上げてみました。自分のメインPCがおかしくなるのは、ある意味 サーバトラブルとはまた一味違った焦りがあるものですね。クラウド上のサーバと違って、壊れたらすぐに替えがきかない機器ということで、少し緊張感の高い作業でした。折角の機会なので久方ぶりのWindowsのコマンド操作の復習をしつつ、WMIのアーキテクチャ面の基礎を改めて整理をしてみましたので、どこかで誰かのご参考になればと思います。

ところで、普段動いているのが当たり前の機能やサービスが、何か想定外トラブルでダウンしてしまうことってそれなりにありますよね。私のメインの守備範囲の1つはインフラですが、インフラでいうとどこかのクラウドサービスがまた別のクラウドサービスをバックボーンに動いていて、大元のサービスが障害になった時に「あ、こういう関係性で動いていたんだ…」とその時になって気付くことがあります。また、こうしたケースでは依存先のサービスが公称されていないことが大半で、その影響は事前になかなかわからないものです。

今回のPC上でのトラブル程度でもいざ起こってみると案外色々な機能に影響が出て混乱しましたが、エンタープライズ領域のシステムにおける影響は、ある端末で起きたWMIエラーのようなかわいいものではすみません。普段のシステムデザインにおける考慮事項として、こういった可能性は常に頭において考えていきたいものですね。

ではまた!

参考情報