共用方式為


第 7 章 - 使用 WMI

WMI 和 CIM

Windows PowerShell 預設會隨附 Cmdlet,以使用 Windows Management Instrumentation (WMI) 等其他技術。 WMI Cmdlet 已被取代,且無法在 PowerShell 6+ 中使用,但在這裡涵蓋,因為您可能會在 Windows PowerShell 上執行的舊版腳本中遇到它們。 針對新的開發,請改用 CIM Cmdlet。

PowerShell 中存在數個原生 WMI Cmdlet,而不需要安裝任何其他軟體或模組。 Get-Command 可用來判斷 Windows PowerShell 中有哪些 WMI Cmdlet。 下列結果來自執行 PowerShell 5.1 版的 Windows 10 實驗室環境計算機。 您的結果可能會因您執行的PowerShell版本而有所不同。

Get-Command -Noun WMI*
CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Get-WmiObject                                      3.1.0.0    Microsof...
Cmdlet          Invoke-WmiMethod                                   3.1.0.0    Microsof...
Cmdlet          Register-WmiEvent                                  3.1.0.0    Microsof...
Cmdlet          Remove-WmiObject                                   3.1.0.0    Microsof...
Cmdlet          Set-WmiInstance                                    3.1.0.0    Microsof...

PowerShell 3.0 版引進了通用資訊模型 (CIM) Cmdlet。 CIM Cmdlet 的設計可讓它們同時用於 Windows 和非 Windows 電腦上。

CIM Cmdlet 全都包含在模組內。 若要取得 CIM Cmdlet 的清單,請搭配 Module 參數使用Get-Command,如下列範例所示。

Get-Command -Module CimCmdlets
CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Export-BinaryMiLog                                 1.0.0.0    CimCmdlets
Cmdlet          Get-CimAssociatedInstance                          1.0.0.0    CimCmdlets
Cmdlet          Get-CimClass                                       1.0.0.0    CimCmdlets
Cmdlet          Get-CimInstance                                    1.0.0.0    CimCmdlets
Cmdlet          Get-CimSession                                     1.0.0.0    CimCmdlets
Cmdlet          Import-BinaryMiLog                                 1.0.0.0    CimCmdlets
Cmdlet          Invoke-CimMethod                                   1.0.0.0    CimCmdlets
Cmdlet          New-CimInstance                                    1.0.0.0    CimCmdlets
Cmdlet          New-CimSession                                     1.0.0.0    CimCmdlets
Cmdlet          New-CimSessionOption                               1.0.0.0    CimCmdlets
Cmdlet          Register-CimIndicationEvent                        1.0.0.0    CimCmdlets
Cmdlet          Remove-CimInstance                                 1.0.0.0    CimCmdlets
Cmdlet          Remove-CimSession                                  1.0.0.0    CimCmdlets
Cmdlet          Set-CimInstance                                    1.0.0.0    CimCmdlets

CIM Cmdlet 仍然可讓您使用 WMI,因此當有人提出「當我使用 PowerShell CIM Cmdlet 查詢 WMI 時...」語句時,請勿混淆。

如我先前所述,WMI 是與 PowerShell 不同的技術,而您只是使用 CIM Cmdlet 來存取 WMI。 您可能會發現使用 WMI 查詢語言 (WQL) 來查詢 WMI 的舊 VBScript,例如在下列範例中。

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set colBIOS = objWMIService.ExecQuery _
    ("Select * from Win32_BIOS")

For each objBIOS in colBIOS
    Wscript.Echo "Manufacturer: " & objBIOS.Manufacturer
    Wscript.Echo "Name: " & objBIOS.Name
    Wscript.Echo "Serial Number: " & objBIOS.SerialNumber
    Wscript.Echo "SMBIOS Version: " & objBIOS.SMBIOSBIOSVersion
    Wscript.Echo "Version: " & objBIOS.Version
Next

您可以從該 VBScript 取得 WQL 查詢,並將其與 Cmdlet 搭配 Get-CimInstance 使用,而不需要進行任何修改。

Get-CimInstance -Query 'Select * from Win32_BIOS'
SMBIOSBIOSVersion : 090006
Manufacturer      : American Megatrends Inc.
Name              : Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz
SerialNumber      : 3810-1995-1654-4615-2295-2755-89
Version           : VRTUAL - 4001628

這不是我通常會使用PowerShell查詢 WMI 的方式。 但它確實可運作,並可讓您輕鬆地將現有的 VBScript 移轉至 PowerShell。 當我開始撰寫一行程式代碼來查詢 WMI 時,我使用下列語法。

Get-CimInstance -ClassName Win32_BIOS
SMBIOSBIOSVersion : 090006
Manufacturer      : American Megatrends Inc.
Name              : Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz
SerialNumber      : 3810-1995-1654-4615-2295-2755-89
Version           : VRTUAL - 4001628

