Windows PowerShellWMI 連線

Don Jones

在 VBScript 的國度裡,我最信賴的其中一項技術是 Windows Management Instrumentation,或稱 WMI。有趣的是,Windows PowerShell 與 WMI 的關係相當深厚,不單就技術觀點而言,Windows PowerShell 的架構設計師 Jeffrey Snover,也曾是創造

Wmic.exe 的要角之一。Wmic.exe 是 Windows Server® 2003 時代用來與 WMI 搭配使用的命令列工具。它在許多方面是 Windows PowerShell™ 的前驅,因為它們的運作方式有點類似 (如需 WMIC 的詳細資訊,請參閱 John Kelbley 在 2006 年 7 月期《TechNet Magazine》內發表的文章,網址為 microsoft.com/technet/technetmag/issues/2006/09/WMIData)。

跟此命令介面的其餘功能一樣,Windows PowerShell 也是以相同一致、物件為基礎的方式提供 WMI 支援。這使得 WMI 學習和使用起來比早期的技術 (如 VBScript) 還要簡單許多 — 特別是在臨機操作的情況下。

WMI 入門

如果您讀過指令碼書籍和文章,幾乎處處都會提到 WMI。然而,真正使用 WMI 時又很容易陷入困境,因為您會忘了它實際上是怎麼建置的 — 知道它的建置方式對於了解它在 Windows PowerShell 中如何運作尤為重要。

WMI 主要是一個類別組織化的系統,這些類別代表 Windows® 作業系統及其他 Windows 軟硬體產品的管理資訊。類別其實不過是某些特定軟體或硬體元件擁有的屬性和功能的抽象描述。比方說,邏輯磁碟類別描述的類別可能包含序號、固定儲存容量、可用的容量等等。另一方面,描述 Windows 服務的類別可能會指出該服務具有名稱,可以被啟動和停止,並說明它目前的狀態等等。

在 WMI 中,類別代表 WMI 可以管理的所有內容。假如 WMI 沒有某元件的類別,就無法管理該元件。Microsoft 在 msdn2.microsoft.com/aa394554.aspx 記錄核心 Windows WMI 類別,其他產品 — 例如網際網路資訊服務、SQL Server™ — 則是個別記載其 WMI 類別。

因為類別很多,WMI 於是將它們組織成命名空間階層。例如,包含核心 Windows OS 類別的命名空間稱為 root\cimv2,而 Microsoft IIS 6.0 則是將其類別存放在 root\MicrosoftIISv2 中。為了方便,root\cimv2 命名空間即是 WMI 預設的命名空間,這是由 Windows PowerShell 共用的設定,以便與這些核心類別搭配使用。

「例項」是類別實際發生的次數。舉例來說,若您的電腦有兩個邏輯磁碟,您就會有兩個 Win32_LogicalDisk 類別的例項。如果電腦上有 50 個服務正在執行,WMI 會看到 50 個 Win32_Service 類別的例項。使用 WMI 基本上等於是要求 WMI 給您一或多個例項,然後檢查該些例項的屬性以找出您所需的管理資訊,或執行這些例項的方法以進行管理變更,例如啟動或停止服務。

WMI 是採用主從式架構。Windows 自 Windows 2000 以後的每個版本都內建有 WMI (後續版本擴增了可用的類別數),這表示您有現成的 WMI 用戶端和 WMI 伺服器可用。使用 WMI 時,實際上是傳送要求給任何您感興趣的電腦上執行的 WMI 服務。該 WMI 服務會擷取您指定的 WMI 例項,並將它們傳回給您使用。這也正是 Windows PowerShell 派上用場的時候,它會簡化要求例項,取回例項,以及使用例項的程序。

取得 WMI 物件

