更新履歴(5件・最終更新 2026年09月07日)
この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。
- WMI/CIMの解説を、用途の判断、仕組み、PowerShellでの試作、リモート接続、C#への組み込み、イベント監視、障害切り分けの順に整理した。元の主張・条件、コード例、比較表、出典、FAQと知識マップを保持し、接続方式と前提条件、照会と購読、型と日付の扱いを近接させた。図番号と章参照を更新した。
- 知識マップの関係を総点検し、説明文と食い違っていた関係(向きの逆転・過剰な一般化・述語の取り違え)を修正しました。本文の説明は変えていません。
- 知識マップの関係を総点検し、説明文と食い違っていた関係(向きの逆転・過剰な一般化・述語の取り違え)を修正しました。本文の説明は変えていません。
- 知識マップの「イベント購読はポーリングに推奨される」という関係を、「イベント購読はポーリングを置き換える」に改めました。本文の説明は変えていません。
- 仕組みの説明を図で追えるよう、Mermaid図を19点追加しました。業務アプリの定番要求とWMI/CIMの対応、CIM標準とWMI実装の関係、WQL照会が名前空間からプロバイダーへたどる構造、CimInstanceのメソッド呼び出し、新規スクリプトをCIMコマンドレットで書く理由、リモート接続方式の選び方とWinRMの前提構成、PowerShellでの試作からC#への書き写し、プロパティのキャストの落とし穴、エージェントなしディスク監視の土台、プロセス起動イベント購読の流れと2つの購読方式の対比、常駐監視の購読再登録、照会の絞り込みによる性能対策、一般ユーザー環境での監視構成、64bit環境でのプロバイダー選択、リポジトリ不整合時の切り分け手順、DMTF日付形式の扱い、手段の判断の軸を図にしています。本文の文章とコード、参考リンクは変えていません。
- 初版公開
この記事を引用する(DOI: 10.5281/zenodo.22054225)
この記事はZenodoにアーカイブされています。常に最新版へ解決されるDOIと、いま表示している版に固定されたDOIの両方を下に示します。
小村 豪(2026)「WMI/CIMをC#・PowerShellから使う ── ハードウェア情報取得・プロセス監視・リモート照会の実務ガイド」合同会社小村ソフト. https://doi.org/10.5281/zenodo.22054225 https://comcomponent.com/blog/wmi-cim-practical-guide/
- DOI(最新版)
- 10.5281/zenodo.22054225
- DOI(この版)
- 10.5281/zenodo.22639733
「PCのシリアル番号と機種名を表示したい」「サーバーのディスク空きを調べたい」「プロセスの起動を検知したい」。Windowsの業務アプリや管理ツールで、こうした情報を共通の方法で扱えるのが WMI/CIM です。
CIMは管理情報を表す標準モデル、WMIはその標準を使うWindowsの管理基盤です。PowerShellのCIMコマンドレットとC#のAPIは、この基盤へアクセスする入口になります。1
flowchart TB
accTitle: 定番要求とWMI/CIM
accDescr: シリアル番号と機種名の表示、ディスク空き容量の監視、プロセス起動の検知、リモートPCの照会という業務アプリ定番の要求への定番の答えがWMIであり、管理情報の表現にはCIM標準を使う
r1["シリアル番号・機種名"] --> ans["WMI(CIM標準を使う基盤)"]
r2["ディスク空き容量の監視"] --> ans
r3["プロセス起動の検知"] --> ans
r4["リモートPCの照会"] --> ans
図1: 業務アプリ定番の4つの要求に対する定番の答えがWMI/CIM。
迷いやすいのは、入口が複数あることです。検索結果には旧Get-WmiObjectとGet-CimInstanceが混在し、C#にもSystem.ManagementとMicrosoft.Management.Infrastructureがあります。旧WMIコマンドレットはWindows PowerShell 5.1では使えても、PowerShell 7にはありません。2
この記事は、ハードウェア情報取得・プロセス監視・リモートPC照会を実装するC#/PowerShell開発者向けです。まずWMIを選ぶべきかを判断し、PowerShellで試し、接続条件を確認してC#へ組み込み、監視と障害対応まで整える順に説明します。2026年8月時点の一次情報を土台に、実例と注意点を整理しています。
1. まず結論:用途と接続先から入口を選ぶ
新しく書くPowerShellはCIMコマンドレットを使い、C#は用途に応じてAPIを選びます。ただし、専用の仕組みで済む処理までWMIへ寄せる必要はありません。
| 判断・作業 | 基本方針 | 説明する章 |
|---|---|---|
| WMIを使うべきか決める | 横断的な情報取得・リモート照会に使い、設定や高頻度の性能監視は専用の仕組みを選ぶ | 2章 |
| 何を照会するか決める | 名前空間、クラス、プロパティを選び、WQLで対象を絞る。日常の既定はroot/CIMV23 |
3章・4章 |
| PowerShellで試す | Get-CimInstanceで読み、Invoke-CimMethodで操作する。5.1向けの新規コードもCIM側で書く2 |
4章 |
| リモートへ広げる | WSMan/WinRMを基本にし、同じ相手への複数操作はCIMセッションを使い回す。必要ならDCOMを選ぶ34 | 5章 |
| C#へ組み込む | ローカルの手軽な照会はSystem.Management、リモートや監視の組み込みはMI APIを検討する56 |
6章 |
| プロセス起動を監視する | イベント購読を使い、権限、購読の解除、切断後の再登録も設計する78 | 7章 |
| 遅い・値が違う・クラスが見つからない原因を調べる | 照会の量と頻度、プロバイダーのビット数、リポジトリの整合性を切り分ける | 8章 |
特に、一覧を取得できることと、イベントを購読できることは別です。Win32_ProcessStartTraceの購読例は管理者権限で実行します。7 また、SELECT *や短周期ポーリングを惰性で使わず、-Filter・-Property・-KeyOnlyで必要な情報に絞ります。3
図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全26件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle
2. WMI/CIMを使う場面・専用の仕組みを選ぶ場面
WMIは「統一された読み取り口」としては優秀ですが、常に最適解ではありません。実務での使い分けの目安です。
| やりたいこと | 適した手段 | WMIを選ばない理由 |
|---|---|---|
| ハードウェア情報・OS構成の取得、エージェントなしのリモート照会 | WMI/CIM | ここがWMIの本領。専用APIを個別に叩くより統一的 |
| 自アプリの設定の読み書き | レジストリ直読(Microsoft.Win32.Registry)・構成ファイル |
WMI経由のレジストリ操作は遠回りで、8.2節のビット数問題も背負い込む |
| CPU使用率などの高頻度・連続的な性能監視 | パフォーマンスカウンター(System.Diagnostics.PerformanceCounter 等) |
counterはそのための仕組み。WMIの短周期ポーリングは負荷と精度で不利 |
| 単発のOS機能呼び出し・低レイテンシーが必要な処理 | Win32 API(P/Invoke) | WMIはCOM/プロバイダーを経由する分のオーバーヘッドがある |
| 自プロセス権限で足りるローカルのプロセス列挙・操作 | System.Diagnostics.Process |
標準ライブラリで完結し、依存が減る |
| ファイアウォール・ネットワーク等のWindows管理機能の構成 | Get-NetFirewallRule などの専用CIMベースコマンドレット |
生のWMIクラスを探すより、用途別に整備されたコマンドレット群が正確で安全 |
| ファイル・フォルダーの変更検知 | FileSystemWatcher |
専用APIがある領域にWMIを持ち込まない |
判断の軸は単純で、「専用の仕組みがある領域では専用の仕組みを使い、横断的な照会・リモート照会にWMI/CIMを使う」です。表の Get-NetFirewallRule などは内部的にはCIMの上に構築されたコマンドレット群であり、「WMI/CIMを直接触らずに、その恩恵だけ受ける」形と言えます。
flowchart TB
accTitle: 手段の判断の軸
accDescr: 専用の仕組みがある領域では専用の仕組みを使い、ない領域の横断的な照会やリモート照会にWMIとCIMを使うのが判断の軸で、専用CIMベースコマンドレットはWMIとCIMを直接触らずに恩恵だけ受ける形である
q1{"専用の仕組みがある?"} -->|ある| ded["専用の仕組みを使う"]
q1 -->|ない| wmi["WMI / CIMを使う"]
wmi -.-> use["横断的な照会・リモート照会"]
cmd["専用CIMベースコマンドレット"] -.-> ben["恩恵だけ受ける形"]
図2: 専用の仕組みがある領域では専用を使い、横断的な照会とリモート照会にWMI/CIMを使う。
3. 仕組みを押さえる:標準、名前空間、クラス、WQL
3.1. CIMは標準、WMIはWindows上の実装
まず用語の関係を1回で整理します。
| 用語 | 正体 |
|---|---|
| CIM (Common Information Model) | システム・アプリ・ネットワーク・デバイスなどの管理対象を表現する業界標準モデル。DMTF(Distributed Management Task Force)が策定・維持1 |
| WBEM (Web-Based Enterprise Management) | 企業環境の管理情報へアクセスする標準技術を作る業界イニシアティブ1 |
| WMI | WBEMのMicrosoft実装。CIM標準を使って管理対象を表現し、Windowsに組み込まれている1 |
| MI (Windows Management Infrastructure) | WMIの次世代版。従来のWMIと完全互換で、新しいプロバイダーの多くはMIで書かれている1 |
flowchart TB
accTitle: CIM標準とWMI実装の関係
accDescr: DMTFが策定・維持するCIM標準をWBEMイニシアティブの枠組みで使い、そのMicrosoft実装がWMIで、次世代版のMIは従来のWMIと完全互換であり、CIM系APIの接続先は同じWMI基盤である
dmtf["DMTFが策定・維持"] --> cim["CIM(業界標準モデル)"]
wbem["WBEM(業界イニシアティブ)"] --> wmi["WMI(Microsoft実装)"]
cim --> wmi
wmi -.-> mi["MI(次世代版・完全互換)"]
api["CIM系API(PowerShell / C#)"] --> wmi
図3: CIMが仕様、WMIがWindows上の実装。CIM系APIの接続先は同じWMI基盤。
3.2. 名前空間・クラス・プロバイダー・WQLをつなげて読む
開発者として押さえるべき構造は次の4つです。
- 名前空間(namespace): クラスを束ねる階層です。日常の照会で使うのはほぼ root/CIMV2 で、CIMコマンドレットの既定もここです。3 ほかに
root\default(レジストリプロバイダーなど)等があります。 - クラス:
Win32_ComputerSystem(コンピューター本体)、Win32_LogicalDisk(論理ドライブ)、Win32_Process(プロセス)のような管理対象の型です。CIM標準のクラス(CIM_LogicalDiskなど)を継承したWindows固有クラスがWin32_の接頭辞を持ちます。9 - プロバイダー: クラスの実体を提供するコンポーネントです。照会するとプロバイダーがその場でOSに問い合わせて値を作ります。
- WQL: SQLに似た照会言語です。
SELECT Name, State FROM Win32_Service WHERE StartMode = 'Auto'のように、クラスをテーブルに見立てて絞り込みます。CIMコマンドレットの既定の照会言語もWQLです。3
「OSやハードウェアの情報を、統一されたクラスとクエリ言語で読める」── これがWMIの価値です。ただし、すべてのクラスで書き込みや操作ができるわけではありません。メソッドのあるクラスはInvoke-CimMethodで操作し、書き込み可能なプロパティの変更はSet-CimInstanceで行います。4.1節の対応表のとおり、クラスが提供する機能に合わせて入口を選びます。
flowchart TB
accTitle: WMI照会の構造
accDescr: WQLの照会は名前空間root/CIMV2の中のWin32_*クラスに向けられ、クラスの実体を提供するプロバイダーがその場でOSに問い合わせて値を作り、結果が返る
wql["WQLで照会"] --> ns["名前空間 root/CIMV2"]
ns --> cls["Win32_*クラス"]
cls --> prov["プロバイダー"]
prov --> osq["その場でOSに問い合わせ"]
osq --> res["結果を返す"]
図4: 照会は名前空間、クラス、プロバイダーの順にたどり、値はその場で作られる。
4. PowerShellで試す:読み取り・メソッド呼び出し・資産情報
ここからはWindows上のPowerShellで試します。旧コードから移す場合も、最初にコマンドレットの対応と、戻り値の扱いの違いを確認してください。
4.1. 新規コードはCIMコマンドレットで書く
PowerShell 6以降(現行のPowerShell 7)では、次のWMI v1コマンドレットが削除されています。同じ機能はCimCmdletsモジュール(WMI v2)が提供します。2
| 旧(Windows PowerShell 5.1まで) | 現行(CIMコマンドレット) | 補足 |
|---|---|---|
Get-WmiObject |
Get-CimInstance |
-Filter / -Query の考え方は同じ |
Get-WmiObject -List |
Get-CimClass |
クラスの探索・定義の確認 |
Invoke-WmiMethod |
Invoke-CimMethod |
引数は -Arguments @{ } のハッシュテーブルで渡す |
Register-WmiEvent |
Register-CimIndicationEvent |
イベント購読(7章) |
Set-WmiInstance |
Set-CimInstance |
書き込み可能プロパティの変更 |
Remove-WmiObject |
Remove-CimInstance |
インスタンスの削除 |
Windows PowerShell 5.1でもCIMコマンドレットは使えるので、新しく書くものは5.1で動かす場合でもCIM側で書くのが移行コストを残さない書き方です。5.1と7の共存・移行の全体像は「Windows PowerShell 5.1とPowerShell 7の違い」にまとめています。
flowchart TB
accTitle: 新規スクリプトをCIMで書く理由
accDescr: WMIコマンドレットで書いたスクリプトは5.1では動くもののPowerShell 6以降で削除済みのため移行時に書き直しが必要になり、CIMコマンドレットは5.1でも使えるため新しく書くものはCIM側で書けば移行コストが残らない
new["新しく書くスクリプト"] --> q1{"どちらで書く?"}
q1 -->|WMIコマンドレット| old["5.1では動く"]
q1 -->|CIMコマンドレット| cur["5.1でも使える"]
old --> del["PowerShell 7で削除済み"]
del --> rew["移行時に書き直し"]
cur --> norew["移行コストが残らない"]
図5: 新規はCIMコマンドレットで書いておけば、PowerShell 7への移行時に書き直しが要らない。
4.2. Get-CimInstanceで行と列を絞って読む
# クラス指定(既定の名前空間 root/CIMV2)
Get-CimInstance -ClassName Win32_OperatingSystem
# WHERE句だけを -Filter に書く(WHEREキーワードは書かない)
Get-CimInstance -ClassName Win32_Service -Filter "StartMode = 'Auto' AND State <> 'Running'"
# 必要なプロパティだけ取得して転送量を減らす
Get-CimInstance -ClassName Win32_Process -Property Name, ProcessId, CreationDate
# WQLをそのまま書くなら -Query
Get-CimInstance -Query "SELECT * FROM Win32_Process WHERE Name LIKE 'p%'"
-Filter はWQLのWHERE句そのもの、-Property は取得列の限定です。3 戻り値は CimInstance オブジェクトで、日付プロパティ(CreationDate や LastBootUpTime など)は DateTime に変換済みで返ります。
4.3. メソッドはInvoke-CimMethodで呼ぶ
旧 Get-WmiObject と違い、取得したオブジェクトからWMIのメソッドを直接呼ぶ形ではないため、メソッド呼び出しは Invoke-CimMethod に渡します。
flowchart TB
accTitle: CimInstanceのメソッド呼び出し
accDescr: Get-CimInstanceが返すCimInstanceは日付プロパティがDateTime変換済みで返る一方でWMIメソッドを直接呼び出す形ではないため、メソッド呼び出しはインスタンスをInvoke-CimMethodに渡して行う
gci["Get-CimInstance"] --> inst["CimInstanceオブジェクト"]
inst -.-> dt["日付はDateTime変換済み"]
inst -.-> nom["WMIメソッドは別の入口へ"]
inst --> icm["Invoke-CimMethodに渡す"]
icm --> call["メソッド呼び出し"]
図6: CimInstanceのWMIメソッドは直接呼び出さず、メソッド呼び出しはInvoke-CimMethodに渡して行う。
# インスタンスのメソッドを呼ぶ: 各プロセスの所有者を取得
Get-CimInstance -ClassName Win32_Process -Filter "Name = 'notepad.exe'" |
Invoke-CimMethod -MethodName GetOwner
# クラスの静的メソッドを呼ぶ: プロセスを起動
Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{ CommandLine = 'notepad.exe' }
# クラス定義(プロパティ・メソッド一覧)を調べる
Get-CimClass -ClassName Win32_Process
4.4. 取得したい情報からクラスを選ぶ
| 取りたい情報 | クラス | 主なプロパティ |
|---|---|---|
| メーカー・機種名 | Win32_ComputerSystem |
Manufacturer, Model |
| 本体シリアル番号 | Win32_BIOS |
SerialNumber |
| OSの版・起動時刻 | Win32_OperatingSystem |
Caption, Version, LastBootUpTime |
| ディスク空き容量 | Win32_LogicalDisk |
DeviceID, FreeSpace, Size, DriveType9 |
| サービス状態 | Win32_Service |
Name, State, StartMode |
| プロセス一覧 | Win32_Process |
Name, ProcessId, CommandLine |
4.5. 資産管理の例:機種・シリアル番号・ディスク空き
# 機種情報とシリアル番号(PC資産台帳の突合せに)
$cs = Get-CimInstance -ClassName Win32_ComputerSystem -Property Manufacturer, Model
$bios = Get-CimInstance -ClassName Win32_BIOS -Property SerialNumber
[pscustomobject]@{
Manufacturer = $cs.Manufacturer
Model = $cs.Model
Serial = $bios.SerialNumber
}
# ローカルディスク(DriveType = 3)の空き容量
Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType = 3" |
Select-Object DeviceID,
@{ Name = 'FreeGB'; Expression = { [math]::Round($_.FreeSpace / 1GB, 1) } },
@{ Name = 'SizeGB'; Expression = { [math]::Round($_.Size / 1GB, 1) } }
DriveType = 3 は「ローカルディスク」を表す値で、リムーバブル(2)やネットワークドライブ(4)、CD(5)を除外します。9 5章の接続条件を満たしたうえで、このスクリプトをCIMセッション経由で各サーバーに回すと、エージェントなしのディスク監視の土台ができます。
flowchart TB
accTitle: エージェントなしディスク監視の土台
accDescr: DriveType 3の絞り込みでリムーバブルやネットワークドライブやCDを除外してローカルディスクだけを対象にし、同じスクリプトをCIMセッション経由で各サーバーに回すことで、エージェントなしのディスク監視の土台ができる
scr["空き容量取得スクリプト"] --> flt["DriveType = 3で絞る"]
flt -.-> exc["リムーバブル等を除外"]
scr --> ses["CIMセッション経由"]
ses --> srvs["各サーバーに回す"]
srvs --> mon["エージェントなし監視"]
図7: ローカルディスクに絞ったスクリプトをCIMセッションで各サーバーに回すのが監視の土台。
5. リモートへ広げる:接続方式と前提条件
5.1. ローカルとリモートで接続方式が変わる
-CimSessionを渡さないCIMコマンドレットは、-ComputerNameも指定しなければローカルのWMIにCOMで接続し、-ComputerName を指定するとWSMan(WinRM)プロトコルで一時セッションを作って接続します。同じコンピューターに複数の操作を行う場合は、CIMセッションを作って使い回す方が性能上有利です。3
flowchart TB
accTitle: CIM接続方式の選択
accDescr: CimSessionを渡さない場合、ComputerName指定なしはローカルWMIへCOM接続、ComputerName指定はWSManの一時セッションが照会のたびに作られ、同じ相手への複数操作はNew-CimSessionの使い回しが性能上有利で、WinRM未構成の相手にはDCOMプロトコルオプションがある
exec["CimSessionを渡さず実行"] --> q1{"ComputerName指定?"}
q1 -->|なし| local["ローカルWMIへCOM接続"]
q1 -->|あり| q2{"同じ相手に複数操作?"}
q2 -->|単発| temp["WSManの一時セッション"]
q2 -->|複数| sess["New-CimSessionを使い回す"]
temp -.-> cost["照会のたびに作成される"]
nowinrm["WinRM未構成の相手"] -.-> dcom["DCOMプロトコルオプション"]
図8: リモート照会はWSManが既定で、同じ相手への複数操作はCIMセッションの使い回しが定石。
5.2. WinRM・ファイアウォール・認証・権限を準備する
WSMan/WinRMで照会する場合の前提は次のとおりです。接続処理を書く前に、サービス・通信経路・認証・権限を分けて確認します。
- 接続先でWinRMが構成されていること。
winrm quickconfigが、サービスの自動起動化・HTTPリスナー(既定ポート5985)の作成・ファイアウォール例外の登録を一括で行います。10 HTTPS(既定ポート5986)で接続したい場合はこれだけでは足りず、サーバー証明書を用意したうえでwinrm quickconfig -transport:httpsなどでHTTPSリスナーを別途構成する必要があります。10 - 経路のファイアウォールで該当ポートが開いていること。受信規則の設計と登録の実務は「Windowsファイアウォールと業務アプリ」の記事で扱ったとおりです。
- 認証。ドメイン環境ならKerberosで相互認証されます。ワークグループではKerberosが使えないため、クライアント側の
TrustedHostsへの登録が必要になる場合があります。登録先は必要最小限に絞ります。10 - 権限。既定の構成では、リモートのWMI照会・操作は接続先の管理者グループに属するアカウントで行うのが基本です。一般ユーザーに開放する場合は、WinRMとWMI名前空間の両方でアクセス許可の構成が必要になります。10
flowchart TB
accTitle: リモート照会の前提の確認
accDescr: 接続先ではwinrm quickconfigがサービスの自動起動化とHTTPリスナー作成とファイアウォール例外登録を一括で行い、HTTPSリスナーは証明書を用意して別途構成し、ワークグループ環境ではTrustedHostsへの登録が必要になる場合がある
qc["winrm quickconfig"] --> svc["サービスの自動起動化"]
qc --> lis["HTTPリスナー作成(5985)"]
qc --> fw["ファイアウォール例外"]
lis ~~~ https["HTTPSリスナー(5986)"]
https -.-> cert["証明書を用意し別途構成"]
fw ~~~ wg["ワークグループ環境"]
wg -.-> th["必要な場合に限定して登録"]
図9: winrm quickconfigは既定構成を一括で行い、HTTPSリスナーとワークグループの認証は別途対応する。
5.3. 同じ相手への複数操作はCIMセッションを使い回す
# 単発なら -ComputerName(1回ごとに一時セッションが作られる)
Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName Server01, Server02
# 繰り返し照会するならCIMセッションを使い回す
$session = New-CimSession -ComputerName Server01
Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $session
Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType = 3" -CimSession $session
Remove-CimSession $session
5.4. WinRMを構成できない相手にはDCOMを検討する
WinRMを構成できない古いマシンなど、WSManで接続できない相手にはDCOMプロトコルを選べます。4
$dcom = New-CimSessionOption -Protocol Dcom
$session = New-CimSession -ComputerName OldServer -SessionOption $dcom
DCOMはRPCの動的ポートも使うため、ファイアウォールをまたぐ設計が難しくなります。これから作る仕組みはWSManを既定と考えるのが無難です。
セッション例は接続方法を示したものです。組み込み時には、途中で照会に失敗してもRemove-CimSessionへ到達するよう、try / finallyなどで後始末を保証してください。DCOMの例で作ったセッションも同様に解除します。
6. C#へ組み込む:二つのAPIと型・日付の扱い
6.1. 二つのAPIを用途で選ぶ
C#からWMIを使うAPIは2系統あります。どちらもWindows専用です。
| System.Management | Microsoft.Management.Infrastructure (MI API) | |
|---|---|---|
| 導入 | .NET Frameworkは標準。現行の.NETではNuGetパッケージ System.Management5 | NuGetパッケージ Microsoft.Management.Infrastructure6 |
| 入口クラス | ManagementObjectSearcher(WQLを渡して照会)5 |
CimSession(Create → QueryInstances / InvokeMethod / Subscribe)6 |
| 型体系 | ManagementObject / ManagementEventWatcher11 |
CimInstance / CimSession ── CIMコマンドレットと同じ型3 |
| リモート | DCOMベース | WSMan(CIMセッション)ベース。非同期版(*Async)あり6 |
| 向いている場面 | ローカルの情報取得。既存コード資産の維持 | リモート照会・監視の組み込み。PowerShell併用の設計 |
6.2. System.Management:WQLを渡し、CIM型に合わせて読む
WQLを文字列で渡し、Get() で結果コレクションを受け取ります。5
// NuGet: System.Management(Windows専用)
using System.Management;
using var searcher = new ManagementObjectSearcher(
@"root\cimv2",
"SELECT DeviceID, FreeSpace, Size FROM Win32_LogicalDisk WHERE DriveType = 3");
foreach (ManagementObject disk in searcher.Get())
{
var freeGb = (ulong)disk["FreeSpace"] / 1024.0 / 1024.0 / 1024.0;
var sizeGb = (ulong)disk["Size"] / 1024.0 / 1024.0 / 1024.0;
Console.WriteLine($"{disk["DeviceID"]} 空き {freeGb:F1} GB / 全体 {sizeGb:F1} GB");
}
プロパティはインデクサーで object として返るため、クラスのドキュメントでCIM型(この例では FreeSpace / Size は uint649)を確認してキャストします。型を確認せず int と思い込んでキャストすると InvalidCastException になる、というのが最初の定番のつまずきです。
flowchart TB
accTitle: プロパティ取得とキャストの落とし穴
accDescr: System.Managementのプロパティはインデクサーでobjectとして返るため、クラスのドキュメントでCIM型を確認してキャストする必要があり、intと思い込んでキャストするとInvalidCastExceptionになる
idx["インデクサーで取得"] --> obj["objectとして返る"]
obj --> chk["ドキュメントでCIM型確認"]
chk --> cast["正しい型へキャスト"]
obj -.-> wrong["intと思い込みキャスト"]
wrong -.-> ex["InvalidCastException"]
図10: プロパティはobjectで返るため、CIM型を確認してからキャストする。
6.3. MI API:PowerShellと同じ型で照会する
CimSession はローカル・リモートを同じ形で扱えます。列挙・照会・メソッド呼び出し・イベント購読と非同期版まで一通り揃っています。6
// NuGet: Microsoft.Management.Infrastructure(Windows専用)
using Microsoft.Management.Infrastructure;
// ローカルなら CimSession.Create(null)、リモートならコンピューター名を渡す
using CimSession session = CimSession.Create(null);
IEnumerable<CimInstance> disks = session.QueryInstances(
@"root\cimv2", "WQL",
"SELECT DeviceID, FreeSpace, Size FROM Win32_LogicalDisk WHERE DriveType = 3");
foreach (CimInstance disk in disks)
{
var deviceId = (string)disk.CimInstanceProperties["DeviceID"].Value;
var free = (ulong)disk.CimInstanceProperties["FreeSpace"].Value;
Console.WriteLine($"{deviceId} 空き {free / 1024.0 / 1024 / 1024:F1} GB");
}
PowerShellのCIMコマンドレットが返すのと同じ CimInstance を扱うので、「PowerShellで試してからC#に書き写す」という開発の流れが素直につながります。C#とPowerShellの連携そのものを設計するなら「C#からPowerShellを実行してオブジェクトで受け取る方法」も参照してください。
flowchart TB
accTitle: PowerShellで試してC#に書き写す流れ
accDescr: PowerShellのCIMコマンドレットとC#のMI APIは同じCimInstance型を扱うため、PowerShellで試作してからC#に書き写す開発の流れが素直につながる
trial["PowerShellで試作"] --> gci["CIMコマンドレット"]
impl["C#で本実装"] --> mi["MI API"]
gci --> ci["同じCimInstance型"]
mi --> ci
ci -.-> flow["書き写しが素直につながる"]
図11: CIMコマンドレットとMI APIは同じCimInstance型を扱うため、試作から本実装へつながる。
6.4. DMTF日付は手で切り貼りせず変換APIへ渡す
WMIの日付は、CIM仕様のDMTF形式 yyyymmddHHMMSS.mmmmmm±UUU(末尾はUTCからのオフセット分。例: 20260801100000.000000+540)の文字列で格納されています。生の値を文字列処理で切り貼りするのはやめて、変換APIを使います。
- C# (System.Management):
ManagementDateTimeConverterがDMTF形式とDateTime/TimeSpanの相互変換を提供します。11 - CIM系API(Get-CimInstance / MI API): 日付プロパティは
DateTimeに変換済みで返るため、そもそもこの問題に遭遇しません。(Get-CimInstance Win32_OperatingSystem).LastBootUpTimeはそのままDateTimeとして計算に使えます。
flowchart TB
accTitle: DMTF日付形式の扱い
accDescr: WMIの日付はDMTF形式の文字列で格納されており、System.Managementで生の値を読んだ場合はManagementDateTimeConverterで変換し、CIM系APIならDateTimeに変換済みで返るため、自前の文字列の切り貼りはしない
dmtf["DMTF形式の文字列"] --> q1{"どのAPIで取得?"}
q1 -->|System.Management| conv["ManagementDateTimeConverter"]
q1 -->|CIM系API| done["DateTime変換済みで返る"]
conv --> dtv["DateTime / TimeSpanへ変換"]
cut["自前の文字列切り貼り"] -.-> ng["使わない"]
図12: DMTF文字列の変換は変換APIに任せ、CIM系APIなら変換済みのDateTimeをそのまま使う。
ここでのコードはAPIの基本形です。実際のアプリでは、取得失敗や未設定の値の扱いに加え、結果コレクション・取得オブジェクト・セッションの破棄を、利用するAPIに合わせて実装します。
7. プロセス起動を監視する:権限・購読・解除・再登録
「ポーリングで Win32_Process を定期取得して差分を見る」のではなく、イベント購読にします。プロセスの起動は Win32_ProcessStartTrace(カーネルトレースプロバイダーのイベントクラス。ProcessName / ProcessID / ParentProcessID などを持ちます8)を購読するのが簡単です。
7.1. 最初に実行権限と監視の置き場所を決める
Register-CimIndicationEvent はクラス名またはWQLイベントクエリで購読を登録し、-Action のスクリプトブロックが着信のたびに実行されます。7 このクラスの購読には管理者権限が必要です。7 イベントを誰が受信できるかはイベントクラスのセキュリティ記述子で制御されており、一般ユーザーのままではアクセス拒否になります。8
Win32_ProcessStartTrace 系の購読は管理者権限が前提です。7 「開発機(管理者で実行)では動いたのに、客先の一般ユーザー環境で監視が動かない」という事故は、ファイアウォールの通知ダイアログと並ぶ定番です。一般ユーザーで動かす業務アプリに監視を組み込むなら、監視部分をWindowsサービス(LocalSystem等)に分離し、アプリ本体とはプロセス間通信でつなぐ構成を検討してください。
flowchart TB
accTitle: 一般ユーザー環境での監視構成
accDescr: 管理者権限が前提の購読は一般ユーザーで動くアプリ本体から切り出し、LocalSystem等で実行するWindowsサービスに監視部分を分離して、アプリ本体とはプロセス間通信でつなぐ
svcm["監視用Windowsサービス"] --> subm["起動トレースを購読"]
svcm -.-> lsm["LocalSystem等で実行"]
appm["アプリ本体(一般ユーザー)"] ---|プロセス間通信| svcm
図13: 管理者権限が要る購読はサービス側に分離し、アプリ本体とはプロセス間通信でつなぐ。
7.2. PowerShellで購読し、監視終了時に解除する
# 管理者権限のPowerShellで実行すること
$action = {
$name = $Event.SourceEventArgs.NewEvent.ProcessName
$id = $Event.SourceEventArgs.NewEvent.ProcessID
Write-Host "プロセス起動: $name (PID=$id)"
}
Register-CimIndicationEvent -ClassName Win32_ProcessStartTrace `
-SourceIdentifier ProcessStarted -Action $action
購読は登録したPowerShellセッションに結び付いており、正常に継続している間は、プロセスが起動するたびに -Action が実行されます。解除コマンドまで続けて一気に実行してしまうと、監視が始まる前に購読が消えるだけなので注意してください。
解除は監視を終えるときに実行します。
# 監視を終えるとき: 購読の解除
Unregister-Event -SourceIdentifier ProcessStarted
sequenceDiagram
accTitle: プロセス起動イベント購読の流れ
accDescr: 管理者権限のPowerShellセッションでRegister-CimIndicationEventが購読を登録し、プロセスが起動するたびにイベントが着信してActionが実行され、監視を終えるときにUnregister-Eventで解除する
participant ps as PowerShellセッション
participant wmi as WMI
ps->>wmi: Register-CimIndicationEventで購読登録
Note over ps: 管理者権限で実行
wmi-->>ps: プロセス起動のたびにイベント着信
ps->>ps: -Actionを実行
ps->>wmi: Unregister-Eventで解除(監視終了時)
図14: 購読は登録したセッションに結び付き、解除は監視を終えるときに行う。
7.3. WITHINを使う汎用イベントはポーリングである
もう1つの方法が、クラスのインスタンス生成を監視する汎用のインスタンス生成イベント(__InstanceCreationEvent)です。こちらはWMIが WITHIN で指定した間隔でポーリングして差分をイベント化する仕組みなので、検知間隔と負荷のトレードオフを自分で決めることになります。
flowchart TB
accTitle: プロセス起動検知の2つの購読方式
accDescr: Win32_ProcessStartTraceはカーネルトレースプロバイダーのイベントクラスを購読する方式で、汎用の__InstanceCreationEventはWMIがWITHIN指定の間隔でポーリングして差分をイベント化するため検知間隔と負荷のトレードオフを自分で決める
goal["プロセス起動の検知"] --> t1["Win32_ProcessStartTrace"]
goal --> t2["__InstanceCreationEvent"]
t1 -.-> k1["カーネルトレースの購読"]
t2 -.-> w1["WITHIN間隔でポーリング"]
w1 -.-> tr["間隔と負荷のトレードオフ"]
図15: 専用のイベントクラスを購読するか、汎用のインスタンス生成イベントをポーリング間隔付きで使うか。
# 5秒間隔のポーリングでWin32_Processの新規インスタンスを監視
$query = "SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Process'"
Register-CimIndicationEvent -Query $query -SourceIdentifier ProcPoll -Action {
Write-Host "起動: $($Event.SourceEventArgs.NewEvent.TargetInstance.Name)"
}
7.4. C#ではManagementEventWatcherで受け取る
C#(System.Management)では ManagementEventWatcher が同じ役割です。11
using System.Management;
// 管理者として実行しているプロセスで
var watcher = new ManagementEventWatcher(
new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace"));
watcher.EventArrived += (_, e) =>
{
var name = (string)e.NewEvent["ProcessName"];
var pid = (uint)e.NewEvent["ProcessID"];
Console.WriteLine($"プロセス起動: {name} (PID={pid})");
};
watcher.Start();
// 監視終了時は watcher.Stop() と Dispose を忘れずに
7.5. 常駐監視は購読が切れた後の再登録まで設計する
常駐監視に組み込む場合は、購読が切れたときの再登録(サービス再起動時・エラー時)まで設計に含めてください。デバイス監視を含む「状態の確認と表示」の設計論は「外部機器の状態確認と表示のベストプラクティス」で扱っています。
stateDiagram-v2
accTitle: 常駐監視の購読ライフサイクル
accDescr: 常駐監視では購読中の状態がサービス再起動やエラーで切れることがあるため、切れたことを検知して再登録し購読中に戻す設計までを含める
s1: 購読中
s2: 購読が切れた状態
s3: 再登録
[*] --> s1
s1 --> s2: サービス再起動・エラー
s2 --> s3
s3 --> s1
図16: 常駐監視では、購読が切れたときに再登録して購読中へ戻す設計まで含める。
8. 障害を切り分ける:性能・ビット数・リポジトリ
接続できない場合は5.2節、購読だけが拒否される場合は7.1節、キャストや日付の扱いは6.2・6.4節へ戻って確認します。ここでは、それ以外によく出会う「遅い」「値が違う」「クラスが見つからない」を分けます。
8.1. 遅い:取得する量・頻度・セッションを見直す
WMIの照会は「プロバイダーがその場で値を作る」処理であり、タダではありません。定番のアンチパターンは2つです。
SELECT *の惰性使用。Win32_Processを全プロパティで全件取得すれば、その分プロバイダーの仕事とネットワーク転送(リモート時)が膨らみます。-Filterで行を、-Propertyで列を絞り、後続操作のためにキーだけ欲しいなら-KeyOnlyを使います。いずれも「オブジェクトのサイズとネットワークトラフィックを減らすため」の公式に用意された手段です。3- 短周期ポーリング。「1秒ごとに
Get-CimInstance Win32_Process」のような設計は、7章のイベント購読に置き換えます。どうしてもポーリング型(WITHIN)を使う場合も、要件に対して必要十分な間隔まで広げます。
また、リモートに対して1台ずつ -ComputerName で繰り返すのもムダが大きい形です。一時セッションの作成が照会のたびに走るため、複数操作はCIMセッションの使い回しに変えます。3
flowchart TB
accTitle: 性能アンチパターンと置き換え先
accDescr: SELECTアスタリスクの惰性使用はFilterとPropertyで行と列を絞りキーだけならKeyOnlyを使い、短周期ポーリングはイベント購読へ、1台ずつのComputerName指定の繰り返しはCIMセッションの使い回しへ置き換える
a1["SELECT *の惰性使用"] --> f1["FilterとPropertyで絞る"]
f1 -.-> f2["キーだけならKeyOnly"]
a2["短周期ポーリング"] --> f3["イベント購読に置き換え"]
a3["1台ずつComputerName"] --> f4["CIMセッションを使い回す"]
図17: 行・列・キーの絞り込み、適切な監視方式、セッション再利用で不要な負荷を抑える。
8.2. 値が違う:32bit/64bitのプロバイダーを確認する
64bit Windowsではプロバイダーに32bit版と64bit版が併存するものがあり、既定では呼び出し元アプリのビット数に一致する側が応答します。12 典型が root\default のレジストリプロバイダー(StdRegProv)で、32bitアプリから読むと Wow6432Node 側(32bitビュー)の値が返ります。12 「WMIで読んだレジストリ値が、regeditで見た値と違う」ときはまずこれを疑ってください。
逆側のビューが必要な場合は、接続時のコンテキストに __ProviderArchitecture(と、必須にするなら __RequiredArchitecture)を指定して明示的に要求できます。12 ビット数問題の全体像は「C#からWin32 APIを安全に呼ぶ ── P/Invoke実務ガイド」でも扱っています。
flowchart TB
accTitle: 64bit環境でのプロバイダー選択
accDescr: 既定では呼び出し元アプリのビット数に一致するプロバイダーが応答し、32bitアプリのレジストリ照会はWow6432Node側の値を受け取るが、__ProviderArchitecture指定で逆側のビューを明示的に要求できる
q1{"呼び出し元のビット数は?"} -->|32bit| p32["32bitプロバイダーが応答"]
q1 -->|64bit| p64["64bitプロバイダーが応答"]
p32 -.-> wow["レジストリはWow6432Node側の値"]
ctx["__ProviderArchitecture指定"] -.-> ov["逆側のビューを明示的に要求"]
図18: 既定では呼び出し元のビット数に一致する側が応答するため、32bitアプリはWow6432Node側を読む。
8.3. クラスが見つからない:リポジトリは確認してから修復する
WMIのクラス定義はリポジトリ(単一ファイルではなく、Repositoryフォルダー内のファイル群がデータベースとして機能します13)に格納されています。これが不整合を起こすと、「存在するはずのクラスが見つからない」「名前空間が無効」といったエラーが、アプリ側は何も変えていないのに出始めます。
切り分けと修復には winmgmt.exe を使います。13
rem 整合性チェック(結果が inconsistent なら不整合あり)
winmgmt /verifyrepository
rem 整合性チェック+不整合があれば再構築(読める内容はマージされる)
winmgmt /salvagerepository
注意すべきは、リポジトリの削除や初期化を最初の一手にしないことです。WMI経由で出るエラーはOSの他の部分に起因することもあり、Microsoftはリポジトリの削除を最初の対処にすると「システムやインストール済みアプリへの損傷につながり得る」と明言しています。13 /verifyrepository での確認 → /salvagerepository での修復、の順を守ります。
flowchart TB
accTitle: WMIリポジトリ不整合の切り分け手順
accDescr: クラスが見つからない等のエラーが出たらwinmgmtのverifyrepositoryで整合性を確認し、不整合ならsalvagerepositoryで再構築し、リポジトリの削除や初期化を最初の一手にしない
sym["クラスが見つからない等のエラー"] --> verify["winmgmt /verifyrepository"]
verify --> q1{"結果は inconsistent?"}
q1 -->|はい| salvage["winmgmt /salvagerepository"]
q1 -->|いいえ| other["OSの他の部分の原因を疑う"]
salvage -.-> merge["読める内容はマージされる"]
del["リポジトリの削除・初期化"] -.-> ng["最初の一手にしない"]
図19: verifyで確認してからsalvageで修復する順を守り、削除を最初の一手にしない。
9. まとめ:照会から監視・運用までをつなげる
WMI/CIMは、Windowsの管理情報を横断的に照会するための共通の入口です。専用APIで済む処理まで、すべてWMIへまとめる道具ではありません。
| 組み込む段階 | 確認すること |
|---|---|
| 道具を選ぶ | 設定・高頻度の性能監視・単発のOS操作は専用の仕組みを優先し、情報取得・リモート照会にWMI/CIMを使う |
| PowerShellで試す | 5.1向けでもCIMコマンドレットで書く。root/CIMV2のクラスを選び、行・列・キーを絞る |
| リモートへ広げる | WSMan/WinRMの接続条件を整え、複数操作はセッションを使い回す。必要な相手にはDCOMオプションを検討する |
| C#へ移す | ローカル照会向きのSystem.Managementと、リモート・監視向きのMI APIを選び分ける。型と日付の扱いを確認する |
| 常駐監視にする | Win32_ProcessStartTraceの権限を確認し、購読・解除・切断後の再登録まで一続きで設計する |
| 障害を調べる | 短周期ポーリング、プロバイダーのビット数、リポジトリの整合性を切り分ける。削除を最初の対処にしない |
CIMという標準とWMIという実装、照会とイベント購読、接続とアクセス許可を分けて考えると、どの道具を選び、どこを確認すべきかが明確になります。まずPowerShellで必要な情報を取得し、その結果をC#の実装と運用設計へつなげてください。
関連記事
- C#(CSharp)でPowerShellを実行して、オブジェクトとして受け取る方法
- PowerShell実用コマンド集 ── 日常作業でよく使う小さな機能を増やす
- Windows PowerShell 5.1とPowerShell 7の違い ── 社内スクリプト移行の実務ガイド
- 外部機器の状態の確認と表示のベストプラクティス - 「接続中」だけで済ませない設計
- C#からWin32 APIを安全に呼ぶ ── P/Invoke実務ガイド(DllImport / LibraryImport / CsWin32)
- WindowsのTPMとは何か ── 図解でわかる「鍵を外に出さない金庫」と測定起動
関連する相談領域
合同会社小村ソフトでは、WMI/CIMを使ったハードウェア情報取得・プロセス監視・リモートPC照会の業務アプリへの組み込み、Get-WmiObjectベースの社内スクリプトのCIMコマンドレットへの移行、「開発機では動くのに客先で権限エラーになる」類の原因調査を扱っています。PowerShellでの試作からC#への本実装までを一続きでご相談いただけます。
参考リンク
-
Microsoft Learn, About WMI. WMIがWBEM(企業環境の管理情報アクセスの標準技術を開発する業界イニシアティブ)のMicrosoft実装であること、管理対象の表現にCIM(Common Information Model)業界標準を使い、CIMはDMTF(Distributed Management Task Force)が開発・維持していること、次世代版のMI(Windows Management Infrastructure)が従来のWMIと完全互換であること、リモートWMI接続がDCOMで行われ、代替としてWS-ManagementベースのWinRMがあることについて。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Differences between Windows PowerShell 5.1 and PowerShell 7.x. WMI v1コマンドレット(Register-WmiEvent / Set-WmiInstance / Invoke-WmiMethod / Get-WmiObject / Remove-WmiObject)がPowerShellから削除されたこと、CimCmdletsモジュール(WMI v2)のコマンドレットが同じ機能を提供し、新機能と再設計された構文を持つことについて。 ↩ ↩2 ↩3
-
Microsoft Learn, Get-CimInstance (CimCmdlets). ComputerNameもCimSessionも指定しない場合はローカルWMIにCOMセッションで接続し、-ComputerName指定時はWsManプロトコルの一時セッションを作ること、同一コンピューターへの複数操作にはCIMセッションでの接続が性能上推奨されること、-FilterがWHEREキーワードを含めないWQL/CQLのwhere句であること、-Propertyや-KeyOnlyでオブジェクトサイズとネットワークトラフィックを削減できること、既定の名前空間がroot/CIMV2で既定の照会言語(-QueryDialect)がWQLであること、出力がMicrosoft.Management.Infrastructure.CimInstanceであること、Invoke-CimMethodと組み合わせたGetOwner呼び出し例、Windows専用のコマンドレットであることについて。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10
-
Microsoft Learn, New-CimSessionOption (CimCmdlets). CIMセッションオプションにWsMan用とDCOM用の2つのパラメーターセットがあること、-ProtocolにDcom / Default / Wsmanを指定できること、New-CimSessionOption -Protocol Dcomで作成したオプションをNew-CimSessionの-SessionOptionに渡してDCOMのCIMセッションを作成する例、DCOMセッションの既定の偽装レベルがImpersonateであることについて。 ↩ ↩2
-
Microsoft Learn, ManagementObjectSearcher Class (System.Management). 指定したWQLクエリにもとづいて管理オブジェクトのコレクションを取得する、管理情報取得の最も一般的な入口クラスであること、ObjectQueryとManagementScope(WMI名前空間)を受け取りGet()でManagementObjectCollectionを返すこと、System.Management.dllがNuGetパッケージSystem.Managementとして提供されることについて。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, CimSession Class (Microsoft.Management.Infrastructure). Microsoft.Management.Infrastructure.dllがNuGetパッケージMicrosoft.Management.Infrastructureとして提供されること、Create(computerName)によるセッション作成、QueryInstances(namespace, queryDialect, query)によるクエリ実行、EnumerateInstances / GetInstance / InvokeMethod / Subscribeおよびそれぞれの非同期版(*Async)を備えIDisposableを実装することについて。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Register-CimIndicationEvent (CimCmdlets). クラス名またはクエリ式でインディケーション(イベント)を購読し-SourceIdentifierで購読名を付けること、Win32_ProcessStartTraceの購読例とその実行にPowerShellの管理者実行が必要である旨の注記、-Actionスクリプトブロック内で$Event.SourceEventArgs.NewEventからProcessName / ProcessIdを参照する例、-ComputerName指定時はWsManの一時セッション・未指定時はローカルにCOMで接続すること、購読解除にUnregister-Eventを使うことについて。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Win32_ProcessStartTrace class. 新しいプロセスの開始を示すイベントクラスであり、ProcessName / ProcessID / ParentProcessID / SessionID / Sidなどのプロパティを持つこと、SECURITY_DESCRIPTORプロパティがどのユーザーがイベントを受信できるかをイベントプロバイダーが決定するための記述子であること、名前空間がRoot\CIMV2でカーネルトレースプロバイダー(Krnlprov.dll)により提供されることについて。 ↩ ↩2 ↩3
-
Microsoft Learn, Win32_LogicalDisk class. Win32_LogicalDiskがCIM_LogicalDisk派生のローカルストレージデバイスを表すクラスであること、DriveTypeの値(2=リムーバブル、3=ローカルディスク、4=ネットワークドライブ、5=CD等)、FreeSpace / Sizeがuint64のバイト値であること、DeviceIDがキーであること、DriveType = 3で絞り込むVBScript / C#のクエリ例について。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Installation and configuration for Windows Remote Management. 既定ではWinRMリスナーが構成されておらずWS-Managementメッセージを送受信できないこと、winrm quickconfigがサービスの自動起動化・HTTP/HTTPSリスナーの構成・ファイアウォール例外の登録を行うこと、WinRM 2.0の既定ポートがHTTP 5985 / HTTPS 5986であること、ワークグループ等で相互認証(Kerberos)が確立できない場合はTrustedHostsを可能な限り限定して設定すること、リスナーへのリモートアクセスを制御する既定のセキュリティ記述子(RootSDDL)や、管理者以外のユーザーにWMIプラグイン利用を許可する場合の追加構成について。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, System.Management Namespace. WMI基盤への照会をManagementObjectSearcher系クラスで、イベント購読をManagementEventWatcherで行う名前空間であること、WqlEventQueryがWQL形式のイベントクエリを表すこと、ManagementDateTimeConverterがDMTF日時・時間間隔とCLRのDateTime / TimeSpanの相互変換メソッドを提供することについて。 ↩ ↩2 ↩3
-
Microsoft Learn, Requesting WMI Data on a 64-bit Platform. プロバイダーに32bit版と64bit版が併存する場合、既定では32bitアプリ(スクリプト含む)には32bitプロバイダーが、64bitアプリには64bitプロバイダーが応答すること、コンテキストの__ProviderArchitecture(32または64)と__RequiredArchitectureで非既定側のプロバイダーを要求・強制できること(強制時に該当版がなければWBEM_E_PROVIDER_LOAD_FAILURE)、レジストリプロバイダーの例で32bitクライアントがHKLM\SOFTWARE\Wow6432Node側のデータを受け取ることについて。 ↩ ↩2 ↩3
-
Microsoft Learn, winmgmt. winmgmt.exeの/verifyrepositoryがWMIリポジトリの整合性チェックを行うこと、/salvagerepositoryが整合性チェックのうえ不整合検出時にリポジトリを再構築し読み取れた内容をマージすること、/resetrepositoryがOS初期インストール時の状態へ戻すこと、リポジトリがRepositoryフォルダー内のファイル群でデータベースとして機能すること、WMI経由のエラーがOSの他の部分に起因する場合もあり、最初の対処としてのリポジトリ削除はシステムやインストール済みアプリの損傷につながり得るため行わないべきことについて。 ↩ ↩2 ↩3
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
引数はなぜ壊れるか ── Windowsのコマンドライン引数の規則
Windowsでは引数の配列は存在せず、CreateProcessに渡るのは1本の文字列で、分割は受け取り側が行います。CommandLineToArgvW・CRT・.NETの分割規則と、.NETのArgumentList・C++での正しい組み立て方を解説します。
マルチスレッドの実務ベストプラクティス .NET編 ── スレッドを増やす前に決めておくこと
「スレッドを立てたら、たまに落ちる・固まる」を防ぐ設計の定石を.NET/C#向けに整理。スレッドを自分で作らずTaskに乗る、共有可変状態を減らす、ロックの規律、CancellationTokenでの停止設計、UIスレッドの扱いまで解説します。
業務アプリの和暦・祝日・締め日処理 ── 改元に強い設計とJapaneseCalendar・営業日計算の実務
和暦表示・祝日を除く営業日計算・締め日処理という日本の業務アプリ特有の日付処理を整理します。JapaneseCalendarと改元に強い設計、内閣府CSVによる祝日マスタ運用、AddMonthsの丸めを踏まえた締め日計算まで解説します。
Windowsアプリの多重起動防止 ── 名前付きMutexと二重起動時のアクティブ化
業務Windowsアプリの多重起動防止を名前付きMutexで実装する方法を整理します。Global\とLocal\の違いによるRDP環境の落とし穴、AbandonedMutexException、既存インスタンスの前面化まで解説します。
Windowsアプリ 外注・受託開発を依頼する前に整理したいこと
Windowsアプリの外注・受託開発を依頼する前に、既存ソフト改修、装置連携、COM/ActiveX、配布・更新、保守の整理ポイントを解説します。
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
Windowsアプリ開発
業務アプリ、装置連携、通信ツールなどの Windows ソフト開発を支援します。
よくある質問
この記事のテーマについて、相談時によくある質問をまとめています。
- WMIとCIMは何が違うのですか?
- CIMは、DMTF(Distributed Management Task Force)が策定・維持している「システムやデバイスなどの管理対象を表現するための業界標準モデル」です。WMIは、その標準を使うWBEMというイニシアティブのMicrosoft実装で、Windowsに組み込まれています。つまりCIMが仕様、WMIがWindows上の実装という関係です。PowerShellのGet-CimInstanceやC#のMicrosoft.Management.Infrastructureが「CIM」を名乗っているのは、この標準に沿ったAPIだからで、接続先は同じWMIの基盤です。日常の開発では「WMIのクラス(Win32_*など)をCIM系のAPIで照会する」と理解しておけば実務上は困りません。
- Get-WmiObjectはもう使えないのですか?
- Windows PowerShell 5.1では今も動きますが、PowerShell 6以降(現行のPowerShell 7)ではGet-WmiObject・Invoke-WmiMethod・Register-WmiEvent・Set-WmiInstance・Remove-WmiObjectのWMI v1コマンドレットが削除されており、実行できません。同じ機能はCimCmdletsモジュール(Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEventなど)が提供しています。新しく書くスクリプトは、5.1で動かす場合でもCIMコマンドレットで書いておくのが安全です。そうしておけば、PowerShell 7への移行時にWMI部分を書き直す必要がなくなります。
- C#からWMIを使うにはSystem.ManagementとMicrosoft.Management.Infrastructureのどちらを使うべきですか?
- どちらもWindows専用で、現行の.NETからはNuGetパッケージとして利用します。System.ManagementはManagementObjectSearcherにWQLを渡すだけで使える古典的なAPIで、ローカルの情報取得が中心ならこれで十分です。DMTF日付を変換するManagementDateTimeConverterもこちらに含まれます。一方Microsoft.Management.Infrastructure(MI API)は、PowerShellのCIMコマンドレットと同じ型体系(CimSession / CimInstance)を持ち、WSMan経由のリモート照会、非同期版メソッド、イベント購読(Subscribe)まで一貫して扱えます。リモートPCの照会や監視を本格的に組み込むならMI APIを選ぶのが合理的です。
- リモートPCにGet-CimInstanceがつながりません。何を確認すべきですか?
- まず接続先でWinRMが構成されているかを確認してください。-ComputerNameを指定したCIM操作はWSMan(WinRM)プロトコルで一時セッションを作るため、接続先でWinRMサービスとリスナーが動いていることが前提です。winrm quickconfigで既定構成(サービス起動・リスナー作成・ファイアウォール例外)を行えます。既定ポートはHTTPが5985、HTTPSが5986なので、経路のファイアウォールも確認します。ワークグループ環境ではKerberosの相互認証が使えないため、クライアント側のTrustedHostsへの登録が必要になる場合があります。どうしてもWinRMを構成できない相手には、New-CimSessionOption -Protocol Dcomで作ったオプションを使いDCOMで接続する手もあります。
- WMIの日付が「20260801100000.000000+540」のような形式で返るのはなぜですか?
- WMIの日付は、DMTFのCIM仕様で定められた文字列形式(yyyymmddHHMMSS.mmmmmm±UUU、末尾はUTCからのオフセット分)で格納されているためです。旧Get-WmiObjectやSystem.Managementで生の値を読むと、この文字列がそのまま返ります。C#(System.Management)ではManagementDateTimeConverterにDMTF形式とDateTime / TimeSpanの相互変換メソッドが用意されているので、自前で文字列を切り貼りせずこれを使ってください。なお、Get-CimInstanceなどのCIM系APIで取得した場合は、日付プロパティはDateTimeに変換済みで返るため、この問題自体に遭遇しません。