Windows Powershell變數的效用

Don Jones

如果您使用 Windows 指令碼語言,例如 VBScript 或 KiXtart,應該已習慣於變數只是某種資料儲存機制。Windows PowerShell 也有變數,但是其變數的效用遠大於舊式指令碼語言中的變數。Windows

PowerShell 的變數實際上是對應至 Microsoft® .NET Framework 中的基礎類別。而 Framework 中的變數是物件,也就是說,變數可以儲存資料,也可以利用許多種方式操作資料。事實上,Windows PowerShell™ 中的變數功能強大,所以 Windows PowerShell 指令碼語言沒有包含任何內建的資料操作函數。它不需要這些函數,因為變數本身已經提供了功能。

宣告變數

雖然 Windows PowerShell 中的 New-Variable cmdlet 允許您宣告變數及指派其初始值,不過您並不需要使用 cmdlet。您只要在作業中指派值給變數,就可以建立新變數:

$var = "Hello"

Windows PowerShell 中的變數名稱一律以貨幣符號 ($) 開頭,而且可以包含字母、數字、符號,甚至空格的混合 (不過若是使用空格,您必須以括號括住變數,例如 ${My Variable} = "Hello")。此範例建立一個名為 $var 的新變數,並為其指派初始值 "Hello"。因為在此範例中的值是一串字元,所以 Windows PowerShell 會使用 String 資料類型來儲存值。就 .NET Framework 而言,這是 System.String 類別,此類別可能擁有任何變數類型中最多的內建功能。假設我若是要檢視 $var 中之值的全部小寫版本,可以這麼做:

PS C:\> $var.ToLower()
hello
PS C:\>

ToLower 方法會內建在 System.String 類別中,且會產生字串值的全部小寫表示。但是它不會變更變數 $var 的實際內容。若要檢視 System.String 類別所能執行之所有工作的完整清單,可傳送字串變數到 Get-Member cmdlet,如下所示:

$var | get-member

[圖 1] 顯示輸出,其中包含幾十種用於操作字串的方法。幾乎 VBScript 字串操作函數所提供的所有功能,在 Windows PowerShell 中都改由字串變數的方法提供。

Figure 1 A look at the System.String class output

Figure 1** A look at the System.String class output **(按影像可放大)

在系統管理環境中,字串變數的許多功能比 VBScript 等語言中的字串函數更有用。假設您撰寫了一段指令碼,會從檔案讀入通用命名慣例 (UNC) 路徑,並會對路徑執行某些操作。您希望在嘗試使用路徑之前,先確認讀入的每個路徑都是 UNC。StartsWith 方法可讓您確認字串的值是以 UNC 要求的必要反斜線字元開頭:

PS C:\> $path = "\\Server\Share"
PS C:\> $path.StartsWith("\\")
True
PS C:\>

因為 StartsWith 會傳回 True 或 False 值,所以您可以在邏輯建構中使用此方法:

if ($path.StartsWith("\\")) {
 # code goes here
}

Windows PowerShell 甚至還提供變數之方法的自動完成形式,減少您必須打字的量。如果 $var 包含字串,您可以輸入

$var. 

然後按 Tab 鍵,這會顯示 $var 變數的第一個方法名稱。再按一次 Tab 鍵就會移至下一個方法,而按 Shift+Tab 鍵則會顯示前一個方法。以這種方式,可以循環顯示所有可用的方法,直到您找到所要的方法為止。

變數的混淆

到目前為止,我的範例都允許 Windows PowerShell 決定我的變數的資料類型。指派字串給變數實質上會強制變數成為 System.String 類別。另一方面,指派數字給變數通常會導致變數成為整數 (Interger) (或者更明確地說,成為 Int32,可以儲存特定範圍的值)。例如,設想下列範例:

PS C:\> $int = 5
PS C:\> $int | get-member

  TypeName: System.Int32

此截斷的輸出顯示 Windows PowerShell 會將 $int 當成 Int32 處理,它擁有自己的方法和屬性集合。而事實上,它的方法和屬性集合遠少於 String 類型的集合。

$int 會成為 Int32,原因在於其值並未以引號括住,而且值只包含數字。如果以引號括住,則會當成 System.String 來解譯。

