VBAでWMIのWin32_LogicalDiskクラスからリモートPCのディスク空き容量を照会する

Tech

本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。

VBAでWMIのWin32_LogicalDiskクラスからリモートPCのディスク空き容量を照会する

【背景と目的】

複数PCのディスク容量調査を手動で行うと多大な工数がかかります。本稿では、VBAとWMI接続のタイムアウトやエラーを考慮しつつ、高速かつ一括で情報を収集する仕組みを構築します。

【処理フロー図】

graph TD
A["処理開始"] --> B["画面更新・自動計算の停止"]
B --> C["対象PC名のリストを走査"]
C --> D["WMI接続の試行"]
D -->|接続失敗| E["配列に接続エラーを記録"]
D -->|接続成功| F["Win32_LogicalDisk情報のクエリ実行"]
F --> G["ローカルディスク情報の抽出"]
G --> H["容量変換と計算(GB単位化)"]
H --> I["配列に取得結果を格納"]
E --> J["次PCの処理へループ"]
I --> J
J -->|全PC完了| K["シートへ配列情報を一括書き出し"]
K --> L["画面更新・自動計算の再開"]
L --> M["処理終了"]

【実装:VBAコード】

Option Explicit

' ==============================================================================
' 処理名:GetRemoteDiskSpace
' 概要  :リモートPCの「Win32_LogicalDisk」からローカルディスク情報を取得し、
'         アクティブシートに一覧出力します。
' 備考  :参照設定不要(Late Binding)、高速書き込み、エラーハンドリング実装
' ==============================================================================
Sub GetRemoteDiskSpace()
    ' Excel描画・自動計算の停止(処理の高速化)
    On Error GoTo ErrorHandler
    With Application
        .ScreenUpdating = False
        .Calculation = xlCalculationManual
        .EnableEvents = False
    End With

    Dim ws As Worksheet
    Set ws = ActiveSheet

    ' A列にPC名が入力されていると仮定(2行目からスタート)
    Dim lastRow As Long
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row

    If lastRow < 2 Then
        MsgBox "A列の2行目以降に対象のPC名を入力してください。", vbExclamation, "確認"
        GoTo CleanExit
    End If

    ' 結果を格納する一時二次元配列(セルへの都度書き込みによる遅延を防止)
    ' 列構成:[PC名, ドライブ, 空き容量(GB), 総容量(GB), 使用率(%), 状態]
    Dim resultData() As Variant
    ReDim resultData(1 To lastRow - 1, 1 To 6)

    Dim i As Long
    Dim pcName As String

    For i = 2 To lastRow
        pcName = Trim(ws.Cells(i, 1).Value)
        resultData(i - 1, 1) = pcName

        If pcName = "" Then
            resultData(i - 1, 6) = "PC名未入力"
            GoTo NextPC
        End If

        ' WMIオブジェクトの定義
        Dim objWMIService As Object
        Dim colDisks As Object
        Dim objDisk As Object
        Dim wmiQuery As String

        ' 接続エラーを個別に処理するため、一時的にエラーハンドリングを無効化
        On Error Resume Next

        ' リモートPCのWMI namespace(CIMV2)へ接続
        Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & pcName & "\root\cimv2")

        If Err.Number <> 0 Then
            resultData(i - 1, 6) = "接続失敗 (Error: " & Err.Description & ")"
            Err.Clear
            On Error GoTo ErrorHandler
            GoTo NextPC
        End If
        On Error GoTo ErrorHandler

        ' DriveType = 3 (ローカルハードディスクのみ)をフィルタリングするクエリ
        wmiQuery = "SELECT DeviceID, FreeSpace, Size FROM Win32_LogicalDisk WHERE DriveType = 3"
        Set colDisks = objWMIService.ExecQuery(wmiQuery)

        Dim diskInfoCount As Long
        diskInfoCount = 0

        ' 各ディスク情報を取得(代表として最初のローカルディスク [Cドライブ等] を取得)
        For Each objDisk In colDisks
            Dim freeBytes As Double
            Dim totalBytes As Double

            ' Null値(空値)による型ミスマッチの防止
            freeBytes = IIf(IsNull(objDisk.FreeSpace), 0, CDbl(objDisk.FreeSpace))
            totalBytes = IIf(IsNull(objDisk.Size), 0, CDbl(objDisk.Size))

            resultData(i - 1, 2) = objDisk.DeviceID ' ドライブ文字 (例: "C:")

            ' バイトをGB(ギガバイト)に換算(1024^3 = 1,073,741,824)して小数点以下第2位で丸める
            resultData(i - 1, 3) = Round(freeBytes / 1073741824, 2)
            resultData(i - 1, 4) = Round(totalBytes / 1073741824, 2)

            If totalBytes > 0 Then
                resultData(i - 1, 5) = Round(((totalBytes - freeBytes) / totalBytes) * 100, 1) & "%"
            Else
                resultData(i - 1, 5) = "N/A"
            End If

            resultData(i - 1, 6) = "取得成功"
            diskInfoCount = diskInfoCount + 1
            Exit For ' 本サンプルでは簡易化のため、1つ目の代表ドライブ取得時点でループを出ます
        Next objDisk

        If diskInfoCount = 0 Then
            resultData(i - 1, 6) = "ローカルディスク非検出"
        End If