WMI 類別例項廣義來說是指物件,因此可以解釋在 Windows PowerShell 中擷取該些例項的方法是 Get-WMIObject cmdlet。此 cmdlet 的別名 gwmi 很好記,我會在大多數的範例中用到它。最簡單的用法是,直接指定您要擷取的 WMI 類別名稱,然後就悠哉等著看結果 (見 [圖 1])。執行 gwmi win32_service 時,Windows PowerShell 連線到我的本機電腦上的 WMI 服務 (因為我沒有指定其他電腦),並連線到 root\cimv2 命名空間 (因為我沒有指定其他命名空間)。Windows PowerShell 擷取指定類別的所有例項,另外因為我沒有告訴它要對這些例項採取什麼動作,因此 Windows PowerShell 將它們轉換成文字表示。換言之,Windows PowerShell 取得這些物件並產生了一些我 (身為人類) 看得懂的文字。

[圖 1] 執行 gwmi win32_service 時,Windows PowerShell 以可讀的文字格式傳回指定類別的所有例項

[圖 1]** 執行 gwmi win32_service 時,Windows PowerShell 以可讀的文字格式傳回指定類別的所有例項 **

具體地說,Windows PowerShell 是藉著讀取和顯示選定類別屬性的名稱和值,將 WMI 物件轉換成文字。對於 Win32_Service 類別,它會選取一組六個的屬性。

Windows PowerShell 實際上可透過這種方式將任何物件轉換成文字。它選擇顯示的屬性絕大部分是根據 Windows PowerShell 安裝資料夾中的一組 .format.pslxml 檔案定義而成。這些格式定義檔案已經過 Microsoft 數位簽署,因此建議您不要變更這些檔案,不過您可提供自己的格式化檔案 (我在將來的專欄中會更深入討論此主題)。

gwmi cmdlet 可幫助您探索電腦以找出可用的類別。比如,執行 gwmi –namespace "root\cimv2" –list 可提供該命名空間當中完整的類別清單。不過要記住,您電腦上的類別只有在電腦是由您管理時才相關,如果您管理的是遠端電腦,那麼應該了解該系統上可用的類別。若要這麼做,您可以使用 gwmi 的 –computer 參數連線到遠端電腦。比如,gwmi –namespace "root\cimv2" –list –computer ServerA 會列出名為 ServerA 之遠端電腦上 \root\cinv2 命名空間內的所有類別。

遠端 WMI

在 1.0 版的 Windows PowerShell 中,gwmi 可算是唯一直接支援遠端管理的 cmdlet。這主要是因為遠端控制已內建至基礎 WMI 架構。而且因為 Windows PowerShell 僅利用該現有架構,所以受限於該架構的安全性功能。以下為範例:

C:\> gwmi -namespace “root\cimv2” -computer
mediaserver -list
Get-WmiObject : Access is denied. (Exception
from HRESULT: 0x80070005 (E_ACCESSDENIED))
At line:1 char:5
+ gwmi <<<< -namespace “root\cimv2” -computer
mediaserver -list
PS C:\>

在此例中,我試著連線到一台我沒有存取權限的遠端電腦 — 叫做 MediaServer。身為系統管理員,我應該有權使用此電腦的 WMI 服務,但可能我的本機工作站的憑證權限不足。比方說,我可能登入了另一個不受信任的網域,或者我可能是以低權限的帳戶登入。幸虧 gwmi 支援 –credential 參數,可讓我為 WMI 連線指定另外一組使用者憑證。您在下面會看到一個非常簡單的範例:

gwmi win32_service –credential mydomain\administrator –computer mediaserver

我的憑證 — 具體來說是我的使用者名稱 — 是以 DOMAIN\Username 的格式提供。

請注意這裡沒有地方可以輸入密碼 — Windows PowerShell 會另外提示。Windows PowerShell 是故意不在命令列上提供輸入密碼的管道,因為這麼做便可讓您將密碼寫死到指令碼檔案中,這無疑會提高安全性風險。不過,還有另外一種方法可以使用這個 –credential 參數,就是事先建立一個叫做 PSCredential 的憑證物件。關鍵是 Get-Credential cmdlet:

