Windows PowerShell:通過命令而不是腳本完成操作
在 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 ActiveDirectory Get-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}}
這里要完成許多操作。下面是操作詳解:
- 首先,運行 Get-WmiObject,從特定的計算機名稱中檢索 Win32_OperatingSystem 對象。如果您定期閱讀此專欄,您就可能知道 Get-WmiObject 所返回的對象始終包括一個 __SERVER 屬性,該屬性包含 WMI 對象的來源計算機名稱。
- WMI 對象通過管道傳輸到 Select-Object。我使用四個散列表來定義四個屬性:ComputerName、OSBuild、SPVersion 和 BIOSSerial。每個散列表都會指定一個標簽和一個表達式,其中標簽將隨后用作輸出的列標題。該散列表通過使用 @ 數組運算符后跟包含在括號內的標簽/表達式定義構成。這些括號封裝定義散列表表達式部分的可執行代碼。
- 對于前三列,該表達式只是指該對象的現有屬性;我只不過更改了屬性名稱。
- 對于第四列,我的表達式實際上是在同一臺服務器上執行第二次 WMI 查詢。它會從 __SERVER 屬性中提取計算機名稱。查看整個 WMI 調用是如何封裝在圓括號內的?這會強制先執行該表達式。該表達式所得到的任何對象都將代替圓括號內部分插入。右括號后面的句點使我能夠訪問得到的對象的屬性,因此我可從第四列訪問其 SerialNumber 屬性。
在某種程度上,此語法比我所啟動的腳本更難讀。它比較緊湊,并使用了大量標點符號。您可以將其用作模板,并根據您的需要進行修改。如果您不明白為什么它無法工作,請在我的 ConcentratedTech.com 博客上提問,我會為您解答。
不要將它稱為腳本
我的意思是我們不必將 Windows PowerShell 作為腳本語言使用。我演示的命令可能復雜,但也不會比我所見到的管理員為舊式 Cmd.exe shell 編寫的冗長命令更復雜。雖然需要進行一些訓練,但熟悉其語法之后,與編寫完整的腳本或函數相比,該命令要簡單的多。
因此,請不要看到“腳本語言”便不愿采用該 shell。您可以選擇使用腳本編寫較為簡單的功能。
Don Jones 是 Concentrated Technology 的創始人,他會在 ConcentratedTech.com 解答有關 Windows PowerShell 和其他技術的問題。他也是 Nexus.Realtimepublishers.com 的撰稿人,他的許多著作還在他的網站上以電子版的形式提供。
【編輯推薦】