WMI/CIMをC#・PowerShellから使う ── ハードウェア情報取得・プロセス監視・リモート照会の実務ガイド

· · Windows, C#, .NET, PowerShell, WMI, CIM, 業務アプリ, Windows開発

「PCのシリアル番号と機種名を業務アプリの画面に出したい」「サーバーのディスク空き容量を監視して警告したい」「特定のプロセスが起動したことを検知したい」「離れた場所のPCの状態をまとめて照会したい」── Windowsの業務アプリや管理ツールの開発で、この種の要求は定番です。そして、その定番の答えがWMI(Windows Management Instrumentation)、標準名で言えばCIM(Common Information Model)です。

やっかいなのは、WMIまわりの情報が新旧入り混じっていることです。検索すると Get-WmiObject を使った10年前の記事と Get-CimInstance を使った記事が同居し、C#側も System.ManagementMicrosoft.Management.Infrastructure の2系統がある。どれが現行の書き方で、どれが「今も動くが新規には選ばない」書き方なのかが分かりにくい状態です。実際、Get-WmiObject はPowerShell 7には存在せず、5.1向けに書いた社内スクリプトの移行で突然表面化します。

この記事では、業務アプリでハードウェア情報の取得・プロセス監視・リモートPC照会を実装するC#/PowerShell開発者を対象に、WMI/CIMの構造の最小限の理解から、PowerShellのCIMコマンドレット、C#の2つのAPI、よく使う実例レシピ、性能・権限・64bitの落とし穴、そして「WMIを使うべきでない場面」の判断までを、2026年8月時点の一次情報にもとづいて整理します。

1. まず結論

  • CIMはDMTFが策定する管理情報の業界標準、WMIはそのMicrosoft実装です。PowerShellやC#の「CIM」系APIは、この標準に沿った現行世代のAPIで、接続先は同じWMI基盤です。1
  • PowerShellの現行はCIMコマンドレット(Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEvent)です。旧WMIコマンドレット(Get-WmiObjectなど5本)はPowerShell 6以降で削除されており、PowerShell 7では動きません。2
  • 既定の名前空間は root/CIMV2 で、日常の照会はここのWin32_*クラスをWQLで絞り込む形が基本です。3
  • リモート照会はWSMan(WinRM)が既定です。-ComputerName 指定でWSManの一時セッションが作られます。同じ相手に複数回照会するならCIMセッション(New-CimSession)を使い回すのが性能面の定石で、WinRMを構成できない古い相手にはDCOMプロトコルオプションがあります。34
  • C#は System.Management(ManagementObjectSearcher)と Microsoft.Management.Infrastructure(CimSession)の2系統です。どちらもWindows専用で、現行の.NETではNuGetから導入します。リモートや監視を本格的にやるならCIMコマンドレットと同じ型体系のMI APIが向いています。56
  • プロセス起動の検知はイベント購読で行い、ポーリングにしないこと。Win32_ProcessStartTrace の購読は管理者権限で実行する必要があります。78
  • SELECT * を惰性で使わないこと。-Filter / -Property / -KeyOnly で転送するデータを絞るのが、WMIの性能問題の半分を予防します。3
  • WMIは万能ではありません。高頻度の性能監視、自アプリの設定読み書き、単発のOS機能呼び出しには、パフォーマンスカウンター・レジストリ・Win32 API・専用コマンドレットの方が適します(8章の判断表)。

2. WMI/CIMとは何か ── 標準と実装、名前空間、クラス、WQL

まず用語の関係を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

開発者として押さえるべき構造は次の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で呼べるメソッドを持つ一部クラスに限られ、何でもできる仕組みではありません。

3. PowerShellからの利用 ── CIMコマンドレットが現行、WMIコマンドレットは削除済み

3.1. 基本は 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 オブジェクトで、日付プロパティ(CreationDateLastBootUpTime など)は DateTime に変換済みで返ります。旧 Get-WmiObject と違い、取得したオブジェクトはメソッドを直接持たないため、メソッド呼び出しは 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

3.2. 旧WMIコマンドレットからの移行対応表

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 イベント購読(6.3節)
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の違い」にまとめています。

4. リモート照会 ── CIMセッション(WSMan既定)とDCOMオプション

