Excel VBA 逆引き集 | WMI 呼び出し

Excel VBA
スポンサーリンク
  1. ねらい:VBAからWMIを呼び出し、PCの「見えない情報」を一気に可視化する
    1. 重要ポイントの深掘り
  2. 基本形:WMIサービスを握って、SELECTで値を読む
    1. サービス取得と簡易ユーティリティ
    2. OS・CPU・メモリを最短で取る
    3. 重要ポイントの深掘り
  3. よく使うWMIクラス:ドライブ・ネットワーク・プロセス・サービス
    1. ドライブの空き容量と総容量(固定ディスクのみ)
    2. IPアドレス(有効NICのみ、IPv4を抽出)
    3. 実行中プロセスの一覧(名前とPID)
    4. サービスの状態(自動起動で停止しているものの抽出にも使える)
    5. 重要ポイントの深掘り
  4. 便利関数:WMI時刻の変換・台数のカウント・フィルタ
    1. WMI時刻(yyyymmddHHMMSS.******±TZ)をISOへ
    2. テーブルフィルタ(状態で絞る例)
  5. レポート生成テンプレート:一括収集→シートへ書く
    1. 入口と書き出し(貼ってすぐ動く)
    2. 共通枠(描画・イベント抑止と復帰)
    3. 重要ポイントの深掘り
  6. 実務で効くトラブルシュート活用例
    1. 遅い・不安定の切り分けに使う視点
  7. より深い取得:イベントログ・プリンタ・BIOS・バッテリ(必要に応じて)
    1. イベントログ(最近のエラーのみ抜粋)
    2. プリンタ一覧
  8. 落とし穴と対策(深掘り)
    1. 権限・ポリシーで失敗する
    2. 遅い・タイムアウトする
    3. Nullと型の扱い
  9. まとめ:Late Binding+配列I/O+一括クエリで「速い・止まらない」WMIレポートを作る

ねらい:VBAからWMIを呼び出し、PCの「見えない情報」を一気に可視化する

WMI(Windows Management Instrumentation)は、OS・ハードウェア・ネットワーク・プロセス・サービスなどの情報を標準化して提供する仕組みです。VBAからは GetObject(“winmgmts:\.\root\cimv2”) を起点にクエリを投げ、返ってきたオブジェクトを走査して値を取り出します。ここでは参照設定不要(Late Binding)で貼って動くテンプレートを、基本の呼び方、よく使うクラス、表への一括書き出し、トラブル対策の順に解説します。

重要ポイントの深掘り

WMIは「クエリを減らして一括取得」が速さの鍵です。1件ずつ取りに行くより、必要な列をまとめてSELECTしてコレクションを一度だけ走査します。企業環境では権限やポリシーで取得に失敗することがあるため、On Errorのスコープを最小にしつつ、空欄返しで“レポートは止めない”設計にしておくと実務で強いです。


基本形:WMIサービスを握って、SELECTで値を読む

サービス取得と簡易ユーティリティ

' ModWmiBase.bas
Option Explicit

Public Function WmiSvc(Optional ByVal ns As String = "root\cimv2") As Object
    Set WmiSvc = GetObject("winmgmts:\\.\\" & ns)
End Function

Public Function WmiQuery(ByVal q As String, Optional ByVal ns As String = "root\cimv2") As Object
    Set WmiQuery = WmiSvc(ns).ExecQuery(q)
End Function
VB

OS・CPU・メモリを最短で取る

' ModWmiQuick.bas
Option Explicit

Public Function OsCaption() As String
    Dim it As Object
    For Each it In WmiQuery("SELECT Caption FROM Win32_OperatingSystem")
        OsCaption = it.Caption: Exit For
    Next
End Function

Public Function CpuName() As String
    Dim it As Object
    For Each it In WmiQuery("SELECT Name FROM Win32_Processor")
        CpuName = it.Name: Exit For
    Next
End Function