讓 Windows PowerShell 決定使用何種資料類型不一定都會產生您要的結果。假設您從檔案讀取值,而且您希望值一律當成字串處理。但是,某些值可能只包含數字,使得 Windows PowerShell 可能會將這些值當成 Int32 或其他數字類型處理。這可能會導致您的指令碼發生問題。如果 Windows PowerShell 未將值辨識為字串,則 System.String 類別的所有方法都無法使用 (而且您的指令碼可能依賴這些無法使用的方法)。

若要解決此問題,您可以在首次使用變數時宣告特定的類型,強制 Windows PowerShell 將變數當成該類型處理。請看以下範例:

[string]$var = 5

$var 通常會是 Int32,但是我已經強制 Windows PowerShell 將 $var 當成 String,確保我可以使用與 System.String 類別關聯的所有方法。變數類型宣告也提供方便的程式碼自我說明,因為現在 $var 中的資料是何種類型已很明顯。事實上,我已經習慣一律為我的所有變數宣告特定的類型,完全不讓 Windows PowerShell 做決定。這使我的指令碼行為更好預測,而且在許多情況下,也節省我許多偵錯的時間。

您應該預期到強制宣告變數會有一些影響,不過不一定是壞的影響。以這個未宣告變數類型的範例為例:

PS C:\> $me = 5
PS C:\> $me = "Don"

$me 變數一開始是 Int32,但是在加入 "Don" 這個值後,Windows PowerShell 已將其變更為 String。只要變數尚未明確地設定為特定的類型,Windows PowerShell 就可以視需要變更變數的類型。

在此範例中,我使用 [int] 類型名稱強制將 $me 設定為 Int32:

PS C:\> [int]$me = 5
PS C:\> $me = "Don"
Cannot convert value "Don" to type 
"System.Int32". Error: "Input string 
was not in a correct format."
At line:1 char:4
+ $me <<<< = "Don"

然後,當我嘗試為其指派字串值時,出現了錯誤訊息。因為我已明確地強制 $me 設定為 Int32,所以 Windows PowerShell 應該要將字串 "Don" 轉換為整數值。但它無法進行轉換,也無法將 $me 的類型變更為 String。

好多的類型

Windows PowerShell 中有許多可用的類型。事實上,您可以使用任何 .NET Framework 類型 (以及數百種可用的類型)。不過,Windows PowerShell 會為常用的資料類型定義許多捷徑。[圖 2] 只是部分清單,顯示最常使用之類型捷徑中的 10 種。如需完整的清單,請參閱 Windows PowerShell 文件。

Figure 2 常用類型捷徑

捷徑 資料類型
[datetime] 日期或時間
[string] 字元字串
[char] 單一字元
[double] 雙精度浮點數
[single] 單精度浮點數
[int] 32 位元整數
[wmi] Windows Management Instrumentation (WMI) 執行個體或集合
[adsi] Active Directory 服務物件
[wmiclass] WMI 類別
[Boolean] True 或 False 值

您也可以使用完整的 .NET Framework 類別名稱宣告變數的類型,如下所示:

[System.Int32]$int = 5

此技巧允許您使用 .NET Framework 中的類型,但是在 Windows PowerShell 中並無特定捷徑的類型。

延伸類型

Windows PowerShell 中最棒的事,可能就是它能夠延伸這些變數類型的功能。在 Windows PowerShell 安裝資料夾中 (通常位於 %systemroot\system32\windowspowershell\v1.0,不過在 64 位元系統上,路徑可能稍有不同),可以找到名為 types.ps1xml 的檔案。您可以在記事本或 XML 編輯器 (例如 PrimalScript) 中編輯這個檔案。根據預設,雖然會列出其他許多類型,但是並不會列出 System.String 類別。不過,可以藉由將它新增到 types.ps1xml 檔案,為 System.String 類型新增功能。

變更之後,我必須關閉 Windows PowerShell,然後再重新開啟。我還必須確定本機指令碼執行原則允許執行未經簽署的指令碼,因為我並未簽署 types.ps1xml。

Set-executionpolicy remotesigned

現在,只要我重新啟動 Windows PowerShell 後,就可以使用新功能,如下所示:

PS C:\> [string]$comp = "localhost"
PS C:\> $comp.canping
True
PS C:\>

如您所見,我已新增了 CanPing 屬性至 System.String 類別。這會傳回 True 或 False,以指出本機電腦是否能夠 Ping 字串中所包含的位址。在 [圖 3] 中,您會注意到 WMI 查詢使用一個特殊的變數 $this。這個 $this 變數代表字串中所包含的目前值,也是字串變數的內容傳入 WMI 查詢的方式。