CIMコマンドレットは、指定なしならローカルのWMIにCOMで接続し、-ComputerName を指定するとWSMan(WinRM)プロトコルで一時セッションを作って接続します。同じコンピューターに複数の操作を行う場合は、CIMセッションを作って使い回す方が性能上有利です。3

# 単発なら -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

WinRMを構成できない古いマシンなど、WSManで接続できない相手にはDCOMプロトコルを選べます。4

$dcom = New-CimSessionOption -Protocol Dcom
$session = New-CimSession -ComputerName OldServer -SessionOption $dcom

リモート照会の前提は次のとおりです。

  • 接続先でWinRMが構成されていること。winrm quickconfig が、サービスの自動起動化・HTTPリスナー(既定ポート5985)の作成・ファイアウォール例外の登録を一括で行います。10 HTTPS(既定ポート5986)で接続したい場合はこれだけでは足りず、サーバー証明書を用意したうえで winrm quickconfig -transport:https などでHTTPSリスナーを別途構成する必要があります。10
  • 経路のファイアウォールで該当ポートが開いていること。受信規則の設計と登録の実務は「Windowsファイアウォールと業務アプリ」の記事で扱ったとおりです。
  • 認証。ドメイン環境ならKerberosで相互認証されます。ワークグループではKerberosが使えないため、クライアント側の TrustedHosts への登録が必要になる場合があります。登録先は必要最小限に絞ります。10
  • 権限。既定の構成では、リモートのWMI照会・操作は接続先の管理者グループに属するアカウントで行うのが基本です。一般ユーザーに開放する場合は、WinRMとWMI名前空間の両方でアクセス許可の構成が必要になります。10
  • なお、DCOMは固定の待ち受けポートを持たない(RPCの動的ポートを使う)ため、ファイアウォールをまたぐ設計が難しくなります。これから作る仕組みはWSManを既定と考えるのが無難です。

5. C#からの利用 ── System.Management と Microsoft.Management.Infrastructure

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併用の設計

5.1. System.Management: ManagementObjectSearcher の基本

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 になる、というのが最初の定番のつまずきです。

5.2. MI API: CimSession の基本

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を実行してオブジェクトで受け取る方法」も参照してください。

6. よく使う実例レシピ

6.1. 定番クラスの早見表

取りたい情報 クラス 主なプロパティ
メーカー・機種名 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

6.2. 資産管理の定番: シリアル番号・モデル名・ディスク空き

# 機種情報とシリアル番号(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 監視ならこのスクリプトをCIMセッション経由で各サーバーに回すだけで、エージェントなしのディスク監視の土台ができます。

6.3. プロセス起動の検知 ── イベント購読

「ポーリングで Win32_Process を定期取得して差分を見る」のではなく、イベント購読にします。プロセスの起動は Win32_ProcessStartTrace(カーネルトレースプロバイダーのイベントクラス。ProcessName / ProcessID / ParentProcessID などを持ちます8)を購読するのが簡単です。

# 管理者権限の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

Register-CimIndicationEvent はクラス名またはWQLイベントクエリで購読を登録し、-Action のスクリプトブロックが着信のたびに実行されます。7 このクラスの購読には管理者権限が必要です。7 イベントを誰が受信できるかはイベントクラスのセキュリティ記述子で制御されており、一般ユーザーのままではアクセス拒否になります。8

もう1つの方法が、任意のクラスに使える汎用のインスタンス生成イベント(__InstanceCreationEvent)です。こちらはWMIが WITHIN で指定した間隔でポーリングして差分をイベント化する仕組みなので、検知間隔と負荷のトレードオフを自分で決めることになります。

# 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)"
}

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. 落とし穴 ── 性能・権限・64bit・リポジトリ・日付

7.1. SELECT * とポーリング乱発

