VBAからWMI/CIMを利用したPCハードウェア情報取得の最適化

Tech

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

VBAからWMI/CIMを利用したPCハードウェア情報取得の最適化

背景と要件

ビジネス環境において、PCのハードウェア情報を効率的に取得・管理するニーズは多岐にわたります。例えば、資産管理台帳の自動更新、ソフトウェア導入前のPCスペック確認、トラブルシューティング時の初期情報収集などが挙げられます。手作業での情報収集は時間がかかり、ヒューマンエラーのリスクも伴います。

Windows Management Instrumentation (WMI) は、Windows環境の管理データを標準化された方法で提供する技術であり、Common Information Model (CIM) はWMIの基盤となる情報モデルです。WMIを利用することで、OS、ハードウェア、アプリケーションに関する詳細な情報をスクリプトやプログラムから取得できます。VBA(Visual Basic for Applications)は、ExcelやAccessといったMicrosoft Officeアプリケーションに組み込まれており、これらのツールからWMIを活用することで、既存の業務フローに組み込みやすい形でPCハードウェア情報取得の自動化を実現できます。 、VBAからWMI/CIMを利用してPCのハードウェア情報を取得する具体的な手法、特に実務レベルで再現可能なコード例と、大規模データ処理における性能最適化について詳しく解説します。外部ライブラリに依存せず、VBAと標準のCOMオブジェクト、必要に応じてWin32 APIのみを使用することを前提とします。

設計

WMI/CIMの基本概念とVBAからのアクセス

WMIは、GetObject("winmgmts:\\.\root\cimv2") を用いてSWbemServicesオブジェクトに接続することで利用を開始します。ここで、\\.\ はローカルPCを、root\cimv2 はWMIの標準的な名前空間を示します。このサービスオブジェクトを通じて、WMI Query Language (WQL) を使用して情報を問い合わせます。WQLはSQLに似た構文を持ち、特定のWMIクラスからプロパティを選択して取得します。

主要なWMIクラス(ハードウェア情報取得用):

  • Win32_Processor: CPUの名称、コア数、論理プロセッサ数、最大クロック速度など。

  • Win32_PhysicalMemory: 物理メモリの容量、速度、メーカー、部品番号など。各DIMM(メモリモジュール)ごとに情報を提供します。

  • Win32_DiskDrive: ディスクドライブのモデル、サイズ、メディアタイプ、シリアル番号など。

  • Win32_OperatingSystem: オペレーティングシステムの名称、アーキテクチャ、総物理メモリ量など。

  • Win32_ComputerSystem: コンピュータのメーカー、モデル、名称、総物理メモリ量など、システム全体の概要情報。

処理の流れ

WMIを利用したハードウェア情報取得の一般的な処理フローは以下の通りです。

