1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WMIがぶっ壊れて沼った話

Posted at

症状

【症状】WMIコマンドでWin32_LogicalDisk が無効なクラスと言われる

背景とか途中経過とかいいから解決方法だけ教えろ!という緊急の方コチラ
お時間と精神に余裕のある方はぜひお付き合いください。

なんでこの記事を書くことになったか

とある案件でRaspberryPiPicoを使用することになったのだが、なぜかArduinoIDEでの書き込みが通らない。
IDEのコンソール出力から、ラズパイピコへプログラムを書き込む際にユーザーディレクトリ下のAppData\Local\Arduino15\packages\rp2040\hardware\rp2040\4.3.1/tools/uf2conv.pyを走らせてるっぽいとこまでは分かったのだが、uf2convの実行中に大量の赤文字エラーメッセージが羅列されて書き込みが通らない。
しかもこのエラーメッセージ、ほぼすべてが文字化けしている!(皆さんに見せたかったけどスクショ取るの忘れた orz)
ということで、ArduinoIDEが無事動くように頑張るぞと課題解決のたびに出かけたのですが最終的に何故かWindows君のシステム治療に落ち着いたのでネタとして記事にしました。

エラーが発生している処理の発見

uf2convの実行関数内に様々なデバッグメッセージを仕込んだりコメントアウトして挙動を確認したりすることで色々と格闘していくこと数時間、プログラムを書き込む前にデバイス情報を取得する関数内にてPowerSehllコマンドをサブプロセスでコールするコードを見つけた。ArduinoIDEコンソールでのエラー出力には必ずUnable to build drive listを含んでいたのでこのtryが失敗していると見て間違いなさそうだ。

uf2conv.py 252行目
except:
    try:
        nul = open("nul:", "r")
        r = subprocess.check_output(["powershell", "-NonInteractive", "-Command",
                                    "Get-WmiObject -class Win32_LogicalDisk | "
                                    "Format-Table -Property DeviceID, DriveType, Filesystem, VolumeName"],
                                    stdin = nul)
        nul.close()
    except:
        print("Unable to build drive list");
        sys.exit(1)

このサブプロセスでコールされている問題のコマンドは以下の通り

問題のコマンド
powershell -NonInteractive -Command Get-WmiObject -class Win32_LogicalDisk | Format-Table -Property DeviceID, DriveType,Filesystem, VolumeName

ArduinoIDEで書き込みが行われる際に、接続されている物理ディスク(ここではターゲットマイコンのこと)を取得して対象ディスクをフォーマットするらしい。
このあとに対象ディスクへビルドしたバイナリデータをアップロードする処理も書かれていたので、RaspberryPiPicoのArduinoIDEでの書き込みでは毎回コントローラのフラッシュをフォーマットする仕様になっているようで間違えなさそうだ。

さて、問題のコマンドについてpowershell -NonInteractive -CommandはPowerShellコマンドをコールするときにCLIを開かず実行する指示なのでこれは素通りして、本命のコマンドはディスク情報取得のコマンドとフォーマットのコマンドだ。

ディスク情報取得
Get-WmiObject -class Win32_LogicalDisk
フォーマットのコマンド
Format-Table -Property DeviceID, DriveType,Filesystem, VolumeName

ArduinoIDEの処理出力画面は前述の通り綺麗に文字化けしていてまったく役に立たないのでPowerSehllを管理者権限で開いてこれらのコマンドを試していこうと思ったところで

言っていることは分かるが理解したくないメッセージ
> Get-WmiObject -class Win32_LogicalDisk
Get-WmiObject : 無効なクラスです "Win32_LogicalDisk"
発生場所 :1 文字:1
+ Get-WmiObject -class Win32_LogicalDis
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidType: (:) [Get-WmiObject], ManagementException
    + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

やってまいりました!
Windows君お得意の何もしていないのに壊れている現象が出てきました!

a

Win32_LogicalDiskが無効なクラス?!

さて発見されたエラーメッセージGet-WmiObject : 無効なクラスです "Win32_LogicalDisk"でのWin32_LogicalDiskクラスについてですが、WMIプロパイダ内でのローカルストレージデバイスに関するデータソースをコールするクラスです。WMIについてとLogicalDiskクラスについては下記ページで詳しく解説されています。

WMIの破損

Win32_LogicalDiskのクラスだけピンポイントにパスが壊れたとかそんなことあるか?
と思ったのもつかの間、WMIがWindowsのシステム監視・管理用のインフラだったことを思い出し猛烈に嫌な予感がした僕はそのままPowerShellにsysteminfoをぶち込みました。