$cred = get-credential mydomain\administrator

當我執行此命令時,還是會收到要對應密碼的提示。不過這一次,建立的憑證物件是存放在 $cred 變數中。如果查看 $cred 的內容,會看到名稱而不是密碼:

PS C:\> $cred

UserName
--------
mydomain\adminstrator

我接著就可以任意重複使用該憑證物件,多少次都可以:

gwmi win32_service –credential $cred –computer mediaserver

透過預先定義一個可重複使用的憑證物件,簡化了 WMI 連線至遠端電腦的重複作業。可惜無用武之地,因為 Get-WMIObject cmdlet 目前並不像 VBScript 一樣支援指定驗證等級 (亦稱為模擬)。請參閱 msdn2.microsoft.com/aa389290.aspx 以取得詳細資訊。

自動探索

我最喜歡 Windows PowerShell 的一點是它不會使事情過於無趣。我向您說明過 Windows PowerShell 針對我查詢的 Win32_Service 類別只挑選一組屬性。但命令介面仍可存取所有屬性,甚至可以告訴您這是什麼屬性。如果想這麼做,只要將物件輸送到 Get-Member cmdlet (或是它的別名 gm) 即可,如 [圖 2] 所示。

[圖 2] 將物件輸送到 Get-Member cmdlet 會告訴您可存取哪些方法和屬性

[圖 2]**  將物件輸送到 Get-Member cmdlet 會告訴您可存取哪些方法和屬性 **(按影像可放大)

除了屬性外,命令介面還會列出可用的方法,這表示不需要說明文件也可以了解類別的作用。我可以看到類別自己提供變更例項設定、暫停服務、停止服務等方法。

要利用這些方法,或顯示其他屬性,最簡單的方法通常是將例項放入變數中:

$server = gwmi win32_operatingsystem
$server.reboot()

這個範例將擷取 Win32_OperatingSystem 類別唯一可用的例項 (此類別在每台電腦只有一個例項),並將它儲存到 $server 變數中。之後便會使用 $server 變數來存取例項的 Reboot 方法,以重新啟動電腦。使用這個方法時要小心!

高階查詢語言

如果您在 VBScript 或其他技術下用過 WMI,可能已經習慣使用以 WQL (WMI 查詢語言) 寫成的查詢來擷取 WMI 類別例項。它的語法類似 SQL,因此更容易擷取特定例項 (例如特定服務) 而不是擷取指定類別的所有例項。幸運的是,gwmi 也可讓您指定查詢,如下所示:

gwmi –query “select * from win32_service where name=’alerter’”

gwmi 這樣的語法 (這是在 Windows PowerShell 正式發行之前新增的) 非常實用,而且非常方便您遷移針對其他用途開發的複雜 WMI 查詢。另外,Windows PowerShell 向來都會在傳回豐富物件時,一同傳回這些物件本身的屬性和方法,讓您徹底運用 WMI 的管理威力。

與 WMI 一同邁進

WMI 會繼續針對未來的 Windows 版本進行開發,新添類別和功能,而且還會持續加入 Microsoft 新產品中。雖然大多數 Microsoft 產品都還沒發行專門以 Windows PowerShell 為基礎建置的版本,但是其 WMI 連線能力儼然是使現今的 Windows PowerShell 這麼實用最大的優點之一。

我所介紹的 WMI 只不過是皮毛而已,不過,仍希望這足以激發您探索 Windows PowerShell 的興趣,並自行研究其他可用的功能。

Don Jones 是 SAPIEN Technologies 的專案與服務總監,也是《Windows PowerShell:TFM》(SAPIEN Press) 的作者之一。請透過 Don 的網站與他連絡:www.ScriptingAnswers.com

© 2008 Microsoft Corporation and CMP Media, LLC. 保留所有權利;未經允許,嚴禁部分或全部複製.