NextPC:
    Next i

    ' 結果出力セクションのヘッダー作成
    ws.Range("B1:G1").Value = Array("ドライブ", "空き容量(GB)", "総容量(GB)", "使用率", "ステータス")

    ' 配列からシートへ一括書き出し(処理速度向上の要)
    ws.Range("B2").Resize(UBound(resultData, 1), UBound(resultData, 2)).Value = resultData

    MsgBox "リモートPCのディスク容量照会が完了しました。", vbInformation, "完了"

CleanExit:
    ' 画面更新・自動計算の設定を復元(異常終了時も必ず通過させる)
    With Application
        .ScreenUpdating = True
        .Calculation = xlCalculationAutomatic
        .EnableEvents = True
    End With
    Exit Sub

ErrorHandler:
    MsgBox "予期せぬエラーが発生しました。" & vbCrLf & "エラー内容:" & Err.Description, vbCritical, "システムエラー"
    Resume CleanExit
End Sub

【技術解説】

  1. WMIクラス Win32_LogicalDisk の利用 Windowsが標準搭載するWMIを利用し、特定PCのドライブ種別、全体の物理サイズ、および現在の空き容量をネットワーク越しに取得します。DriveType = 3 で抽出することで、ネットワーク共有フォルダや仮想ドライブ、DVD-ROMなどを排他し、実体のあるローカルHDD/SSDのみを正確に補足します。

  2. Late Bindingによる参照設定フリー GetObject関数を用いた遅延結合により、VBA実行環境に左右されずコードが動きます。特定のActiveXや参照ライブラリの事前登録が不要になるため、別端末への横展開が極めて容易です。

  3. 二次元配列を活用した一括転記による極小負荷化 セルの値をループ内で都度書き替えるとExcelの描画処理がボトルネックとなります。データをすべてメモリ上の二次元配列(resultData)に蓄積し、最後に Range.Resize を使って一括展開することで、数百台規模のPCであっても一瞬でデータ書き込みが完了します。

【注意点と運用】

  • 管理者権限の確保(最も重要) リモート接続先のWMIへ問い合わせるには、呼び出し元ユーザーが接続先のPCに対する管理者権限(Administrator権限等)を保持している必要があります。ドメイン環境下や適切なアカウントポリシーが共有されていることが前提となります。

  • ファイアウォール(DCOM/WMIポート)の疎通 リモートPC側で「WMI(DCOM受信)」ルールがブロックされていると、接続時にフリーズまたは「リモートサーバーが応答しません」等のエラーが返ります。

  • タイムアウトによるExcelのフリーズ対策 応答のない(電源が切れている)PCに対してWMI接続を行うと、タイムアウトを待つ最大数十秒間、VBAの処理全体が一時停止(応答なし)になります。これを防ぐためには、WMI接続前に Ping のコマンドを発行し、疎通が取れたPCにのみWMI接続を試行するロジックを追加することが実務上効果的です。

【まとめ】

  • 権限設定の確認:ドメイン管理下または双方のローカルに同一管理者パスワードが存在する環境下で実行する。

  • 配列化による省力化:PC台数が多い時こそ、セル書き込みを最小化する配列技術が効力を発揮する。

  • エラー処理の分離:個々の接続障害が全体処理を止めないよう、On Error Resume Next を特定の行のみに限定適用して対処する。

ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

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