Windows Management Instrumentation (WMI) 是 Windows 內建的管理基礎設施,提供統一介面查詢/操作系統、硬體、網路、服務、進程等資源。.NET 透過 `System.Management` 命名空間完整支援 WMI,讓 C# 開發者能輕鬆建立**無代理程式**的遠端管理工具。本文深度解析六大核心類別、連線認證、WQL 查詢、遠端操作與實戰模式。
using System.Management;
var options = new ConnectionOptions
{
Username = @"DOMAIN\Administrator", // 或 ".\Administrator" (本機)
Password = "P@ssw0rd",
Authority = "ntlmdomain:DOMAIN", // 指定驗證授權單位 (Kerberos/NTLM)
Locale = "en-US", // 地區設定 (影響日期/數字格式)
EnablePrivileges = true, // 啟用特殊權限 (如 SeShutdownPrivilege)
Impersonation = ImpersonationLevel.Impersonate, // 模擬等級
Authentication = AuthenticationLevel.PacketPrivacy, // 加密封包
Timeout = TimeSpan.FromMinutes(2) // 連線逾時
};
// 方式一:建構子直接連線 (可能拋出例外)
var scope = new ManagementScope(@"\\Server01\root\cimv2", options);
// 方式二:分步連線 (可捕獲連線錯誤)
var scope = new ManagementScope(@"\\Server01\root\cimv2");
scope.Options = options;
try
{
scope.Connect(); // 實際建立連線
Console.WriteLine($"已連線至 {scope.Path.Server}");
}
catch (ManagementException ex)
{
Console.WriteLine($"WMI 錯誤: {ex.ErrorCode} - {ex.Message}");
}
catch (UnauthorizedAccessException)
{
Console.WriteLine("存取被拒絕:檢查帳號密碼、WMI 權限、防火牆");
}
catch (System.Runtime.InteropServices.COMException ex)
{
Console.WriteLine($"RPC 錯誤 (通常是防火牆/服務未啟動): 0x{ex.ErrorCode:X}");
}
// 簡單查詢
var query = new ObjectQuery("SELECT * FROM Win32_OperatingSystem");
// 參數化查詢 (SelectQuery 繼承 ObjectQuery)
var query = new SelectQuery("Win32_Service", "State = 'Running' AND StartMode = 'Auto'");
// 等同: SELECT * FROM Win32_Service WHERE State = 'Running' AND StartMode = 'Auto'
// 投影查詢 (只取需要欄位,效能較好)
var query = new SelectQuery("SELECT Name, ProcessId, ExecutablePath FROM Win32_Process WHERE Name LIKE 'chrome%'");
var searcher = new ManagementObjectSearcher(scope, query);
// 同步執行 (阻塞直到完成)
ManagementObjectCollection results = searcher.Get();
// 非同步執行 (事件模式)
searcher.GetCompleted += (sender, e) =>
{
if (e.Error != null) Console.WriteLine($"查詢失敗: {e.Error}");
else foreach (ManagementObject obj in e.Result) ProcessObject(obj);
};
searcher.GetAsync();
// 取消查詢
searcher.CancelAsync();
// 實作 IEnumerable,支援 foreach
foreach (ManagementObject obj in results)
{
Console.WriteLine($"物件路徑: {obj.Path}");
foreach (PropertyData prop in obj.Properties)
{
Console.WriteLine($" {prop.Name} = {prop.Value} (型別: {prop.Type})");
}
}
// 取得計數 (需完整枚舉)
int count = results.Count; // 注意:這會觸發完整枚舉
// 複製到陣列
ManagementObject[] array = new ManagementObject[results.Count];
results.CopyTo(array, 0);
// 核心屬性
obj.Path; // 物件路徑 (可用於後續直接取得)
obj.ClassPath; // 類別路徑
obj.Properties; // 所有屬性集合
obj.SystemProperties; // 系統屬性 (__SERVER, __NAMESPACE, __CLASS, __RELPATH 等)
// 核心方法
obj.Get(); // 重新整理資料 (同步)
obj.GetAsync(); // 非同步重新整理
obj.InvokeMethod("MethodName", args); // 呼叫方法 (如 Reboot, Shutdown, Create, Delete)
obj.Put(); // 提交屬性變更
obj.Delete(); // 刪除物件實例
obj.GetRelated(); // 取得關聯物件 (關聯類別)
obj.GetRelationships(); // 取得關聯關係物件
public class AssetScanner
{
private readonly ConnectionOptions _options;
public AssetScanner(string username, string password, string domain = null)
{
_options = new ConnectionOptions
{
Username = string.IsNullOrEmpty(domain) ? username : $@"{domain}\{username}",
Password = password,
Impersonation = ImpersonationLevel.Impersonate,
Authentication = AuthenticationLevel.PacketPrivacy
};
}
public ComputerAsset Scan(string computerName)
{
var scope = new ManagementScope($@"\\{computerName}\root\cimv2", _options);
scope.Connect();
var asset = new ComputerAsset { ComputerName = computerName };
// 作業系統
QuerySingle(scope, "SELECT Caption, Version, BuildNumber, OSArchitecture FROM Win32_OperatingSystem",
obj => { asset.OS = $"{obj["Caption"]} {obj["Version"]} ({obj["OSArchitecture"]})"; });
// CPU
QuerySingle(scope, "SELECT Name, NumberOfCores, NumberOfLogicalProcessors, MaxClockSpeed FROM Win32_Processor",
obj => { asset.CPU = $"{obj["Name"]} ({obj["NumberOfCores"]}C/{obj["NumberOfLogicalProcessors"]}T) @{obj["MaxClockSpeed"]}MHz"; });
// 記憶體
QuerySingle(scope, "SELECT TotalVisibleMemorySize FROM Win32_OperatingSystem",
obj => { asset.TotalMemoryGB = Math.Round(Convert.ToDouble(obj["TotalVisibleMemorySize"]) / 1024 / 1024, 1); });
// 磁碟
foreach (var obj in Query(scope, "SELECT DeviceID, Size, FreeSpace, FileSystem FROM Win32_LogicalDisk WHERE DriveType = 3"))
{
asset.Disks.Add(new DiskInfo
{
Drive = obj["DeviceID"].ToString(),
SizeGB = Math.Round(Convert.ToDouble(obj["Size"]) / 1024 / 1024 / 1024, 1),
FreeGB = Math.Round(Convert.ToDouble(obj["FreeSpace"]) / 1024 / 1024 / 1024, 1),
FileSystem = obj["FileSystem"]?.ToString()
});
}
// 網卡
foreach (var obj in Query(scope, "SELECT Description, MACAddress, IPEnabled, IPAddress FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = True"))
{
asset.NetworkAdapters.Add(new NetworkInfo
{
Description = obj["Description"]?.ToString(),
MAC = obj["MACAddress"]?.ToString(),
IPs = (string[])obj["IPAddress"]
});
}
return asset;
}
private ManagementObjectCollection Query(ManagementScope scope, string wql)
{
return new ManagementObjectSearcher(scope, new ObjectQuery(wql)).Get();
}
private void QuerySingle(ManagementScope scope, string wql, Action action)
{
foreach (ManagementObject obj in Query(scope, wql))
{
action(obj);
break; // 只取第一筆
}
}
}
// 資料模型
public class ComputerAsset
{
public string ComputerName { get; set; }
public string OS { get; set; }
public string CPU { get; set; }
public double TotalMemoryGB { get; set; }
public List Disks { get; } = new();
public List NetworkAdapters { get; } = new();
}
public class DiskInfo { public string Drive { get; set; } public double SizeGB { get; set; } public double FreeGB { get; set; } public string FileSystem { get; set; } }
public class NetworkInfo { public string Description { get; set; } public string MAC { get; set; } public string[] IPs { get; set; } }
public class ServiceController
{
private readonly ManagementScope _scope;
public ServiceController(string computer, ConnectionOptions options)
{
_scope = new ManagementScope($@"\\{computer}\root\cimv2", options);
_scope.Connect();
}
public ServiceStatus GetStatus(string serviceName)
{
var query = new SelectQuery("Win32_Service", $"Name = '{serviceName}'");
using var searcher = new ManagementObjectSearcher(_scope, query);
foreach (ManagementObject svc in searcher.Get())
{
return new ServiceStatus
{
Name = svc["Name"].ToString(),
DisplayName = svc["DisplayName"].ToString(),
State = svc["State"].ToString(), // Running, Stopped, Paused
StartMode = svc["StartMode"].ToString(), // Auto, Manual, Disabled
ProcessId = Convert.ToInt32(svc["ProcessId"])
};
}
return null;
}
public bool StartService(string serviceName)
{
return InvokeServiceMethod(serviceName, "StartService");
}
public bool StopService(string serviceName)
{
return InvokeServiceMethod(serviceName, "StopService");
}
private bool InvokeServiceMethod(string serviceName, string methodName)
{
var query = new SelectQuery("Win32_Service", $"Name = '{serviceName}'");
using var searcher = new ManagementObjectSearcher(_scope, query);
foreach (ManagementObject svc in searcher.Get())
{
var result = svc.InvokeMethod(methodName, null);
return Convert.ToUInt32(result) == 0; // 0 = 成功
}
return false;
}
}
public class ServiceStatus
{
public string Name { get; set; }
public string DisplayName { get; set; }
public string State { get; set; }
public string StartMode { get; set; }
public int ProcessId { get; set; }
}
public class ProcessManager
{
private readonly ManagementScope _scope;
public ProcessManager(string computer, ConnectionOptions options)
{
_scope = new ManagementScope($@"\\{computer}\root\cimv2", options);
_scope.Connect();
}
public List GetTopProcessesByCpu(int top = 10)
{
var query = new SelectQuery(@"
SELECT Name, ProcessId, PercentProcessorTime, WorkingSetSize, PageFileUsage
FROM Win32_PerfFormattedData_PerfProc_Process
WHERE Name NOT IN ('_Total', 'Idle', 'System')
ORDER BY PercentProcessorTime DESC");
var results = new List();
using var searcher = new ManagementObjectSearcher(_scope, query);
int count = 0;
foreach (ManagementObject proc in searcher.Get())
{
if (count++ >= top) break;
results.Add(new ProcessInfo
{
Name = proc["Name"].ToString(),
ProcessId = Convert.ToInt32(proc["ProcessId"]),
CpuPercent = Convert.ToDouble(proc["PercentProcessorTime"]),
WorkingSetMB = Math.Round(Convert.ToDouble(proc["WorkingSetSize"]) / 1024 / 1024, 1),
PageFileMB = Math.Round(Convert.ToDouble(proc["PageFileUsage"]) / 1024 / 1024, 1)
});
}
return results;
}
public bool KillProcess(int processId)
{
var query = new SelectQuery("Win32_Process", $"ProcessId = {processId}");
using var searcher = new ManagementObjectSearcher(_scope, query);
foreach (ManagementObject proc in searcher.Get())
{
var result = proc.InvokeMethod("Terminate", new object[] { 0 }); // exit code 0
return Convert.ToUInt32(result) == 0;
}
return false;
}
}
public class ProcessInfo
{
public string Name { get; set; }
public int ProcessId { get; set; }
public double CpuPercent { get; set; }
public double WorkingSetMB { get; set; }
public double PageFileMB { get; set; }
}
| 語法 | 範例 | 說明 |
|---|---|---|
| SELECT | SELECT Name, State FROM Win32_Service | 投影欄位,* 為全部 |
| WHERE | WHERE State = 'Running' | 字串用單引號,數值直接寫 |
| LIKE | WHERE Name LIKE 'SQL%' | % 多字元,_ 單字元 |
| IS NULL | WHERE ParentProcessId IS NULL | 檢查空值 |
| ISA | WHERE __CLASS ISA 'Win32_BaseService' | 繼承關係查詢 |
| ASSOCIATORS OF | ASSOCIATORS OF {Win32_Service.Name='wuauserv'} WHERE ResultClass=Win32_DependentService | 關聯查詢 (相依服務) |
| REFERENCES OF | REFERENCES OF {Win32_Service.Name='wuauserv'} | 反向關聯查詢 |
| 錯誤代碼 | HRESULT | 原因 | 解決 |
|---|---|---|---|
| Access Denied | 0x80070005 | 權限不足 | 檢查 WMI 安全性設定、帳號群組、UAC 遠端限制 |
| RPC Server Unavailable | 0x800706BA | RPC 服務停用/防火牆 | 啟動 RPC 服務、開放 TCP 135/動態埠、檢查 `winrm quickconfig` |
| Invalid Namespace | 0x8004100E | 命名空間錯誤 | 確認 `root\cimv2` 拼寫、目標 OS 版本支援 |
| Provider Load Failure | 0x80041013 | WMI 提供者損壞 | 重建 WMI 儲存庫: `winmgmt /salvagerepository` 或 `/resetrepository` |
| Quota Violation | 0x8004106C | 查詢傳回資料過大 | 加上 WHERE 條件、分頁查詢、投影必要欄位 |
`System.Management` 提供了完整、強型別的 WMI 存取能力。掌握 **ConnectionOptions → ManagementScope → ObjectQuery → ManagementObjectSearcher → ManagementObjectCollection → ManagementObject** 這條核心鏈路,配合 WQL 查詢語言,即可建立企業級的無代理遠端管理系統。關鍵成功因素:**正確的權限設定、防火牆規則、錯誤處理、效能優化、安全性實務**。現代替代方案包括 PowerShell Remoting (WinRM)、CIM Cmdlets (`Get-CimInstance`)、Windows Admin Center、Azure Arc 等,但 WMI 仍是 Windows 管理的基石,深度理解極具價值。