Windows PowerShell:通過命令而不是腳本完成操作

不要被“編寫腳本”這個術語嚇倒,因為您可以通過 Windows PowerShell 使用簡單的命令完成許多操作。

Don Jones

在 Windows PowerShell 爭取得到管理員接受方面,認知一向是我們所面臨的最大問題。 長期以來,管理員對該 shell 的認知是,它與 VBScript 一樣都是“腳本編寫語言”。 雖然由於腳本編寫語言可被用於完成大量操作而深受許多管理員喜愛,但由於其複雜性和陡峭的學習曲線,也使很多管理員望而卻步。

這令人感到非常可惜。 該 shell 支援基於腳本的強大功能,但同樣也支援更簡單的、以命令為導向的功能。 該 shell 的真正吸引人之處在于您可以使用上述任何一種方法來完成大量同樣的工作。

僅僅是一個腳本

下列函數將從命令列處以字串或輸入物件的“ComputerName”屬性的方式接受電腦名稱;它還會使用 Windows Management Instrumentation (WMI) 從每台電腦檢索 BIOS 和 OS 資訊。

function Get-Inventory{   [CmdletBinding()]   Param(       [Parameter(Mandatory=$true,                 ValueFromPipeline=$true,                 ValueFromPipelineByPropertyName=$true)]       [string] $computername   )   Process {      $os = gwmi win32_operatingsystem -computername $computername      $bios = gwmi win32_bios -computername $computername      $obj = new-object psobject      $obj | add-member noteproperty ComputerName $computername      $obj | add-member noteproperty OSBuild ($os.buildnumber)      $obj | add-member noteproperty SPVersion ($os.servicepackmajorversion)      $obj | add-member noteproperty BIOSSerial ($bios.serialnumber)      Write-output $obj   }}

請注意,圓括弧會強制 shell 執行運算式(例如從 $os 變數的物件中獲取 BuildNumber 屬性),並將該運算式的結果作為 Add-Member 的第三個參數值返回。

我也可以通過管道輸入靜態電腦名稱來運行此函數:

'localhost','server2' | Get-Inventory

或者,通過發送每行包含一個電腦名稱的文字檔的內容來運行此函數。

Get-Content names.txt | Get-Inventory

或者甚至是通過從 Active Directory 檢索電腦物件、將“名稱”屬性更改為 ComputerName,並通過管道傳輸下列內容:

Import-Module ActiveDirectoryGet-ADComputer –filter * | Select-Object @{Label='ComputerName';Expression={$_.Name}} | Get-Inventory

另外,我使用括弧來封裝可執行代碼。 $_ 預留位置代表通過管道輸入 Select-Object cmdlet 的物件。 上述操作的結果均為格式簡潔的表,包含四列。 我可以輕鬆地將上述輸出重定向至檔、印表機或網格,或者甚至是在顯示結果之前對其進行篩選和排序。 例如,

Get-Content names.txt | Get-Inventory | Where { $_.BuildNumber –eq 7600 } | Sort ComputerName

再次重申,括弧封裝一個可執行代碼塊,即我希望篩選的運算式,而 $_ 預留位置代表通過管道傳入的物件。

命令性能

類似那樣的腳本並沒有錯誤,但是需要處理大量工作。 對於這種腳本編寫人員或者說程式師式方法,許多管理員都認為任務過於繁重。 通過一個稍微複雜的命令也可以完成同樣的任務。 打起精神來:

Get-WmiObject Win32_OperatingSystem -computername (get-content names.txt) | Select-object @{Label="ComputerName";Expression={$_.__SERVER}},             @{Label="OSBuild";Expression={$_.BuildNumber}},             @{Label="SPVersion";Expression={$_.ServicePackMajorVersion}},             @{Label="BIOSSerial";Expression={(gwmi win32_bios -comp $_.__server).serialnumber}}

這裡要完成許多操作。 下麵是操作詳解:

  1. 首先,運行 Get-WmiObject,從特定的電腦名稱中檢索 Win32_OperatingSystem 物件。 如果您定期閱讀此專欄,您就可能知道 Get-WmiObject 所返回的物件始終包括一個 __SERVER 屬性,該屬性包含 WMI 物件的來源電腦名稱。
  2. WMI 物件通過管道傳輸到 Select-Object。 我使用四個散清單來定義四個屬性:ComputerName、OSBuild、SPVersion 和 BIOSSerial。 每個散清單都會指定一個標籤和一個運算式,其中標籤將隨後用作輸出的列標題。 該散清單通過使用 @ 陣列運算子後跟包含在括弧內的標籤/運算式定義構成。 這些括弧封裝定義散清單運算式部分的可執行代碼。
  3. 對於前三列,該運算式只是指該物件的現有屬性;我只不過更改了屬性名稱。
  4. 對於第四列,我的運算式實際上是在同一台伺服器上執行第二次 WMI 查詢。 它會從 __SERVER 屬性中提取電腦名稱。 查看整個 WMI 調用是如何封裝在圓括弧內的?這會強制先執行該運算式。 該運算式所得到的任何物件都將代替圓括弧內部分插入。 右括弧後面的句點使我能夠訪問得到的物件的屬性,因此我可從第四列訪問其 SerialNumber 屬性。

在某種程度上,此語法比我所啟動的腳本更難讀。 它比較緊湊,並使用了大量標點符號。 您可以將其用作範本,並根據您的需要進行修改。 如果您不明白為什麼它無法工作,請在我的 ConcentratedTech.com 博客上提問,我會為您解答。

不要將它稱為腳本

我的意思是我們不必將 Windows PowerShell 作為指令碼語言使用。 我演示的命令可能複雜,但也不會比我所見到的管理員為舊式 Cmd.exe shell 編寫的冗長命令更複雜。 雖然需要進行一些訓練,但熟悉其語法之後,與編寫完整的腳本或函數相比,該命令要簡單的多。

因此,請不要看到“指令碼語言”便不願採用該 shell。 您可以選擇使用腳本編寫較為簡單的功能。

Don Jones

Don Jones是 Concentrated Technology 的創始人,他會在 ConcentratedTech.com 解答有關 Windows PowerShell 和其他技術的問題。他也是 Nexus.Realtimepublishers.com 的撰稿人,他的許多著作還在他的網站上以電子版的形式提供。

相關內容