WMIの照会は「プロバイダーがその場で値を作る」処理であり、タダではありません。定番のアンチパターンは2つです。

  • SELECT * の惰性使用。Win32_Process を全プロパティで全件取得すれば、その分プロバイダーの仕事とネットワーク転送(リモート時)が膨らみます。-Filter で行を、-Property で列を絞り、後続操作のためにキーだけ欲しいなら -KeyOnly を使います。いずれも「オブジェクトのサイズとネットワークトラフィックを減らすため」の公式に用意された手段です。3
  • 短周期ポーリング。「1秒ごとに Get-CimInstance Win32_Process」のような設計は、6.3節のイベント購読に置き換えます。どうしてもポーリング型(WITHIN)を使う場合も、要件に対して必要十分な間隔まで広げます。

また、リモートに対して1台ずつ -ComputerName で繰り返すのもムダが大きい形です。一時セッションの作成が照会のたびに走るため、複数操作はCIMセッションの使い回しに変えます。3

7.2. イベント購読の権限

6.3節のとおり、Win32_ProcessStartTrace 系の購読は管理者権限が前提です。7 「開発機(管理者で実行)では動いたのに、客先の一般ユーザー環境で監視が動かない」という事故は、ファイアウォールの通知ダイアログと並ぶ定番です。一般ユーザーで動かす業務アプリに監視を組み込むなら、監視部分をWindowsサービス(LocalSystem等)に分離し、アプリ本体とはプロセス間通信でつなぐ構成を検討してください。

7.3. 32bit/64bitとプロバイダー

64bit Windowsではプロバイダーに32bit版と64bit版が併存するものがあり、既定では呼び出し元アプリのビット数に一致する側が応答します。12 典型が root\default のレジストリプロバイダー(StdRegProv)で、32bitアプリから読むと Wow6432Node 側(32bitビュー)の値が返ります。12 「WMIで読んだレジストリ値が、regeditで見た値と違う」ときはまずこれを疑ってください。逆側のビューが必要な場合は、接続時のコンテキストに __ProviderArchitecture(と、必須にするなら __RequiredArchitecture)を指定して明示的に要求できます。12 ビット数問題の全体像は「C#からWin32 APIを安全に呼ぶ ── P/Invoke実務ガイド」でも扱っています。

7.4. WMIリポジトリ破損時の症状と対処

WMIのクラス定義はリポジトリ(単一ファイルではなく、Repositoryフォルダー内のファイル群がデータベースとして機能します13)に格納されています。これが不整合を起こすと、「存在するはずのクラスが見つからない」「名前空間が無効」といったエラーが、アプリ側は何も変えていないのに出始めます。切り分けと修復には winmgmt.exe を使います。13

rem 整合性チェック(結果が inconsistent なら不整合あり)
winmgmt /verifyrepository

rem 整合性チェック+不整合があれば再構築(読める内容はマージされる)
winmgmt /salvagerepository

注意すべきは、リポジトリの削除や初期化を最初の一手にしないことです。WMI経由で出るエラーはOSの他の部分に起因することもあり、Microsoftはリポジトリの削除を最初の対処にすると「システムやインストール済みアプリへの損傷につながり得る」と明言しています。13 /verifyrepository での確認 → /salvagerepository での修復、の順を守ります。

7.5. DMTF日付形式の変換

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 として計算に使えます。

8. WMIを使うべきでない場面 ── 手段の判断表

WMIは「統一された読み取り口」としては優秀ですが、常に最適解ではありません。実務での使い分けの目安です。

やりたいこと 適した手段 WMIを選ばない理由
ハードウェア情報・OS構成の取得、エージェントなしのリモート照会 WMI/CIM ここがWMIの本領。専用APIを個別に叩くより統一的
自アプリの設定の読み書き レジストリ直読(Microsoft.Win32.Registry)・構成ファイル WMI経由のレジストリ操作は遠回りで、7.3節のビット数問題も背負い込む
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を直接触らずに、その恩恵だけ受ける」形と言えます。