如果我只想要序號,我可以使用管線將輸出傳送至 Select-Object ,並只 指定 SerialNumber 屬性。

Get-CimInstance -ClassName Win32_BIOS | Select-Object -Property SerialNumber
SerialNumber
------------
3810-1995-1654-4615-2295-2755-89

根據預設,在幕後擷取的數個屬性永遠不會使用。 在本機計算機上查詢 WMI 時,可能並不重要。 但是,一旦您開始查詢遠端計算機,不僅需要額外的處理時間才能傳回該資訊,而且還需要額外的不必要的資訊才能跨網路提取。 Get-CimInstance具有屬性參數,可限制所擷取的資訊。 這可讓對 WMI 的查詢更有效率。

Get-CimInstance -ClassName Win32_BIOS -Property SerialNumber |
Select-Object -Property SerialNumber
SerialNumber
------------
3810-1995-1654-4615-2295-2755-89

先前的結果會傳回物件。 若要傳回簡單的字串,請使用 ExpandProperty 參數。

Get-CimInstance -ClassName Win32_BIOS -Property SerialNumber |
Select-Object -ExpandProperty SerialNumber
3810-1995-1654-4615-2295-2755-89

您也可以使用語法的虛線樣式來傳回簡單的字串。 這樣就不需要使用管線傳送至 Select-Object

(Get-CimInstance -ClassName Win32_BIOS -Property SerialNumber).SerialNumber
3810-1995-1654-4615-2295-2755-89

使用 CIM Cmdlet 查詢遠端電腦

我仍在以身為網域使用者的本機系統管理員身分執行PowerShell。 當我嘗試使用 Get-CimInstance Cmdlet 從遠端電腦查詢資訊時,我會收到拒絕存取的錯誤訊息。

Get-CimInstance -ComputerName dc01 -ClassName Win32_BIOS
Get-CimInstance : Access is denied.
At line:1 char:1
+ Get-CimInstance -ComputerName dc01 -ClassName Win32_BIOS
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : PermissionDenied: (root\cimv2:Win32_BIOS:String) [Get-CimI
   nstance], CimException
    + FullyQualifiedErrorId : HRESULT 0x80070005,Microsoft.Management.Infrastructure.Cim
   Cmdlets.GetCimInstanceCommand
    + PSComputerName        : dc01

在 PowerShell 方面,許多人都有安全性考慮,但事實是您在 PowerShell 中的許可權與在 GUI 中的許可權完全相同。 不多也不少。 上一個範例中的問題在於執行 PowerShell 的用戶沒有從 DC01 伺服器查詢 WMI 資訊的許可權。 我可以以網域系統管理員身分重新啟動PowerShell,因為 Get-CimInstance 沒有 Credential 參數。 但是,信任我,這不是個好主意,因為我從 PowerShell 執行的任何項目都會以網域系統管理員身分執行。從安全的角度來看,這可能很危險,這取決於情況。

使用最低許可權原則,如果命令有一個,則會使用 Credential 參數,依每個命令提升至網域系統管理員帳戶。 Get-CimInstance 沒有 Credential 參數,因此此案例中的解決方案是先建立 CimSession 。 然後,我使用 CimSession ,而不是計算機名稱來查詢遠端電腦上的 WMI。

$CimSession = New-CimSession -ComputerName dc01 -Credential (Get-Credential)
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential

CIM 會話儲存在名為的 $CimSession變數中。 請注意,我也在括弧中指定 Get-Credential Cmdlet,讓它先執行,提示我輸入替代認證,再建立新的會話。 我將在本章稍後示範另一個更有效率的方式來指定替代認證,但請務必先了解這個基本概念,再讓其更加複雜。

在上一個範例中建立的 CIM 工作階段現在可以與 Cmdlet 搭配 Get-CimInstance 使用,從遠端電腦上的 WMI 查詢 BIOS 資訊。

Get-CimInstance -CimSession $CimSession -ClassName Win32_BIOS
SMBIOSBIOSVersion : 090006
Manufacturer      : American Megatrends Inc.
Name              : Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz
SerialNumber      : 0986-6980-3916-0512-6608-8243-13
Version           : VRTUAL - 4001628
PSComputerName    : dc01

使用 CIM 會話有數個額外的優點,而不只是指定計算機名稱。 對同一部計算機執行多個查詢時,使用 CIM 會話比針對每個查詢使用電腦名稱更有效率。 建立 CIM 會話只會設定連線一次。 然後,多個查詢會使用該相同的會話來擷取資訊。 使用計算機名稱需要 Cmdlet 來設定和卸除每個個別查詢的連線。

Cmdlet Get-CimInstance 預設會使用 WSMan 通訊協定,這表示遠端電腦需要 PowerShell 3.0 版或更高版本才能連線。 這實際上不是重要的 PowerShell 版本,它是堆疊版本。 您可以使用 Cmdlet 來判斷 Test-WSMan 堆疊版本。 它必須是 3.0 版。 這是您使用PowerShell 3.0版和更新版本找到的版本。