Figure 3 延伸 System.String 類型

<Type>
  <Name>System.String</Name>
  <Members>
    <ScriptProperty>
      <Name>CanPing</Name>
      <GetScriptBlock>
      $wmi = get-wmiobject -query "SELECT *
FROM Win32_PingStatus WHERE Address = '$this'"
      if ($wmi.StatusCode -eq 0) {
        $true
      } else {
        $false
      }
      </GetScriptBlock>
    </ScriptProperty>
  </Members>
</Type>

讓變數執行工作

Windows PowerShell 提供彈性、功能豐富的變數類型,以及同樣彈性的系統以延伸類型的功能。這些功能可以很容易地讓您在指令碼中建立強大的功能。事實上,變數在複雜的指令碼中可以成為主要的建置組塊,在許多情況下,可以提供在較複雜的函數中才有的進階功能。

從線上深入了解

我在每個月的第二個星期二會主持一系列的網路廣播,廣播中將繼續探討 Windows PowerShell 所提供的豐富指令碼功能,歡迎您參加。請造訪 microsoft.com/events/series/donjonesscripting.mspx,立即註冊。

2007 年 2 月 20 日,Windows PowerShell:The Scripting Crash Course

(英文)

參加此網路廣播,了解 Windows PowerShell 中的變數、語言建構、指令碼及函數。在這個一小時的速成課程中,我們會示範 Windows PowerShell 中簡單但有效的指令碼語言如何加快 Windows® 系統管理的自動化。我們也會探討讓 Windows PowerShell 指令碼盡可能容易的許多第三方工具。

2007 年 3 月 20 日,Windows PowerShell:Functions, Filters, and Efficiency

(英文)

學習在 Windows PowerShell 函數與篩選器中建立有效、模組化的程式碼。我們會探索 Windows PowerShell 中能讓您完全封裝函數與篩選器的強大範圍規則,並說明可以多容易地在不同專案重複使用這些函數和篩選器。我們也會示範如何將您自己的自訂函數加入 Windows PowerShell 中的全域範圍,全域範圍可以輕鬆容易地組合實用的公用程式函數庫。

2007 年 4 月 17 日,Windows PowerShell and Windows Management Instrumentation

(英文)

Windows PowerShell 可以存取 Windows Management Instrumentation (WMI) 所有的優點和功能。我們不只會說明如何使用 Windows PowerShell 存取 WMI,也會介紹如何透過 Windows PowerShell 管線傳遞 WMI 物件和集合。我們會探討如何在 Windows PowerShell 指令碼中使用 WMI 屬性和方法,並說明 WMI 中的基礎安全性與組態功能。

2007 年 5 月 22 日,Windows PowerShell:Converting from VBScript

(英文)

是否想要將 VBScript 的指令碼,甚至只是您的技能,轉換到 Windows PowerShell?請參加此網路廣播,了解如何做到。我們會探索 Windows PowerShell 如何包含 VBScript 的所有主要建構和功能,讓您很容易將您的 VBScript 技能轉譯到這個新的系統管理環境。我們會說明如何將 VBScript 中的工具轉換為 Windows PowerShell 中的原生指令碼語言。我們也會檢視 Windows PowerShell 中獨特的結構,並示範如何開始使用 Windows PowerShell 指令碼語言,讓您的工作更有效率並且更有效。

2007 年 6 月 19 日,Windows PowerShell:Under-the-Hood Extensions

(英文)

在這個網路廣播中,我們會探討 Windows PowerShell 如何使用功能強大且彈性的 .NET Framework 來處理資料,提供您管理字串、日期及其他資料類型的幾百個內建函數。但是,您知道可以使用 Windows PowerShell 指令碼來延伸這些函數嗎?我們會示範如何製作字串變數,其中不只包含電腦名稱,還可以告訴您電腦是否啟動並執行中。了解如何建立可以不使用外部函數,自動將資料格式化的日期和時間變數。請參加此課程,了解如何迅速在 Windows PowerShell 中建立各式各樣的新功能,讓 Windows 的系統管理更快且更容易。

Don Jones 是 SAPIEN Technologies 的專案與服務總監,也是 Windows PowerShell:TFM (SAPIEN Press) 的作者之一。Don 的連絡方式為:www.ScriptingAnswers.com

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