Windows PowerShell美觀大方

Don Jones

希望指令碼產生美觀的輸出是很正常的,因此經常有人問我有什麼好辦法可以產生像是表格這類的東西。要這麼做其實有好幾種方法,第一步是撰寫指令碼以便把資料 ─ 也就是要格式化顯示的任何資料 ─ 放入名為

$data1、$data2 和 $data3 的變數。接下來就可以開始將資料格式化。

文字之道

網路上

您如果想要快速瀏覽本月 Windows PowerShell 專欄中所探討的方法,請前往 technetmagazine.com/video 看看 Don Jones 如何實際操作這些指令程式。

人們處理這項工作最常見的方法,跟他們處理 VBScript、Perl、KiXtart 或其他文字導向的語言一樣。一開始我可能會先寫出螢幕上的一組欄標題:

Write-Host "ColumnA'tColumnB'tColumnC"

請注意,`t 在 Windows PowerShellTM 中是一個插入定位字元的特殊逸出序列。若要寫出表格中的每一行 — 還記得我的資料是在 $data1、$data2 和 $data3 中 — 我有幾項選擇。其中之一是直接寫入變數,仰賴命令介面自行在雙引號內以它們的內容取代變數:

Write-Host "$data1't$data2't$data3"

另外一種稍微比較吸引人的方法,是利用 –f 運算子來達成同樣的目的。這種方法會將格式與資料相區隔,並形成我個人認為既方便閱讀且更容易維護的一行程式碼:

Write-Host "{0}'t{1}'t{3}" –f $data1,$data2,$data3

不過,這整套方法卻有個明顯的問題。首先,藉由主控台視窗裡面固定的定位點,我讓自己處於一些奇怪格式中。比方說,假設特定的表格列在第一欄中有 24 個字元的值,我會把該列的整個格式弄亂。另外,因為我是使用 Write-Host 輸出此文字,所以等於只能使用主控台顯示。

如果想要把輸出傳送到檔案或使用其他格式並不容易。最重要的是,這種以文字為基礎的作法會完全忽略我原本使用的以物件為基礎的命令介面,而無法充分運用 Windows PowerShell 所提供的各種超棒技術和功能。

Windows PowerShell 之道

Windows PowerShell 是一種物件導向的命令介面。也就是說,在理想的情況下,您所處理的所有一切內容都應該是在物件中,好讓命令介面在必要時把內容轉換成文字顯示。但是您要怎麼為任意資料建立物件呢?

延續我的範例,我開始先建立一個空白的自訂物件,然後把它存放在變數中:

 $obj = New-Object PSObject

這為我提供一個全新的空白物件來處理。我接下來以屬性的形式將資料加入物件中。我是直接將物件輸送到 Add-Member 指令程式進行這個動作。我新增一個叫做 NoteProperty 的東西,為屬性命名 (使用欄標題作為屬性名稱是個不錯的主意),然後將資料插入作為屬性的值:

 $obj | Add-Member NotePropertyColumnA $data1
$obj | Add-Member NotePropertyColumnB $data2
$obj | Add-Member NotePropertyColumnC $data3

現在我只要將這個物件輸出 — 到管線,而不是到主控台就行了:

Write-Output $obj

我接著可以針對每個需要輸出的表格列重複這些步驟。下面是一個簡短的函式,它會接受一個字串並隨同原始的字串輸出大小寫的版本:

functionStringVersions {
param([string]$inputString)
  $obj = New-Object PSObject
  $obj | Add-Member NoteProperty Original($inputString)
  $obj | Add-Member NoteProperty Uppercase($inputString.ToUpper())
  $obj | Add-Member NoteProperty Lowercase($inputString.ToLower())
  Write-Output $obj
}  
$strings = @("one","two","three")
foreach ($item in $strings) {
StringVersions $item
}

我先從字串變數陣列下手,然後一次處理一個字串變數,再把它們傳送到函式。接著函式的輸出會寫入管線中。

您應該曉得,寫這段程式碼有比較簡單的方式,但我選擇這種方法是因為它可清楚的表達我的重點。結果如 [圖 1] 所示,是格式完美的表格。這是因為命令介面早已知道如何格式化表格中的物件。

[圖 1] 顯示在表格中的 Windows PowerShell 輸出

[圖 1]** 顯示在表格中的 Windows PowerShell 輸出 **(按一下影像可放大檢視)

每當物件有四個以下的屬性時,Windows PowerShell 都會自動選擇表格。所以現在我不用動手就可以擁有一個雅致的表格了。

等等,還不止這些呢!

本月指令程式:Get-Command

我相信您已用過 Get-Command 或是它好記的別名 (gcm) 一兩次來檢閱可用的 Windows PowerShell 指令程式清單。但是您可能不知道 gcm 到底有多靈活。比方說,假如您想要查看 Windows PowerShell 對某服務可以進行的所有動作,就可以執行 gcm -noun service。或者,若是您想要查看所有的 Windows PowerShell 匯出選項,可以試試 gcm -verb export。如果您只是要查看某特定嵌入式管理單元所加入的指令程式,例如 PowerShell Community Extensions,可以試試 gcm -pssnapin pscx (您可以使用任何嵌入式管理單元來取代「pscx」,查看該嵌入式管理單元的指令程式)。

正如您所見,Get-Command 在探索 Windows PowerShell 上可說是扮演著舉足輕重的角色。您甚至不用查閱手冊,它就可以讓您確知哪項功能可用。而且就探索功能來說,gcm 要比使用像是 Help * 等命令更正確的多。Help 功能只會列出可用的說明主題。任何未隨說明檔發行的指令程式並不會顯示在說明清單中 — 即使指令程式在您需要時可供使用也一樣。

這種方法的好處不只是提供表格而已。當您處理物件時,Windows PowerShell 還知道如何處理一大堆事情。想要將資料放在 CSV 檔案中?就用 Export-CSV。偏好使用 HTML 表格嗎?不妨把物件輸送到 ConvertTo-HTML。需要清單格式嗎?把它們輸送到 Format-List 就搞定了。透過使用物件,您可以利用命令介面早知道要怎麼處理的各種事項。以下是一個修改過的範例:

functionStringVersions {
  PROCESS {
   $obj = New-Object PSObject
   $obj | Add-Member NoteProperty Original($_)
   $obj | Add-Member NoteProperty Uppercase($_.ToUpper())
   $obj | Add-Member NoteProperty Lowercase($_.ToLower())
   Write-Output $obj
}
}

這次我把函式修改成接受管線輸入 — 這在處理物件時,向來是比較好的辦法 — 然後輸出到管線。

這個函式現在在 PROCESS 指令碼區塊內有自己的程式碼。這表示函式會接受管線輸入,而且會針對每個從管線送入的物件執行一次 PROCESS 指令碼區塊。

在 PROCESS 指令碼區塊內,特殊的 $_ 變數指的是目前正在處理的管線物件。這個動作產生的實際結果是,我現在可以直接輸入字串陣列:

@("one","two","three") | StringVersions

因為函式將它的輸出放到管線中,所以我得到一個表格。在管線的尾端,命令介面知道要呼叫它的格式化子系統,這個子系統決定使用表格,因為管線內的物件具有少於五個的屬性 (如果有更多屬性,命令介面預設會使用清單)。

但我不用仰賴預設的行為。我只要將這些物件輸送到另一個指令程式,完成其他作業就大功告成了:

@("one","two","three") | StringVersions | Format-List
@("one","two","three") | StringVersions | ConvertTo-HTML | Out-File "strings.html"
@("one","two","three") | StringVersions | Export-CSV "strings.csv"
@("one","two","three") | StringVersions | Select Uppercase,Lowercase -unique

[圖 2] 顯示第二個範例在網頁瀏覽器中顯示所得的 HTML。只要將我的輸出資料呈現在物件中,而不是以簡單文字呈現,我馬上就能夠完整存取命令介面內建的豐富功能 — 各種格式化配置、HTML 轉換、匯出選項,還可以排序、篩選和群組等。

[圖 2] HTML 格式的 Windows PowerShell 資料輸出

[圖 2]** HTML 格式的 Windows PowerShell 資料輸出 **(按一下影像可放大檢視)

這項功能威力無窮,事實上,我甚至會建議您所寫的每個指令碼都應該產生物件作為它的輸出,這樣一來,您就可以盡可能透過許多不同的方法來使用該項輸出 — 而且連多寫一行程式碼都不必。

Don Jones 是 Windows 系統管理自動化方面的專家,並且著有《Windows PowerShell:TFM》和《VBScript, WMI, and ADSI Unleashed》等書。您可以透過 ScriptingAnswers.com 上的論壇與他聯絡。

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