Test-WSMan -ComputerName dc01
wsmid           : http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd
ProtocolVersion : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
ProductVendor   : Microsoft Corporation
ProductVersion  : OS: 0.0.0 SP: 0.0 Stack: 3.0

較舊的 WMI Cmdlet 會使用與舊版 Windows 相容的 DCOM 通訊協定。 但 DCOM 通常會在較新版本的 Windows 上遭到防火牆封鎖。 Cmdlet New-CimSessionOption 可讓您建立 DCOM 通訊協定連線,以搭配 New-CimSession使用。 這可讓 Get-CimInstance Cmdlet 與 Windows Server 2000 舊版本進行通訊。 這也表示當使用 Get-CimInstance Cmdlet 搭配設定為使用 DCOM 通訊協定的 CimSession 時,遠端電腦上不需要 PowerShell。

使用 New-CimSessionOption Cmdlet 建立 DCOM 通訊協定選項,並將其儲存在變數中。

$DCOM = New-CimSessionOption -Protocol Dcom

為了提高效率,您可以將網域系統管理員或提升許可權的認證儲存在變數中,因此您不需要持續輸入每個命令。

$Cred = Get-Credential
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential

我有一個名為 SQL03 的伺服器,其執行 Windows Server 2008 (非 R2)。 這是預設未安裝 PowerShell 的最新 Windows Server 作業系統。

使用 DCOM 通訊協定建立 CimSession 至 SQL03。

$CimSession = New-CimSession -ComputerName sql03 -SessionOption $DCOM -Credential $Cred

請注意,在上一個命令中,這次我指定名為 $Cred變數做為 Credential 參數的值,而不需要再次手動輸入。

不論所使用的基礎通訊協議為何,查詢的輸出都相同。

Get-CimInstance -CimSession $CimSession -ClassName Win32_BIOS
SMBIOSBIOSVersion : 090006
Manufacturer      : American Megatrends Inc.
Name              : Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz
SerialNumber      : 7237-7483-8873-8926-7271-5004-86
Version           : VRTUAL - 4001628
PSComputerName    : sql03

Cmdlet Get-CimSession 可用來查看目前連線的 CimSession ,以及其所使用的通訊協定。

Get-CimSession
Id           : 1
Name         : CimSession1
InstanceId   : 80742787-e38e-41b1-a7d7-fa1369cf1402
ComputerName : dc01
Protocol     : WSMAN

Id           : 2
Name         : CimSession2
InstanceId   : 8fcabd81-43cf-4682-bd53-ccce1e24aecb
ComputerName : sql03
Protocol     : DCOM

在名為$CimSession的變數中擷取和儲存先前建立的兩個 CimSessions

$CimSession = Get-CimSession

使用一個命令查詢這兩部計算機,一個使用 WSMan 通訊協定,另一個使用 DCOM。

Get-CimInstance -CimSession $CimSession -ClassName Win32_BIOS
SMBIOSBIOSVersion : 090006
Manufacturer      : American Megatrends Inc.
Name              : Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz
SerialNumber      : 0986-6980-3916-0512-6608-8243-13
Version           : VRTUAL - 4001628
PSComputerName    : dc01

SMBIOSBIOSVersion : 090006
Manufacturer      : American Megatrends Inc.
Name              : Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz
SerialNumber      : 7237-7483-8873-8926-7271-5004-86
Version           : VRTUAL - 4001628
PSComputerName    : sql03

我撰寫了許多關於 WMI 和 CIM Cmdlet 的部落格文章。 其中一個最有用的函式是關於我建立的函式,以自動判斷是否應該使用 WSMan 或 DCOM,並自動設定 CIM 會話,而不需要手動找出哪一個。 該部落格文章標題為 PowerShell函式,可建立具有後援 Dcom 的遠端電腦 CimSessions。

當您完成 CIM 工作階段時,應該使用 Remove-CimSession Cmdlet 移除它們。 若要移除所有 CIM 工作階段,只需使用導管 Get-CimSession 傳送至 Remove-CimSession

Get-CimSession | Remove-CimSession

摘要

在本章中,您已瞭解如何使用PowerShell在本機和遠端電腦上使用 WMI。 您也瞭解如何使用 CIM Cmdlet 搭配 WSMan 或 DCOM 通訊協定使用遠端電腦。

檢閱

  1. WMI 和 CIM Cmdlet 有何差異?
  2. 根據預設,Cmdlet 會 Get-CimInstance 使用哪些通訊協定?
  3. 使用 CIM 會話而不是使用 Get-CimInstance電腦名稱的一些優點為何?
  4. 如何指定預設通訊協定以外的替代通訊協定來搭配 Get-CimInstance使用?
  5. 如何關閉或移除 CIM 會話?