Public Function TotalRamGB() As Double
    Dim it As Object
    For Each it In WmiQuery("SELECT TotalVisibleMemorySize FROM Win32_OperatingSystem")
        TotalRamGB = Round(it.TotalVisibleMemorySize / 1024# / 1024#, 2): Exit For
    Next
End Function
VB

重要ポイントの深掘り

同じクラスを何度も問い合わせると遅くなります。必要列を1本のSELECTにまとめる、またはクエリ結果をローカル変数へキャッシュして使い回すと速度が安定します。


よく使うWMIクラス:ドライブ・ネットワーク・プロセス・サービス

ドライブの空き容量と総容量(固定ディスクのみ)

' ModWmiDrive.bas
Option Explicit

Public Function DriveTable() As Variant
    Dim col As Object: Set col = WmiQuery("SELECT Name, FreeSpace, Size FROM Win32_LogicalDisk WHERE DriveType=3")
    Dim cnt As Long: cnt = 0
    Dim it As Object: For Each it In col: cnt = cnt + 1: Next

    Dim a() As Variant: ReDim a(1 To cnt + 1, 1 To 3)
    a(1, 1) = "Drive": a(1, 2) = "Free(GB)": a(1, 3) = "Size(GB)"

    Dim i As Long: i = 2
    For Each it In col
        a(i, 1) = it.Name
        a(i, 2) = Round(CDbl(it.FreeSpace) / 1024# / 1024# / 1024#, 2)
        a(i, 3) = Round(CDbl(it.Size) / 1024# / 1024# / 1024#, 2)
        i = i + 1
    Next
    DriveTable = a
End Function
VB

IPアドレス(有効NICのみ、IPv4を抽出)

' ModWmiNet.bas
Option Explicit

Public Function IPv4List() As String
    Dim res As String, it As Object
    For Each it In WmiQuery("SELECT IPAddress FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled=TRUE")
        If Not IsNull(it.IPAddress) Then
            Dim ip: For Each ip In it.IPAddress
                If InStr(CStr(ip), ":") = 0 Then res = res & ip & " "
            Next
        End If
    Next
    IPv4List = Trim$(res)
End Function
VB

実行中プロセスの一覧(名前とPID)

' ModWmiProcess.bas
Option Explicit

Public Function ProcessTable(Optional ByVal topN As Long = 50) As Variant
    Dim col As Object: Set col = WmiQuery("SELECT Name, ProcessId FROM Win32_Process")
    Dim cnt As Long: cnt = 0: Dim it As Object
    For Each it In col: cnt = cnt + 1: If cnt >= topN Then Exit For: Next
    Dim a() As Variant: ReDim a(1 To WorksheetFunction.Min(cnt, topN) + 1, 1 To 2)
    a(1, 1) = "Name": a(1, 2) = "PID"
    Dim i As Long: i = 2
    For Each it In col
        a(i, 1) = it.Name
        a(i, 2) = it.ProcessId
        i = i + 1
        If i > UBound(a, 1) Then Exit For
    Next
    ProcessTable = a
End Function
VB

サービスの状態(自動起動で停止しているものの抽出にも使える)

' ModWmiService.bas
Option Explicit

Public Function ServiceTable() As Variant
    Dim col As Object: Set col = WmiQuery("SELECT Name, DisplayName, State, StartMode FROM Win32_Service")
    Dim cnt As Long: cnt = 0: Dim it As Object
    For Each it In col: cnt = cnt + 1: Next
    Dim a() As Variant: ReDim a(1 To cnt + 1, 1 To 4)
    a(1, 1) = "Name": a(1, 2) = "DisplayName": a(1, 3) = "State": a(1, 4) = "StartMode"
    Dim i As Long: i = 2
    For Each it In col
        a(i, 1) = it.Name
        a(i, 2) = it.DisplayName
        a(i, 3) = it.State
        a(i, 4) = it.StartMode
        i = i + 1
    Next
    ServiceTable = a
End Function
VB

重要ポイントの深掘り

ネットワークやサービスは環境依存で取得失敗が起きやすい領域です。値がNullのときは空文字で受け止め、テーブル化しても崩れないようにしておくと現場で止まりません。


便利関数:WMI時刻の変換・台数のカウント・フィルタ

WMI時刻(yyyymmddHHMMSS.******±TZ)をISOへ

' ModWmiTime.bas
Option Explicit

Public Function WmiTimeToIso(ByVal s As String) As String
    If Len(s) >= 14 Then
        WmiTimeToIso = Left$(s, 4) & "-" & Mid$(s, 5, 2) & "-" & Mid$(s, 7, 2) & " " & Mid$(s, 9, 2) & ":" & Mid$(s, 11, 2) & ":" & Mid$(s, 13, 2)
    End If
End Function

Public Function LastBootUpTimeIso() As String
    Dim it As Object
    For Each it In WmiQuery("SELECT LastBootUpTime FROM Win32_OperatingSystem")
        LastBootUpTimeIso = WmiTimeToIso(it.LastBootUpTime): Exit For
    Next
End Function
VB

テーブルフィルタ(状態で絞る例)

' ModFilter.bas
Option Explicit

Public Function FilterServicesByState(ByVal state As String) As Variant
    Dim col As Object: Set col = WmiQuery("SELECT Name, State FROM Win32_Service WHERE State='" & state & "'")
    Dim cnt As Long: cnt = 0: Dim it As Object
    For Each it In col: cnt = cnt + 1: Next
    Dim a() As Variant: ReDim a(1 To cnt + 1, 1 To 2)
    a(1, 1) = "Name": a(1, 2) = "State"
    Dim i As Long: i = 2
    For Each it In col
        a(i, 1) = it.Name
        a(i, 2) = it.State
        i = i + 1
    Next
    FilterServicesByState = a
End Function
VB

レポート生成テンプレート:一括収集→シートへ書く

入口と書き出し(貼ってすぐ動く)

' ModWmiReport.bas
Option Explicit

Public Sub Run_WmiReport()
    On Error GoTo EH
    AppEnter "WMI Report"

    Dim ws As Worksheet
    On Error Resume Next
    Set ws = ThisWorkbook.Worksheets("WMI")
    On Error GoTo 0
    If ws Is Nothing Then
        Set ws = ThisWorkbook.Worksheets.Add
        ws.Name = "WMI"
    End If
    ws.Cells.Clear

    Dim row As Long: row = 1
    ws.Cells(row, 1).Value = "OS":           ws.Cells(row, 2).Value = OsCaption(): row = row + 1
    ws.Cells(row, 1).Value = "CPU":          ws.Cells(row, 2).Value = CpuName(): row = row + 1
    ws.Cells(row, 1).Value = "Total RAM(GB)":ws.Cells(row, 2).Value = TotalRamGB(): row = row + 1
    ws.Cells(row, 1).Value = "LastBootUp":   ws.Cells(row, 2).Value = LastBootUpTimeIso(): row = row + 2

    Dim drives As Variant: drives = DriveTable()
    ws.Range("A" & row).Resize(UBound(drives, 1), UBound(drives, 2)).Value = drives
    row = row + UBound(drives, 1) + 1

    Dim ips As String: ips = IPv4List()
    ws.Cells(row, 1).Value = "IPv4": ws.Cells(row, 2).Value = ips: row = row + 2

    Dim svcs As Variant: svcs = ServiceTable()
    ws.Range("A" & row).Resize(UBound(svcs, 1), UBound(svcs, 2)).Value = svcs

    ws.Columns.AutoFit
    AppLeave
    MsgBox "WMIレポートを作成しました。", vbInformation
    Exit Sub
EH:
    AppLeave
    MsgBox "取得に失敗しました: " & Err.Description, vbExclamation
End Sub
VB

共通枠(描画・イベント抑止と復帰)

' ModApp.bas
Option Explicit
Public Sub AppEnter(Optional ByVal status As String = "")
    Application.ScreenUpdating = False
    Application.EnableEvents = False
    Application.DisplayAlerts = False
    If Len(status) > 0 Then Application.StatusBar = status
End Sub
Public Sub AppLeave()
    Application.StatusBar = False
    Application.DisplayAlerts = True
    Application.EnableEvents = True
    Application.ScreenUpdating = True
End Sub
VB

重要ポイントの深掘り

「配列へまとめて→Resizeで一括書き込み」がExcelを固めないコツです。セルに1件ずつ書くと遅くなるため、必ず配列I/Oを使いましょう。開始・終了枠で描画とイベントを止めると、数千行でも快適に終わります。


実務で効くトラブルシュート活用例

遅い・不安定の切り分けに使う視点

  • 低容量ドライブ(Free(GB)が閾値未満)を特定することで、保存失敗やフリーズの予兆を把握できます。
  • RAMが少ない端末(Total RAMが小さい)で巨大ブックを扱っていないか確認できます。
  • LastBootUpが古い端末は再起動の提案が合理的です。
  • IPv4が空欄ならネットワーク切断の可能性。サービス一覧で自動起動なのに停止中のものを見つけると、関連機能の不具合原因が絞れます。

より深い取得:イベントログ・プリンタ・BIOS・バッテリ(必要に応じて)

イベントログ(最近のエラーのみ抜粋)

' ModWmiEvent.bas
Option Explicit

Public Function RecentSystemErrors(Optional ByVal takeN As Long = 20) As Variant
    Dim q As String
    q = "SELECT TimeGenerated, SourceName, EventIdentifier FROM Win32_NTLogEvent WHERE Logfile='System' AND Type='Error'"
    Dim col As Object: Set col = WmiQuery(q)
    Dim buf() As Variant: ReDim buf(1 To takeN + 1, 1 To 3)
    buf(1, 1) = "Time": buf(1, 2) = "Source": buf(1, 3) = "EventId"
    Dim i As Long: i = 2, it As Object
    For Each it In col
        If i > UBound(buf, 1) Then Exit For
        buf(i, 1) = WmiTimeToIso(it.TimeGenerated)
        buf(i, 2) = it.SourceName
        buf(i, 3) = it.EventIdentifier
        i = i + 1
    Next
    RecentSystemErrors = buf
End Function
VB

プリンタ一覧

' ModWmiPrinter.bas
Option Explicit

Public Function PrinterTable() As Variant
    Dim col As Object: Set col = WmiQuery("SELECT Name, Default, WorkOffline FROM Win32_Printer")
    Dim cnt As Long: cnt = 0: Dim it As Object
    For Each it In col: cnt = cnt + 1: Next
    Dim a() As Variant: ReDim a(1 To cnt + 1, 1 To 3)
    a(1, 1) = "Name": a(1, 2) = "Default": a(1, 3) = "Offline"
    Dim i As Long: i = 2
    For Each it In col
        a(i, 1) = it.Name
        a(i, 2) = it.Default
        a(i, 3) = it.WorkOffline
        i = i + 1
    Next
    PrinterTable = a
End Function
VB

落とし穴と対策(深掘り)

権限・ポリシーで失敗する

企業環境ではWMIクエリが制限されることがあります。失敗時はOn Errorのスコープを最小に、空欄返しでレポートを継続。どうしても必要ならPowerShell(Get-WmiObject / Get-CimInstance)へ委譲し、結果CSVをVBAで読む設計が堅牢です。

遅い・タイムアウトする

一回の実行で大量の行を取るクエリは重くなります。列選択を絞る、WHEREで対象を限定する、巨大クラス(NTLogEventなど)は件数をtakeNで抑えるなど、クエリ自体を軽くしましょう。

Nullと型の扱い

WMIはNullがよく返ります。文字列へ取り込む前にIsNullをチェックし、数値はCDblで明示変換。配列へ詰める際に空文字や0で統一しておくと書き込み時に崩れません。


まとめ:Late Binding+配列I/O+一括クエリで「速い・止まらない」WMIレポートを作る

GetObjectでWMIに接続し、必要列をまとめてSELECTして結果を配列へ一括格納、シートへResize書き込み。これだけでOS・CPU・メモリ・ドライブ・ネット・サービスの「環境台帳」が数秒で作れます。

タイトルとURLをコピーしました