Windows PowerShell 不只是命令列殼層,更是建構於 .NET Framework 之上的自動化引擎。其對 WMI (Windows Management Instrumentation) 的原生深度整合,讓系統管理員能以物件導向方式查詢、操作、監控企業級 IT 基礎設施。本文從 WMI 核心架構切入,實戰演示 PowerShell 運用 WMI 的五大核心指令與進階模式。
Win32_Process (進程)、Win32_LogicalDisk (邏輯磁碟)、Win32_Service (服務)。Root\CIMV2 涵蓋絕大多數 Win32 管理類別。其他常見:Root\Default (系統預設)、Root\SecurityCenter (安全中心)、Root\Virtualization (Hyper-V)、Root\Microsoft\Windows\Storage (存儲)。| Cmdlet | 核心功能 | 典型用途 | 關鍵參數 |
|---|---|---|---|
Get-WmiObject (別名 gwmi) | 查詢 WMI 類別實例 (最常用) | 硬體資產盤點、服務狀態、事件日誌、進程監控、網路設定 | -Class, -Namespace, -ComputerName, -Filter (WQL), -Property, -Credential |
| Invoke-WmiMethod | 呼叫 WMI 類別/實例方法 | 建立進程 (Win32_Process.Create)、啟動/停止服務 (Win32_Service.StartService/StopService)、重命名電腦 (Win32_ComputerSystem.Rename) | -Name (方法名), -ArgumentList, -Path (實例路徑) |
| Register-WmiEvent | 訂閱 WMI 事件 (非同步監控) | 監控程式啟動/結束、USB 插拔、服務狀態變更、磁碟空間閾值、登入事件 | -Query (WQL 事件查詢), -Action (ScriptBlock), -SourceIdentifier, -Forward (轉發至引擎事件) |
| Remove-WmiObject | 刪除 WMI 類別實例 (非刪除類別定義) | 移除自訂 WMI 類別實例、清理殘留實例 (謹慎使用) | -InputObject (管線傳入實例) |
| Set-WmiInstance | 建立或更新 WMI 類別實例 (寫入 WMI 儲存庫) | 修改網卡 IP/DNS、建立計劃任務、設定環境變數、配置防火牆規則 (需對應 Provider 支援寫入) | -Arguments (雜湊表屬性值), -PutType (Create/Update/UpdateOnly) |
# 列出根命名空間下的所有子命名空間
Get-WmiObject -Namespace "Root" -Class "__Namespace" | Select-Object Name
# 列出指定命名空間所有類別 (含單例/抽象)
Get-WmiObject -Namespace "Root\CIMV2" -List | Where-Object { $_.Name -like "Win32_*" } | Select-Object Name, Qualifiers
# 關鍵字過濾 (支援萬用字元)
Get-WmiObject -Namespace "Root\SecurityCenter2" -List *Firewall* | Format-Table Name, __Class -AutoSize
# 遠端查詢 (需 RPC/DCOM 通訊、防火牆開放、權限)
Get-WmiObject -Namespace "Root\Virtualization" -List -ComputerName "HyperV-Host01" -Credential (Get-Credential)
工具輔助: WMI Explorer (GUI)、PowerShell ISE 內建 Show-Command、Sapien PowerShell Studio 物件瀏覽器。
$computers = Get-Content "servers.txt" # 或從 AD Get-ADComputer -Filter * | Select-Object -ExpandProperty DNSHostName
$results = foreach ($comp in $computers) {
try {
$cs = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $comp -ErrorAction Stop
$bios = Get-WmiObject -Class Win32_BIOS -ComputerName $comp
$os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $comp
$cpu = Get-WmiObject -Class Win32_Processor -ComputerName $comp
$disk = Get-WmiObject -Class Win32_LogicalDisk -ComputerName $comp -Filter "DriveType=3" | Measure-Object -Property Size, FreeSpace -Sum
$mem = Get-WmiObject -Class Win32_PhysicalMemory -ComputerName $comp | Measure-Object -Property Capacity -Sum
[PSCustomObject]@{
ComputerName = $comp
Manufacturer = $cs.Manufacturer
Model = $cs.Model
BIOSVersion = $bios.SMBIOSBIOSVersion
OSVersion = $os.Caption + " " + $os.Version
CPU = "$($cpu.Name) ($($cpu.NumberOfLogicalProcessors) 邏輯核心)"
TotalRAM_GB = "{0:N1}" -f ($mem.Sum / 1GB)
DiskTotal_GB = "{0:N1}" -f ($disk.Sum / 1GB)
DiskFree_GB = "{0:N1}" -f ($disk.FreeSpace / 1GB)
ScanTime = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
}
} catch {
Write-Warning "$comp 連線失敗: $($_.Exception.Message)"
[PSCustomObject]@{ ComputerName=$comp; Error=$_.Exception.Message }
}
}
$results | Export-Csv "Asset_Inventory_$(Get-Date -Format yyyyMMdd).csv" -NoTypeInformation -Encoding UTF8
$query = "SELECT * FROM __InstanceModificationEvent WITHIN 10 WHERE TargetInstance ISA 'Win32_Service' AND TargetInstance.Name = 'MSSQLSERVER' AND TargetInstance.State = 'Stopped'"
$action = {
$svc = $Event.SourceEventArgs.NewEvent.TargetInstance
Write-Host "[$(Get-Date)] 偵測到 $($svc.DisplayName) ($($svc.Name)) 服務停止,嘗試重啟..."
Invoke-WmiMethod -Path "Win32_Service.Name='$($svc.Name)'" -Name StartService -ComputerName $svc.__SERVER -Credential $cred
# 發送郵件/Teams/Slack 告警 (略)
}
Register-WmiEvent -Query $query -Action $action -SourceIdentifier "Monitor_MSSQL_Service" -Credential $cred
# 持續運行... 結束時: Unregister-Event -SourceIdentifier "Monitor_MSSQL_Service"
$nic = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -ComputerName "TargetPC" -Filter "IPEnabled=TRUE" -Credential $cred
$nic.EnableStatic($ipAddress, $subnetMask)
$nic.SetDNSServerSearchOrder($dnsServers)
WMI Cmdlet (Get-WmiObject 等) 基於 DCOM/RPC,跨網段/NAT/防火牆困難。CIM Cmdlet (Get-CimInstance, Invoke-CimMethod, Register-CimIndicationEvent, New-CimSession) 基於 WS-MAN (WinRM/HTTP/HTTPS),支援會話、遠端更穩健、效能更好、標準化。
# 建立 CIM 會話 (可重用、支援 Kerberos/SSL)
$session = New-CimSession -ComputerName "Server01", "Server02" -Credential $cred -Authentication Kerberos
Get-CimInstance -ClassName Win32_Service -CimSession $session -Filter "State='Running' AND StartMode='Auto'" | Select-Object Name, DisplayName, State, StartMode
Remove-CimSession $session
最佳實踐: 新腳本優先使用 CIM Cmdlet;維護舊腳本或需 DCOM 特定功能時使用 WMI Cmdlet。
掌握 Namespace/Class/Provider 架構、善用 Get/Invoke/Register/Remove/Set 五大核心操作、結合 WQL 過濾、遠端會話、事件訂閱、物件管線,即可將繁瑣手工運維轉化為可版控、可測試、可複用的自動化資產。從「會用指令」進化到「設計自動化系統」,是邁向 DevOps/SRE 的關鍵一步。