結果

WMIぶっ壊れが確定した瞬間
> systeminfo
オペレーティング システム情報を読み込んでいます...                    エラー: 無効なクラスです

はい、確定しました。
WMIがぶっ壊れてます。

WMIの復旧

そもそもWMI自体がWindowsの挙動を監視するためのシステムでWindowsの重要インフラになっているはずなのにサイレントにぶっ壊れてるなんてことあるもんですね(白目)。
日本マイクロソフトのサポートチームによる技術ブログとかいう有能すぎる記事があったのでこちらを早速試してみます。

どうやらPowerSehllで実行できるWMIレポジトリの破損状況確認とその修復を行えるコマンドが存在しているらしくこれを試してみろとのことでした。
この手法はWMIが破損したときに行われる常套手法らしいです。
復旧コマンドの実行でデータベースに矛盾がないって嬉しい出力が返ってきました!

レポジトリの復旧コマンド実行
 > winmgmt /salvagerepository
 WMI データベースに矛盾はありません

みんなこれで治ってるそうだし、これで僕のPCも治るはず!

image.png

・・・まぁ、お約束ですね。人生そんなに楽じゃないわ。

WMIのレポジトリの手動削除

さて、王道のやり方は失敗したので下記の記事を参考に少々強硬手段で行きます。
WMIは以下のディレクトリ下にあるマップファイル等を参照して様々なクラス等をコールしてるみたいです。
\Windows\system32\wbem\repository
このディレクトリのことをWMIレポジトリと呼んでるみたいで、さっきの修復コマンドはこのディレクトリの修復を行うコマンドだったみたいです。
下記の記事ではWMIサービスを強制的に停止させ、再開する前にrepositoryディレクトリを削除。WMIサービスが立ち上がると再びrepositoryディレクトリが自動修復されるのでWMIレポジトリの修復が完了するという手筈みたいです。

記事通りに手順を踏んでやったけど...ダメ!

image.png

Autorecover MOFs の発見

ここまで挫折続きでしたが収穫もありました。
前章での作業中にレジストリエディタをいじる工程があったので、同ディレクトリ下のレジストリを片っ端から覗いていたのですが、ふとこんな名前のレジストリを発見...
名前はAutorecover MOFs、さっき自動復旧で失敗したので見逃せない名前です。

image.png

レジストリのキーを読んでみると大量のMOF、MFLファイルのパスが登録されていました。
MFLファイルはシステム設定ファイルで、MOFファイルはCIMクラスが記述されているクラスフォーマットファイルらしいです。

...ん?クラス?
そもそも今回の出発点は、あるはずのクラスが無効だと言われたところからスタートしてるのでは?

ということでMicrosoftのラーニングページにてMOFファイルについてお勉強しました。

上の記事によると

Managed Object Format (MOF) は、Common Information Model (CIM) クラスを記述するために使用される言語です。
WMI プロバイダーで新しい WMI クラスを実装するには、Mofcomp.exe を使用して "WMI リポジトリ" にコンパイルされる MOF ファイルをお勧めします。 WMI 用 COM API を使用して CIM クラスとインスタンスを作成および操作することもできます。

これはもしかしてWMIサービスが立ち上がるときやWMI復旧コマンドを打ったときにAutorecover MOFsに登録されたMOFファイル群がWMIリポジトリにコンパイルされることでWMIリポジトリが構築されているのでは?

ということでsystem32下のwbem内にあるMOFファイルからWin32_LogicalDiskクラスが定義されているMOFファイルを探す旅に出ました。
頑張って探すこと11ファイル目、cimwin32.mofの3385行目に

