style_prompt
隠蔽メタデータ
業務カテゴリ: VBA/WMI (Windows Management Instrumentation) 対象システム: Microsoft Excel/Access VBA 最適化手法: Late Binding, 配列処理, エラーハンドリング
難易度: 専門家向け (DCOM設定知識要求)
開示バッジ
本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。
VBAとWMIで実現するリモートPC管理:非対話型でのプロセス起動とインストール済みアプリケーションの監査
【背景と目的】
数多のクライアントPCの資産管理や緊急対応において、リモートデスクトップを使わずに情報を収集したり、特定のプログラムを実行したりする必要に直面します。このとき、従来のファイル共有やレジストリ操作では認証やアクセス権の問題、処理速度の低下が発生しがちです。
本ソリューションは、VBAからWMI(Windows Management Instrumentation)を介してターゲットPCに接続することで、一元的な情報取得とプロセス制御をセキュアかつ効率的に実現することを目的とします。特に、大量のPCを監査する場合に発生する「タイムアウトや認証エラー」への対策として、詳細なエラー処理を組み込みます。
【処理フロー図】
リモートPC管理に必要な接続とクエリ実行のフローです。
graph TD
A["開始: リモートPC名と認証情報設定"] --> B{"WMI接続の試行"};
B -- 成功 --> C["WMIサービス取得 (SWbemServices)"];
C --> D["監査クエリ (Win32_Product) 実行"];
D --> E["結果データを配列へ格納"];
E --> F["リモートプロセス起動 (Win32_Process.Create)"];
B -- 失敗 --> H["エラー処理/ログ記録"];
F --> G["結果確認とシートへの出力"];
G --> Z["終了"];
H --> Z;
【実装:VBAコード】
複数のリモートPC(ターゲットリスト)に対してWMI接続を試み、インストールされているアプリケーションの一覧を取得し、さらに特定のコマンドを起動する統合プロシージャです。Late Bindingを使用するため、参照設定は不要です。
Option Explicit
' ******************************************************
' WMI管理プロシージャ
' ******************************************************
Public Sub Main_RemotePC_Management()
' --- 高速化のための初期設定 ---
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Const TARGET_SHEET As String = "WMI_Results"
Dim ws As Worksheet
Dim vTargetPCs As Variant
Dim i As Long
' ターゲットPCリストを配列から取得 (例として3台)
' 実際にはシート上のリストやデータベースから読み込むことを推奨
vTargetPCs = Array("PC-A01", "PC-B02", "PC-C03")
' 結果出力シートの準備
On Error Resume Next
Set ws = ThisWorkbook.Sheets(TARGET_SHEET)
If Err.Number <> 0 Then
Set ws = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
ws.Name = TARGET_SHEET
End If
On Error GoTo 0
' ヘッダ書き込み
ws.Cells.Clear
ws.Range("A1:G1").Value = Array("PC名", "ステータス", "アプリ名", "バージョン", "ベンダー", "インストール日", "プロセス起動結果")
Dim lRow As Long: lRow = 2
' 各PCに対して処理を実行
For i = LBound(vTargetPCs) To UBound(vTargetPCs)
Dim sPCName As String
sPCName = CStr(vTargetPCs(i))
' 1. アプリケーションリストの取得
Dim vAppList() As Variant
If Get_Remote_App_List(sPCName, "root\cimv2", "", "", vAppList) Then
' 取得データを行方向に転置し、配列としてシートに書き込む
If UBound(vAppList, 1) > 0 Then
Dim arrOutput As Variant
ReDim arrOutput(1 To UBound(vAppList, 1), 1 To 6) ' PC名, ステータス, 取得データ4列
Dim j As Long
For j = 1 To UBound(vAppList, 1)
arrOutput(j, 1) = sPCName
arrOutput(j, 2) = "成功 (データ取得)"
arrOutput(j, 3) = vAppList(j, 1) ' Name
arrOutput(j, 4) = vAppList(j, 2) ' Version
arrOutput(j, 5) = vAppList(j, 3) ' Vendor
arrOutput(j, 6) = vAppList(j, 4) ' InstallDate
Next j
' 配列を一括出力
ws.Cells(lRow, 1).Resize(UBound(arrOutput, 1), UBound(arrOutput, 2)).Value = arrOutput
lRow = lRow + UBound(arrOutput, 1)
Else
ws.Cells(lRow, 1).Resize(1, 2).Value = Array(sPCName, "成功 (アプリなし)")
lRow = lRow + 1
End If
Else
' 接続失敗またはエラー
ws.Cells(lRow, 1).Resize(1, 2).Value = Array(sPCName, "接続失敗/WMIエラー")
lRow = lRow + 1
End If
' 2. リモートプロセス起動の試行
Dim sResult As String
sResult = Start_Remote_Process(sPCName, "calc.exe", "root\cimv2", "", "")
' 起動結果を最終行のG列に追記
If lRow > 2 Then
ws.Cells(lRow - 1, 7).Value = sResult
Else ' 最初の行にアプリリストがない場合
ws.Cells(lRow - 1, 7).Value = sResult
End If
Next i
' --- 後処理 ---
ws.Columns.AutoFit
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
MsgBox "リモートPC監査処理が完了しました。", vbInformation
End Sub
' ------------------------------------------------------
' 関数1: リモートPCのアプリケーションリストを取得する
' ------------------------------------------------------
Private Function Get_Remote_App_List( _
ByVal sPCName As String, _
ByVal sNamespace As String, _
ByVal sUser As String, _
ByVal sPass As String, _
ByRef vOutput() As Variant _
) As Boolean
Dim objLocator As Object
Dim objServices As Object
Dim colItems As Object
Dim objItem As Object
Dim sWQL As String
Dim lCount As Long: lCount = 0
On Error GoTo ErrorHandler
Set objLocator = CreateObject("WbemScripting.SWbemLocator")
' WMIサービスの接続 (ConnectServerで認証情報を渡す)
If sUser <> "" Then
Set objServices = objLocator.ConnectServer(sPCName, sNamespace, sUser, sPass)
Else
' 実行ユーザーの認証情報を使用
Set objServices = objLocator.ConnectServer(sPCName, sNamespace)
End If
' WQL (WMI Query Language) を使用してインストール済み製品情報をクエリ
sWQL = "SELECT Name, Version, Vendor, InstallDate FROM Win32_Product"
Set colItems = objServices.ExecQuery(sWQL)
' 取得したデータを一旦配列に格納
If colItems.Count > 0 Then
ReDim vOutput(1 To colItems.Count, 1 To 4)
For Each objItem In colItems
lCount = lCount + 1
vOutput(lCount, 1) = objItem.Name
vOutput(lCount, 2) = objItem.Version
vOutput(lCount, 3) = objItem.Vendor
vOutput(lCount, 4) = objItem.InstallDate
Next objItem
Else
ReDim vOutput(0, 0) ' データがない場合は空配列
End If
Get_Remote_App_List = True
CleanUp:
Set objItem = Nothing
Set colItems = Nothing
Set objServices = Nothing
Set objLocator = Nothing
Exit Function
ErrorHandler:
' 接続失敗やWQLエラーが発生した場合
Debug.Print "WMI接続エラー (" & sPCName & "): " & Err.Description
Get_Remote_App_List = False
Resume CleanUp
End Function
' ------------------------------------------------------
' 関数2: リモートPCでプロセスを起動する
' ------------------------------------------------------
Private Function Start_Remote_Process( _
ByVal sPCName As String, _
ByVal sCommand As String, _
ByVal sNamespace As String, _
ByVal sUser As String, _
ByVal sPass As String _
) As String
Dim objLocator As Object
Dim objServices As Object
Dim objProcessService As Object ' Win32_ProcessStartup
Dim lngReturn As Long
On Error GoTo ErrorHandler
Set objLocator = CreateObject("WbemScripting.SWbemLocator")
If sUser <> "" Then
Set objServices = objLocator.ConnectServer(sPCName, sNamespace, sUser, sPass)
Else
Set objServices = objLocator.ConnectServer(sPCName, sNamespace)
End If
' Win32_Processクラスを取得
Set objProcessService = objServices.Get("Win32_Process")
' Createメソッドを使用してプロセス起動
' 戻り値(lngReturn)が 0 の場合成功
lngReturn = objProcessService.Create(sCommand)
If lngReturn = 0 Then
Start_Remote_Process = "プロセス起動成功 (" & sCommand & ")"
Else
Start_Remote_Process = "プロセス起動失敗 (コード: " & lngReturn & ")"
End If
CleanUp:
Set objProcessService = Nothing
Set objServices = Nothing
Set objLocator = Nothing
Exit Function
ErrorHandler:
Start_Remote_Process = "プロセス起動エラー (接続/権限)"
Debug.Print "Process Error (" & sPCName & "): " & Err.Description
Resume CleanUp
End Function
【技術解説】
WMIオブジェクトモデルの構造
WMIは、Windowsの管理情報にアクセスするためのインターフェースであり、VBAからはCOMオブジェクトとして利用します。
SWbemLocator(WbemScripting.SWbemLocator): WMIサービスへの接続を提供するルートオブジェクトです。ConnectServerメソッドを使用することで、リモートマシン名、WMIネームスペース(通常はroot\cimv2)、認証情報(ユーザー名とパスワード)を指定して接続できます。これにより、実行元の権限に依存せず、必要な認証情報を用いて接続することが可能になります。SWbemServices: 特定のネームスペースに接続された後のサービスオブジェクトで、WQL(WMI Query Language)を実行するためのExecQueryメソッドや、特定の管理クラスを取得するためのGetメソッドを提供します。ExecQueryとWin32_Product:ExecQueryはSQLライクなWQLを実行し、結果をSWbemObjectSet(colItems)として返します。Win32_Productクラスは、システムにインストールされているアプリケーション情報を保持しますが、このクラスへのクエリ実行はシステムリソースを大量に消費する(再設定処理が実行されるため)という点に留意が必要です。Win32_Process.Createメソッド: リモートPCでプロセスを起動する際に使用します。これは、WMIクラスのインスタンスメソッドではなく、静的メソッドとして提供されています。戻り値が0であれば成功、それ以外はWMIのエラーコードを示します。
高速化のポイント
VBAで大量のデータ処理を行う場合、WMIから取得した結果(colItems)を逐次シートに出力せず、一時的にVBAの多次元配列 vOutput に格納します。処理完了後、ws.Cells(...).Value = arrOutput の形式で一度にシートに書き出すことで、Excelの再描画やセル操作のオーバーヘッドを劇的に削減しています。また、冒頭で ScreenUpdating = False および Calculation = xlCalculationManual を設定し、処理中の描画と自動再計算を停止しています。
【注意点と運用】
1. DCOMとファイアウォールの設定(最大の落とし穴)
WMIによるリモート接続は、DCOM(Distributed Component Object Model)プロトコルを使用します。ターゲットPC側で以下の設定が適切に行われていないと、認証情報が正しくても接続が拒否されます。
ファイアウォール: リモート管理(WMI)の着信ルールが有効になっている必要があります。通常、ポート135(RPC Endpoint Mapper)と、それ以降の動的ポート範囲が許可されている必要があります。
DCOMセキュリティ: リモートPCのDCOM構成(dcomcnfg)において、リモート起動およびアクセス権限が、VBAを実行するユーザーまたはコード内で指定したユーザーに許可されている必要があります。
2. Win32_Product クラスの使用制限
Win32_Product クラスをクエリすると、システムがインストーラーの整合性チェックを実行するため、大規模環境や頻繁な実行には不向きです。大量監査を行う場合は、代わりにレジストリを直接操作(HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall)するか、Win32_InstalledSoftware(非標準ネームスペースの場合がある)の利用を検討してください。
3. 認証情報の取り扱い
本コードではユーザー名とパスワードを変数として渡していますが、これらをVBAコード内に平文で記述することはセキュリティ上極めて危険です。実運用では、認証情報をセキュアな外部ファイルやデータベース(暗号化必須)から読み込むか、実行ユーザーの権限でカバーできる範囲に限定してください。
【まとめ】
VBAとWMIを組み合わせたリモートPC管理の運用のコツは以下の3点です。
Late Bindingの徹底:
CreateObjectを使用することで、参照設定の依存性を排除し、異なる環境間での互換性を保ちます。DCOMとネットワーク設定の事前確認: WMI操作の成否は、VBAコードよりもリモートPC側のファイアウォールとDCOMセキュリティ設定に大きく依存します。実行前にターゲット環境の設定を監査ツールなどで確認してください。
配列処理による速度維持: WMI接続のオーバーヘッドを最小化するため、取得したデータは配列に格納し、Excel操作(シートへの書き出し)は最小限に抑えることで、多数のPCへの並列処理時間を短縮します。

コメント