Windows PowerShell:是麥片 (Cereal) 還是序列 (Serial)?
序列化有助於以 Windows PowerShell 匯出或擷取物件。
Don Jones
我在講授有關 Windows PowerShell 的課程時,反復告訴我的學員將物件傳送到 Get-Member:
Get-Process | Get-Member
Get-Member(簡稱 GM)旨在使用名為反射的 Microsoft .NET Framework 功能。 此功能顯示有關物件的資訊,包括物件的正式名稱、屬性、方法等。 使用此 cmdlet 可以快速查看物件的功能,比在搜尋引擎中四處尋找或搜尋 MSDN 庫網站要容易得多。
但是,當學員嘗試執行此 cmdlet 時,他們有時會在 Get-Member 中看到如下內容:
TypeName: Deserialized.System.Diagnostics.Process
是的,我知道什麼是進程,但反序列化進程呢? 通過進一步研究 Get-Member 輸出還發現,普通進程可以停止並執行其他操作,而反序列化進程好像沒有任何方法,也就是說您無法要求反序列化進程執行任何操作。 這是怎麼一回事?
物件如何成為序列化…或序列化
在 Windows 中,物件行使的是部分軟體的功能。 進程實際上就是軟體應用。 進程物件提供用來描述進程的某些特性的屬性,例如進程的名稱、記憶體利用率等;物件可能還包含用來觸發操作(例如停止、刷新等)的方法。
當物件位於您的電腦上時非常有用,但沒有任何實際可行的方法可以通過網路傳輸整個物件。 在 XML 中,通常使用序列化創建物件的文本表示形式。 图 1 顯示已被序列化到 XML 中的進程物件。
實際上,序列化技術獲取物件屬性的快照,將它們編碼到結構化 XML 檔,然後通過網路傳輸該檔。 此時,該 XML 檔實際上只是一個文字檔。 實際運行的進程和該 XML 檔之間已不再存在直接連接。 該檔是傳輸物件的屬性的一個時間點視圖。
圖 1 XML 檔將序列化進程物件。
序列化不會保留物件的方法。 無法返回到原始物件並讓它執行方法。 當外殼需要讀取該序列化物件時,它將對該物件進行反序列化。 它通過讀取 XML 文本並構建看上去與原始物件非常相像的某個物件來執行反序列化 — 當然,這個過程不會使用該物件的所有方法。
序列化物件的常見情況
Windows PowerShell v2 一般在下列兩種情況下使用序列化:
- 使用 Export-CliXML 將物件匯出為 XML 格式時
- 使用 Windows PowerShell 遠端處理功能檢索遠端電腦中的物件時
例如,此命令將檢索遠端電腦中正在運行的進程,根據虛擬記憶體利用率對它們進行排序並顯示前 10 個進程:
invoke-command { ps } -computer server-r2 | sort vm -desc | select -first 10
您還可以在遠端電腦上執行所有排序和選擇操作,這有利於通過網路傳輸較少的序列化物件:
invoke-command { ps | sort vm -desc | select -first 10 } -computer server-r2
關鍵在於通過網路傳輸的物件已不再是實際進程。 它們已被轉化為 XML 格式。 您無法獲取其中一個進程並讓它自行停止,因為您的本地電腦上的進程與遠端電腦上正在運行的進程之間已斷開連接。
序列化在排序物件資訊時也非常有用。 例如,假設您將所有服務的配置匯出到一個 XML 檔中:
get-wmiobject win32_service | export-clixml baseline.xml
然後,您可以使用該快照與以後的伺服器配置進行比較。 這將提醒您對配置進行的任何有意或無意更改。
此命令將當前服務物件與您的快照中的服務物件進行比較:
compare-object (get-wmiobject win32_service) (import-clixml baseline.xml)
在此實例中,反序列化物件不包含方法這一事實並不重要。 包含所有配置資訊(如啟動模式、登錄帳戶等)的是屬性。
請謹慎使用序列化…或序列化物件
然而,當您需要訪問物件的方法時,序列化可能會帶來問題。 例如,此命令在您的本地電腦上運行正常(將重新開機電腦,所以不要運行此命令,除非您已準備好重新開機電腦):
Get-WmiObject Win32_OperatingSystem | ForEach-Object { $_.Reboot() }
但是,以下命令無法正常運行:
Invoke-Command { Get-WmiObject Win32_OperatingSystem } –computer Server-R2 | ForEach-Object { $_.Reboot() }
這是因為 Invoke-Command 的結果是一個不包含方法的反序列化物件。 我們無法執行 Reboot 方法。 但是,我們可以這樣做:
Invoke-Command { Get-WmiObject Win32_OperatingSystem | ForEach-Object { $_.Reboot() }} –computer Server-R2
現在,在物件被序列化並丟失其方法之前,我們將在遠端電腦上調用 Reboot 方法。 因此,每當序列化要產生問題時,通常都會有解決方法。 您只需注意何時進行序列化。
Don Jones 是 Concentrated Technology 的創始人,他會在 ConcentratedTech.com 解答有關 Windows PowerShell 和其他技術的問題。 他還是 Nexus.Realtimepublishers.com 的撰稿人,他的許多著作還在他的網站上以電子版的形式提供。