cimwin32.mof 3385行目
class Win32_LogicalDisk : CIM_LogicalDisk
{
  [Read : ToSubclass,Key : ToInstance ToSubclass DisableOverride,Override("DeviceId") : ToSubclass,MappingStrings{"WMI"} : ToSubclass] string DeviceID;
  [read : ToSubclass,MappingStrings{"Win32API|File System Functions|GetVolumeInformation|FS_VOL_IS_COMPRESSED"} : ToSubclass] boolean Compressed;
  [read : ToSubclass,MappingStrings{"Win32API|FileFunctions|GetDriveType"} : ToSubclass] uint32 DriveType;
  [read : ToSubclass,MappingStrings{"Win32API|File System Functions|GetVolumeInformation"} : ToSubclass] string FileSystem;
  [read : ToSubclass,MappingStrings{"Win32API|File System Functions|GetVolumeInformation"} : ToSubclass] uint32 MaximumComponentLength;
  [read : ToSubclass,MappingStrings{"Win32API|Windows Networking Functions|WNetGetConnection"} : ToSubclass] string ProviderName;
  [read : ToSubclass,MappingStrings{"Win32API|File System Functions|GetVolumeInformation|FS_FILE_COMPRESSION"} : ToSubclass] boolean SupportsFileBasedCompression;
  [read : ToSubclass,write : ToSubclass,MappingStrings{"Win32API|File System Functions|GetVolumeInformation"} : ToSubclass] string VolumeName;
  [read : ToSubclass,MappingStrings{"Win32API|File System Functions|GetVolumeInformation"} : ToSubclass] string VolumeSerialNumber;
  [read : ToSubclass,MappingStrings{"Win32API|Device Input and Output Functions|DeviceIoControl"} : ToSubclass] uint32 MediaType;
  [read : ToSubclass] boolean SupportsDiskQuotas;
  [read : ToSubclass] boolean QuotasDisabled;
  [read : ToSubclass] boolean QuotasIncomplete;
  [read : ToSubclass] boolean QuotasRebuilding;
  [Implemented,MappingStrings{"Fmifs.dll | Method ChkDskExRoutine"} : ToSubclass] uint32 Chkdsk([in] boolean FixErrors = FALSE,[in] boolean VigorousIndexCheck = TRUE,[in] boolean SkipFolderCycle = TRUE,[in] boolean ForceDismount = FALSE,[in] boolean RecoverBadSectors = FALSE,[in] boolean OkToRunAtBootUp = FALSE);
  [Read : ToSubclass,MappingStrings{"FSCTL_IS_VOLUME_DIRTY"} : ToSubclass] boolean VolumeDirty;
  [Static,Implemented,MappingStrings{"Chkntfs.exe"} : ToSubclass] uint32 ScheduleAutoChk([in] string LogicalDisk[]);
  [Static,Implemented,MappingStrings{"Chkntfs.exe"} : ToSubclass] uint32 ExcludeFromAutochk([in] string LogicalDisk[]);
};

image.png

しかもAutorecover MOFscimwin32.mofが登録されていないので修復時にコンパイルされてないっぽい!

ということで、Microsoftによると、Mofcomp.exeを実行するとWMIレポジトリにWMIクラスとしてMOFがコンパイルされるそうなので、WMIサービスを停止した後にコマンドプロンプトを管理者権限で立ち上げて以下を実行。

mofcomp実行
Mofcomp C:\windows\system32\wbem\cimwin32.mof

再度WMIサービスを立ち上げると

image.png

image.png

Get-WmiObject -class Win32_LogicalDisも無事動作して完全勝利です!
後処理としてAutorecover MOFscimwin32.mofを登録したのちにPCを再起動して無事動作を確認しました。

対処方法まとめ

ということで対処方法のまとめです。

【症状】Win32_LogicalDisk が無効なクラスと言われる

【解決方法】

  1. WMIサービスを停止する
    1. サービスからWindows Management Instrumentationを停止
  2. 管理者権限でコマンドプロンプトを立ち上げて以下を入力
    1. Mofcomp C:\windows\system32\wbem\cimwin32.mof
  3. WMIサービスを再開する
  4. 【要注意:下の注意事項を読んでから実行するか決めてください】
    レジストリエディタで以下の作業を行う
    1. コンピューター\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wbem\CIMOMへ移動する
    2. Autorecover MOFsを右クリックして修正を選択
    3. 値のデータにC:\windows\system32\wbem\cimwin32.mofを追加
  5. 念押しの再起動

【注意事項】

  • WMIサービスはいろんな処理が依存しているので手順をさっさと進めないと他のプロセスがサービスの立ち上げにかかります。サービスを止めてからは時間勝負なので頑張りましょう。
  • レジストリエディタでの作業は結構危険を伴います。また、Autorecover MOFsレジストリの修正については未だ検証できていない部分が多く、値を追加することでの影響が未知数です。以上を踏まえて実行するか考えてください。

おわりに

ところで皆さんなぜこの苦行に挑戦することになったのかを忘れていないだろうか。
その理由は業務で使用するラズパイピコのArduinoIDEでの書き込みができなかったからである。
そう!断じてWMIプロパティでコンピュータの構成情報が見たかったのではなく業務で開発中のマイコンへの書き込み環境が壊れたからこの苦行に飛び込んだのだ!

そして、この苦行に費やした時間は早8時間...

この苦行は終わりではなく仕事の前哨戦として消化され、まさにこれから地獄の門が開くのであった。

納期がガガガ...

(おわり)

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?