9. まとめ

  • CIMはDMTFの業界標準、WMIはそのMicrosoft実装です。PowerShellのCIMコマンドレットもC#のMI APIも、この標準に沿った現行世代の入口です。
  • PowerShellでは Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEvent が現行です。Get-WmiObjectなどのWMIコマンドレットはPowerShell 7に存在しないため、新規のスクリプトは5.1向けでもCIM側で書きます。
  • リモート照会はWSMan(WinRM)が既定で、複数操作はCIMセッションを使い回します。WinRM未構成の相手にはDCOMオプションという逃げ道があります。
  • C#はSystem.Management(手軽・ローカル向き)とMicrosoft.Management.Infrastructure(リモート・監視向き、CIMコマンドレットと同じ型体系)の2系統から選びます。どちらもWindows専用のNuGetパッケージです。
  • プロセス監視はポーリングではなくイベント購読で。Win32_ProcessStartTraceの購読には管理者権限が必要です。
  • SELECT *と短周期ポーリングを避け、-Filter / -Property / -KeyOnlyで絞る。32bitプロセスからの照会は32bitプロバイダーに向くこと、DMTF日付は変換APIを使うこと、リポジトリ破損は削除ではなくverify→salvageの順で対処することを覚えておいてください。
  • 専用の仕組みがある領域(設定・性能カウンター・単発API呼び出し)にはWMIを持ち込まず、横断的な照会とリモート照会にWMI/CIMを使う ── これが使いどころの一文です。

関連記事

関連する相談領域

合同会社小村ソフトでは、WMI/CIMを使ったハードウェア情報取得・プロセス監視・リモートPC照会の業務アプリへの組み込み、Get-WmiObjectベースの社内スクリプトのCIMコマンドレットへの移行、「開発機では動くのに客先で権限エラーになる」類の原因調査を扱っています。PowerShellでの試作からC#への本実装までを一続きでご相談いただけます。

参考リンク

  1. 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

  2. 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

  4. 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

  5. Microsoft Learn, ManagementObjectSearcher Class (System.Management). 指定したWQLクエリにもとづいて管理オブジェクトのコレクションを取得する、管理情報取得の最も一般的な入口クラスであること、ObjectQueryとManagementScope(WMI名前空間)を受け取りGet()でManagementObjectCollectionを返すこと、System.Management.dllがNuGetパッケージSystem.Managementとして提供されることについて。  2 3 4

  6. 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

  7. Microsoft Learn, Register-CimIndicationEvent (CimCmdlets). クラス名またはクエリ式でインディケーション(イベント)を購読し-SourceIdentifierで購読名を付けること、Win32_ProcessStartTraceの購読例とその実行にPowerShellの管理者実行が必要である旨の注記、-Actionスクリプトブロック内で$Event.SourceEventArgs.NewEventからProcessName / ProcessIdを参照する例、-ComputerName指定時はWsManの一時セッション・未指定時はローカルにCOMで接続すること、購読解除にUnregister-Eventを使うことについて。  2 3 4

  8. Microsoft Learn, Win32_ProcessStartTrace class. 新しいプロセスの開始を示すイベントクラスであり、ProcessName / ProcessID / ParentProcessID / SessionID / Sidなどのプロパティを持つこと、SECURITY_DESCRIPTORプロパティがどのユーザーがイベントを受信できるかをイベントプロバイダーが決定するための記述子であること、名前空間がRoot\CIMV2でカーネルトレースプロバイダー(Krnlprov.dll)により提供されることについて。  2 3

  9. 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

  10. 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

  11. Microsoft Learn, System.Management Namespace. WMI基盤への照会をManagementObjectSearcher系クラスで、イベント購読をManagementEventWatcherで行う名前空間であること、WqlEventQueryがWQL形式のイベントクエリを表すこと、ManagementDateTimeConverterがDMTF日時・時間間隔とCLRのDateTime / TimeSpanの相互変換メソッドを提供することについて。  2 3

  12. 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

  13. Microsoft Learn, winmgmt. winmgmt.exeの/verifyrepositoryがWMIリポジトリの整合性チェックを行うこと、/salvagerepositoryが整合性チェックのうえ不整合検出時にリポジトリを再構築し読み取れた内容をマージすること、/resetrepositoryがOS初期インストール時の状態へ戻すこと、リポジトリがRepositoryフォルダー内のファイル群でデータベースとして機能すること、WMI経由のエラーがOSの他の部分に起因する場合もあり、最初の対処としてのリポジトリ削除はシステムやインストール済みアプリの損傷につながり得るため行わないべきことについて。  2 3

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

よくある質問

この記事のテーマについて、相談時によくある質問をまとめています。

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に変換済みで返るため、この問題自体に遭遇しません。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る