graph TD
    A["開始"] -->|処理開始| B{"WMIサービス接続"};
    B -->|サービス取得| C["WMIネームスペース選択
root\cimv2"]; C -->|情報対象選択| D{"ハードウェア情報クエリ選択"}; D -->|CPU| D1[Win32_Processor]; D -->|物理メモリ| D2[Win32_PhysicalMemory]; D -->|ディスクドライブ| D3[Win32_DiskDrive]; D1 -->|WQL作成| E{"WQLクエリ実行"}; D2 -->|WQL作成| E; D3 -->|WQL作成| E; E -->|クエリ結果| F["SWbemObjectSet取得"]; F -->|オブジェクトループ| G{"取得データ抽出・加工"}; G -->|データバッファリング| H["VBA内部配列へ格納"]; H -->|最適化設定| I{"VBA性能最適化適用
(画面更新停止,計算モード手動)"}; I -->|結果出力| J["Excel/Accessシート/テーブルへ一括出力"]; J -->|処理完了| K["終了"];

実装

ここでは、Excelを対象とした具体的なVBAコードを2つのシナリオで提供します。Accessでも同様のロジックで利用可能です。

コード1: 基本的なPC概要情報の取得とExcelシートへの出力

このコードは、CPU名、コア数、物理メモリ合計、OS情報、システムモデルといった基本的なPC情報をExcelシートの特定のセルに出力します。

Option Explicit

'// WMI (Windows Management Instrumentation) を使用してPCハードウェア情報を取得する関数
Public Sub GetHardwareSummaryToExcel()
    ' 性能最適化のため、画面更新とイベントを停止
    Call OptimizeVBA_Start(False) ' False: 計算モードは自動のまま

    Dim objWMIService As Object
    Dim colItems As Object
    Dim objItem As Object
    Dim ws As Worksheet
    Dim totalMemoryBytes As Double
    Dim memoryGb As Double
    Dim rowNum As Long
    Dim cpuInfo As String
    Dim osInfo As String
    Dim systemInfo As String

    Set ws = ThisWorkbook.Sheets("Sheet1") ' 出力先のシート名
    rowNum = 1 ' 開始行

    On Error GoTo ErrorHandler

    ' WMIサービスに接続
    Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")

    '--- CPU情報 ---
    Set colItems = objWMIService.ExecQuery("SELECT Name, NumberOfCores, NumberOfLogicalProcessors FROM Win32_Processor")
    For Each objItem In colItems
        cpuInfo = "CPU名: " & objItem.Name & vbLf & _
                  "物理コア数: " & objItem.NumberOfCores & vbLf & _
                  "論理プロセッサ数: " & objItem.NumberOfLogicalProcessors
        Exit For ' 最初のCPU情報のみ取得 (通常は1つ)
    Next
    ws.Cells(rowNum, 1).Value = "CPU情報"
    ws.Cells(rowNum, 2).Value = cpuInfo
    rowNum = rowNum + 1

    '--- 物理メモリ合計 ---
    totalMemoryBytes = 0
    Set colItems = objWMIService.ExecQuery("SELECT Capacity FROM Win32_PhysicalMemory")
    For Each objItem In colItems
        totalMemoryBytes = totalMemoryBytes + CDbl(objItem.Capacity)
    Next
    memoryGb = totalMemoryBytes / (1024 ^ 3) ' バイトをGBに変換
    ws.Cells(rowNum, 1).Value = "物理メモリ合計"
    ws.Cells(rowNum, 2).Value = Format(memoryGb, "0.00") & " GB"
    rowNum = rowNum + 1

    '--- OS情報 ---
    Set colItems = objWMIService.ExecQuery("SELECT Caption, OSArchitecture FROM Win32_OperatingSystem")
    For Each objItem In colItems
        osInfo = "OS: " & objItem.Caption & vbLf & _
                 "アーキテクチャ: " & objItem.OSArchitecture
        Exit For
    Next
    ws.Cells(rowNum, 1).Value = "OS情報"
    ws.Cells(rowNum, 2).Value = osInfo
    rowNum = rowNum + 1

    '--- システムモデル情報 ---
    Set colItems = objWMIService.ExecQuery("SELECT Manufacturer, Model, Name FROM Win32_ComputerSystem")
    For Each objItem In colItems
        systemInfo = "メーカー: " & objItem.Manufacturer & vbLf & _
                     "モデル: " & objItem.Model & vbLf & _
                     "PC名: " & objItem.Name
        Exit For
    Next
    ws.Cells(rowNum, 1).Value = "システム情報"
    ws.Cells(rowNum, 2).Value = systemInfo
    rowNum = rowNum + 1

    MsgBox "PCハードウェア情報の取得が完了しました。", vbInformation
    GoTo CleanUp

ErrorHandler:
    MsgBox "エラーが発生しました: " & Err.Description, vbCritical
CleanUp:
    ' オブジェクトの解放
    Set objItem = Nothing
    Set colItems = Nothing
    Set objWMIService = Nothing
    Set ws = Nothing

    ' 性能最適化設定を元に戻す
    Call OptimizeVBA_End
End Sub

'// VBAの性能最適化を開始するサブルーチン
Private Sub OptimizeVBA_Start(Optional ByVal ManualCalculation As Boolean = True)
    Application.ScreenUpdating = False
    Application.EnableEvents = False
    If ManualCalculation Then
        Application.Calculation = xlCalculationManual
    End If
End Sub

'// VBAの性能最適化を終了し、元の設定に戻すサブルーチン
Private Sub OptimizeVBA_End()
    Application.ScreenUpdating = True
    Application.EnableEvents = True
    Application.Calculation = xlCalculationAutomatic
End Sub

コード2: 複数ディスクドライブの詳細情報取得とExcel表への出力

このコードは、PCに接続されているすべての物理ディスクドライブのモデル、サイズ、シリアル番号などの詳細情報を取得し、Excelシートに表形式で出力します。配列バッファリングを適用し、パフォーマンスを向上させています。

Option Explicit

'// WMI (Windows Management Instrumentation) を使用してPCのディスクドライブ情報を取得し、Excelにテーブル出力するサブルーチン
Public Sub GetDiskDriveInfoToExcelTable()
    ' 性能最適化のため、画面更新と計算モードを停止
    Call OptimizeVBA_Start(True) ' True: 計算モードを手動に設定

    Dim objWMIService As Object
    Dim colItems As Object
    Dim objItem As Object
    Dim ws As Worksheet
    Dim data() As Variant
    Dim i As Long, j As Long
    Dim rowCount As Long

    Set ws = ThisWorkbook.Sheets("Sheet2") ' 出力先のシート名
    ws.Cells.ClearContents ' 既存の内容をクリア

    On Error GoTo ErrorHandler

    ' WMIサービスに接続
    Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")

    '--- ディスクドライブ情報 ---
    Set colItems = objWMIService.ExecQuery("SELECT Caption, Model, Size, MediaType, SerialNumber FROM Win32_DiskDrive")

    ' ヘッダー行を準備
    ReDim data(1 To colItems.Count + 1, 1 To 5) ' +1はヘッダー用
    data(1, 1) = "デバイス名"
    data(1, 2) = "モデル"
    data(1, 3) = "サイズ (GB)"
    data(1, 4) = "メディアタイプ"
    data(1, 5) = "シリアル番号"

    i = 1 ' データ行のインデックス
    For Each objItem In colItems
        i = i + 1
        data(i, 1) = objItem.Caption
        data(i, 2) = objItem.Model
        data(i, 3) = Format(CDbl(objItem.Size) / (1024 ^ 3), "0.00") ' バイトをGBに変換
        data(i, 4) = objItem.MediaType
        data(i, 5) = objItem.SerialNumber
    Next

    rowCount = i ' 実際にデータが格納された行数 (ヘッダー含む)

    ' 配列の内容を一括でシートに出力
    If rowCount > 1 Then ' ヘッダーとデータが存在する場合
        ws.Range("A1").Resize(rowCount, UBound(data, 2)).Value = data
        ' ヘッダーの装飾
        With ws.Range("A1").Resize(1, UBound(data, 2))
            .Font.Bold = True
            .Interior.Color = RGB(217, 217, 217) ' 薄いグレー
            .Borders.LineStyle = xlContinuous
        End With
        ws.Cells.EntireColumn.AutoFit ' 列幅を自動調整
    Else
        ws.Cells(1, 1).Value = "ディスクドライブ情報が見つかりませんでした。"
    End If

    MsgBox "ディスクドライブ情報の取得が完了しました。", vbInformation
    GoTo CleanUp

ErrorHandler:
    MsgBox "エラーが発生しました: " & Err.Description, vbCritical
CleanUp:
    ' オブジェクトの解放
    Set objItem = Nothing
    Set colItems = Nothing
    Set objWMIService = Nothing
    Set ws = Nothing

    ' 性能最適化設定を元に戻す
    Call OptimizeVBA_End
End Sub

Win32 APIの利用について

今回の目的であるPCハードウェア情報の取得においては、WMIが高度に抽象化されたインターフェースを提供しており、ほとんどの情報をWMI経由で取得できます。そのため、直接Win32 APIをDeclare PtrSafeで宣言して使用する必要は稀です。WMIはCOMオブジェクトとしてVBAから利用できるため、外部ライブラリとして扱われることはありません。

ただし、WMIで取得できないような非常に低レベルなハードウェア情報(例:特定のレジスタ値、USBデバイスの生データなど)や、WMIクエリよりもパフォーマンスが要求される場面では、Win32 APIの利用を検討する価値があります。その場合、Declare PtrSafe Function GetPrivateProfileString Lib "kernel32.dll" ... のように、利用するDLLと関数を明示的に宣言する必要がありますが、これは高度なプログラミングスキルとメモリ管理に関する深い理解が求められます。本記事の範囲では、WMIで十分対応可能です。

性能チューニング

VBAでWMIから取得したデータをExcelシートに出力する際、以下の最適化手法を適用することで、特にデータ量が多い場合に大幅な性能向上が期待できます。

  1. 画面更新とイベントの停止:

    • Application.ScreenUpdating = False

    • Application.EnableEvents = False VBAがExcelの画面を更新したり、イベントを処理したりするオーバーヘッドをなくします。処理終了後にTrueに戻すのを忘れないでください。これにより、処理時間が50%から90%短縮されることがあります。

  2. 計算モードの手動設定:

    • Application.Calculation = xlCalculationManual Excelの自動再計算を停止します。大量の数式が含まれるシートにデータを書き込む際に特に有効で、xlCalculationAutomaticに戻すまで計算は行われません。これにより、数式が多い場合、処理時間が数倍から数十倍向上することもあります。
  3. 配列バッファリングによる一括書き込み: WMIから取得した各データを直接セルに書き込むのではなく、一旦VBAの内部配列に格納し、最後にその配列の内容をExcelの範囲に一括で書き込みます。

    • 非最適化コードの例: ws.Cells(i, j).Value = objItem.Property (ループ内でセルアクセス)

    • 最適化コードの例: data(i, j) = objItem.Property (配列に格納)→ ws.Range("A1").Resize(rowCount, colCount).Value = data (一括書き込み) これは、ExcelとVBA間のI/Oオーバーヘッドを劇的に削減するため、大規模データ(例: 1,000行以上のデータ)の場合、処理速度が10倍から100倍向上する可能性があります。

上記のコード例では、これらの最適化手法(OptimizeVBA_Start, OptimizeVBA_Endサブルーチン、およびディスクドライブ情報の配列バッファリング)を適用しています。これらの手法は、WMIからのデータ取得そのものの速度には影響しませんが、取得したデータをOfficeアプリケーションに効率的に反映させる上で不可欠です。

検証

コードの動作確認は以下の手順で行います。

  1. VBAエディタの起動: Excelブックを開き、Alt + F11キーを押してVBAエディタを起動します。

  2. モジュールの挿入: プロジェクトエクスプローラーでVBAProject (your_workbook_name)を右クリックし、「挿入」→「標準モジュール」を選択します。

  3. コードの貼り付け: 新しいモジュールに上記「コード1」と「コード2」のVBAコードを貼り付けます。

  4. シートの準備:

    • 「コード1」用: Sheet1という名前のシートが存在することを確認します。存在しない場合は作成してください。

    • 「コード2」用: Sheet2という名前のシートが存在することを確認します。存在しない場合は作成してください。

  5. 実行:

    • GetHardwareSummaryToExcelサブルーチンを選択し、F5キーを押すか、ツールバーの「実行」ボタンをクリックします。Sheet1にPC概要情報が出力されることを確認します。

    • GetDiskDriveInfoToExcelTableサブルーチンを選択し、同様に実行します。Sheet2にディスクドライブ情報がテーブル形式で出力されることを確認します。

  6. エラーハンドリングの確認: WMIサービスが利用できない、または権限がない場合など、エラーメッセージが適切に表示されるか確認します。

運用

WMIを利用したPCハードウェア情報取得を運用する際には、以下の点を考慮してください。

  • 定期実行: タスクスケジューラと連携し、特定の日時やイベントでVBAマクロを自動実行することで、情報の定期的な更新が可能です。

  • エラーログ: 取得失敗時やエラー発生時に、エラーメッセージやタイムスタンプをログファイルや専用シートに記録する機能を実装することで、問題の特定と対処が容易になります。

  • セキュリティ: WMIは管理者権限で実行されるため、マクロの実行環境には十分なセキュリティ対策を講じる必要があります。また、信頼できるソースからのVBAコードのみを使用し、マクロのセキュリティ設定を適切に管理します。

  • データ保護: 取得した個人情報や機密性の高いハードウェア情報(例: シリアル番号)は、適切なアクセス制限の下で管理してください。

落とし穴

VBAからWMI/CIMを利用する際には、いくつかの潜在的な落とし穴があります。

  • 権限の問題: WMIクエリは、通常、管理者権限が必要です。VBAマクロが管理者権限のないユーザーによって実行される場合、アクセス拒否エラーが発生することがあります。

  • WMIサービスの可用性: WMIサービスが停止している、破損している、またはファイアウォールによってブロックされている場合、クエリは失敗します。

  • リモートPCからの取得: 本記事はローカルPCを対象としていますが、リモートPCの情報を取得する際には、認証情報の設定、ファイアウォール規則、DCOMの設定など、追加の複雑な設定が必要です。

  • データ型の不一致: WMIから取得されるデータはCOM Variant型で返されることが多く、VBAの特定のデータ型(例: Long, Double, String)に変換する際に、型変換エラーが発生しないよう注意が必要です。特に数値データ(例: Capacity, Size)はCDbl()などで明示的に変換すると安全です。

  • NULL値の扱い: WMIプロパティの中にはNULL値を返すものがあります。VBAでNULL値を扱うとエラーになる場合があるため、IsNULL()関数でチェックするか、エラーハンドリングを適切に記述する必要があります。

まとめ

VBAからWMI/CIMを利用することで、PCのハードウェア情報を効率的かつプログラム的に取得し、ExcelやAccessといったOfficeアプリケーションでの管理業務を大幅に自動化できます。GetObjectでのWMIサービス接続、WQLによるクラスからの情報抽出、そしてVBAの性能最適化技術(画面更新・イベント停止、計算モード変更、配列バッファリング)を組み合わせることで、実用レベルで高速かつ安定したソリューションを構築することが可能です。

本記事で提供したコード例と解説が、あなたのOffice自動化プロジェクトの一助となることを願っています。

実行手順とロールバック方法

実行手順

  1. Excelブックの準備:

    • 新しいExcelブックを作成し、任意で名前を付けて保存します(例: HardwareInfoTool.xlsm)。

    • このブックには、マクロを有効にする必要があります。保存時に「Excel マクロ有効ブック (*.xlsm)」形式を選択してください。

    • シート名を「Sheet1」と「Sheet2」に変更するか、VBAコード内のシート名を実際のシート名に合わせてください。

  2. VBAエディタの起動:

    • Excelを開いた状態でAlt + F11キーを押して、VBA(Visual Basic for Applications)エディタを起動します。
  3. 標準モジュールの挿入:

    • VBAエディタの左側にある「プロジェクトエクスプローラー」ペインで、VBAProject (HardwareInfoTool.xlsm)(ブック名)を右クリックします。

    • コンテキストメニューから「挿入」→「標準モジュール」を選択します。新しいモジュールが作成されます。

  4. コードの貼り付け:

    • 本記事の「コード1: 基本的なPC概要情報の取得とExcelシートへの出力」と「コード2: 複数ディスクドライブの詳細情報取得とExcel表への出力」のVBAコード全体を、この新しい標準モジュールにコピー&ペーストします。

    • Option ExplicitからEnd Subまですべてを貼り付けてください。

  5. マクロの実行:

    • VBAエディタ内で、実行したいSubプロシージャ(例: GetHardwareSummaryToExcelまたはGetDiskDriveInfoToExcelTable)のどこかにカーソルを置きます。

    • ツールバーの「実行」ボタン(緑色の再生アイコン)をクリックするか、F5キーを押します。

    • マクロが実行され、Sheet1またはSheet2にハードウェア情報が出力されます。実行完了後、「PCハードウェア情報の取得が完了しました。」などのメッセージボックスが表示されます。

ロールバック方法

万一、マクロの動作に問題があった場合や、元に戻したい場合は以下の手順でロールバックできます。

  1. Excelブックの閉じる:

    • マクロを実行したExcelブックを保存せずに閉じます。これにより、マクロによるシートへの変更が破棄されます。

    • もし保存してしまった場合でも、後述のモジュール削除やシート内容のクリアで対応可能です。

  2. VBAモジュールの削除:

    • VBAエディタを再度起動します(Alt + F11)。

    • プロジェクトエクスプローラーで、先ほどコードを貼り付けた標準モジュール(例: Module1)を右クリックします。

    • Module1 の解放」を選択します。確認メッセージが表示されたら、「いいえ」(エクスポートしない)を選択し、モジュールを削除します。これにより、マクロコード自体がブックから削除されます。

  3. シート内容のクリア:

    • マクロによって内容が書き換えられたシート(Sheet1Sheet2)の内容を、手動でクリアしたり、以前のバックアップから復元したりします。

    • このソリューションでは既存のデータが上書きされる可能性があるため、実行前にシートのバックアップを取ることを推奨します。

これらの手順により、マクロの追加や変更を簡単に元に戻し、元の状態に復旧できます。

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

コメント

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