當你編寫 PowerShell 腳本或函數時,通常希望通過參數接受用戶輸入。如果不限制這些參數接受的值,就無法保證會出現不適當的值的情況。本文將介紹如何使用 PowerShell 的 ValidateSet 參數驗證屬性,將這些值限制為只能是您定義的值。
在編寫 PowerShell 腳本或函數時,可以使用多種不同的驗證屬性來檢查參數的值是否可接受,並在值不可接受時通知用戶。
本文專注於 ValidateSet 驗證屬性。您將學習到 ValidateSet 的作用,為什麼您可能希望在代碼中使用 ValidateSet,以及如何使用它。您還將了解到 ValidateSet 啟用的選項補全功能,這將有助於用戶提供有效的參數值。
PowerShell ValidateSet:簡要概述
ValidateSet是一個參數屬性,允許您定義一組元素,這些元素只能作為該參數的值接受。
例如,也許您有一個腳本被定義為與 Active Directory 域控制器一起工作。此腳本有一個參數,用於指定域控制器的名稱。在您事先知道腳本需要的值時,限制可接受的值列表為實際的域控制器名稱是有意義的。ValidateSet 允許您實現這一能力。
需求
本文將提供一個學習指南。如果您打算跟隨進行學習,您需要以下工具:
- Visual Studio Code或任何其他的程式碼編輯器。我將使用Visual Studio Code。
- 至少需要PowerShell 5.1來執行本文中的大多數程式碼。有一個部分需要PowerShell 6.1或更新版本,我會在需要時進行標識
本文中的所有程式碼已在以下環境中進行過測試:
Operating System | PowerShell Versions |
---|---|
Windows 7 SP1 | 5.1, Core 6.2 |
Windows 10 1903 | 5.1, Core 6.2 |
Linux Mint 19.2 | Core 6.2 |
為了解釋ValidateSet的概念,您將建立一個名為Get-PlanetSize.ps1的小型腳本。該腳本返回我們太陽系中行星的大小資訊。
您將從一個簡單的腳本開始,逐步提高其處理來自最終用戶的輸入能力,並使他們能夠輕鬆地發現可能的參數值。
入門指南
首先,將以下PowerShell程式碼複製並粘貼到您最喜歡的文本編輯器中,並將其保存為Get-PlanetSize.ps1。
從PowerShell提示符處運行該腳本,您應該會得到以下結果:
這是一個提供信息但不夠靈活的版本;即使您只想查詢火星的信息,也會返回所有行星的信息。
也许你想要指定一个单独的行星而不是返回所有行星。你可以通过引入一个参数来实现这个功能。让我们看看如何实现这个功能。
使用参数接受输入
为了让脚本接受一个参数,将一个Param()
块添加到脚本的顶部。将参数命名为Planet
。一个适当的Param()
块如下所示。
在下面的示例中,[Parameter(Mandatory)]
这一行确保了必须始终向脚本提供一个行星名称。如果缺少行星名称,脚本将提示用户输入。
将这个Planet
参数简单地加入到脚本中的方法是将$planets.keys | Foreach-Object {
这一行改为$Planet | Foreach-Object {
。现在,你不再依赖于之前静态定义的哈希表,而是读取Planet
参数的值。
现在,如果你运行脚本并使用Planet
参数指定一个行星,你只会看到关于那个特定行星的信息。
很好。脚本完成了吗?也许还没有。
选项太开放
如果你尝试使用Get-PlanetSize.ps1来查找行星Barsoom的直径,会发生什么?
嗯,不对。Barsoom不在行星列表中,但脚本仍然运行。我们该如何修复这个问题?
問題在於腳本接受任何輸入並使用它,而不論它是否為有效值。腳本需要一種方式來限制接受哪些值作為Planet
參數。輸入ValidateSet!
確保僅使用特定值
A ValidateSet list is a comma-separated list of string values, wrapped in single or double-quotes. Adding a ValidateSet attribute to a script or function parameter consists of adding a line of text to the Param()
block, as shown below. Replace the Param()
block in your copy of Get-PlanetSize.ps1 with the one below and save the file.
嘗試再次運行腳本,並將Barsoom作為Planet
參數。現在將返回一條有用的錯誤消息。該消息具體說明了出錯的原因,甚至提供了參數的可能值列表。
使PowerShell的ValidateSet區分大小寫
ValidateSet屬性默認情況下不區分大小寫。這意味著它將接受任何字符串,只要它在允許的列表中並且具有任何大小寫方案。例如,上面的示例將同樣容易地接受Mars
和mars
。如果需要,您可以通過使用IgnoreCase
選項強制ValidateSet區分大小寫。
ValidateSet中的IgnoreCase
選項是一個驗證屬性,用於確定所提供的值是否與有效值列表完全匹配。默認情況下,IgnoreCase
設置為$True
(忽略大小寫)。如果將其設置為$False
,則將mars作為Get-PlanetSize.ps1
中的Planet
參數的值將生成錯誤消息。
您可以通過在有效值列表的末尾為其分配$true
值來使用IgnoreCase
選項,如下所示。
現在當您嘗試使用 Planet
的值並不完全符合清單中的值時,驗證將失敗。
使用 Tab 鍵自動完成
使用 ValidateSet 的另一個好處是它提供了自動完成功能。這意味著您可以使用 TAB 鍵在參數的可能值之間進行循環。這大大提高了腳本或函數的易用性,特別是在控制台中。
在下面的示例中,有幾點需要注意:
- 在顯示最後一個值後,自動完成會循環回第一個值。
- 儘管 ValidateSet 的值不是按字母順序列出的,但它們以字母順序呈現。
- 輸入首字母並按下 TAB 鍵會將自動完成提供的值限制為以該字母開頭的值。


您還可以在 PowerShell Integrated Scripting Environment (ISE) 中充分利用 ValidateSet 的自動完成功能,如下面的示例所示。ISE 的 Intellisense 功能會以漂亮的選擇框顯示可能的值清單。
Intellisense 會返回包含您輸入的字母的所有值,而不僅僅是以該字母開頭的值。

現在我們已經介紹了 Windows 5.1 中的 ValidateSet 驗證屬性,讓我們來看看 PowerShell Core 6.1 中新增了什麼,並看看這是否可以為我們的腳本提供更多的驗證功能。
理解 PowerShell 6.1 中 ValidateSet 的變更
隨著 PowerShell Core 6.1 的到來,ValidateSet 驗證屬性新增了兩個功能:
- ErrorMessage 屬性
- 透過存取 System.Management.Automation.IValidateSetValuesGenerator 中的類別使用 ValidateSet
ErrorMessage 屬性
當您向 Get-PlanetSize.ps1 提供錯誤的行星名稱時,預設的錯誤訊息是有幫助的,但有點冗長:
使用 ValidateSet 驗證屬性的 ErrorMessage 屬性來設定不同的錯誤訊息,如下面的範例所示。{0} 會自動替換為提交的值,而 {1} 會自動替換為允許的值清單。
替換腳本檔案中的 Param() 區塊並儲存。然後再次嘗試 Get-PlanetSize.ps1 -Planet Barsoom。注意下面的錯誤訊息比較簡短且更具描述性。
接著,看一下透過 PowerShell 類別定義 ValidateSet 中可接受的值的新方法。
PowerShell 類別
自 PowerShell 5 版本以來,已經提供了自訂類型的功能。隨著 PowerShell Core 6.1 的到來,現在可以使用類別來提供 ValidateSet 的值。
使用类可以解决 ValidateSet 的主要限制 – 它是静态的。也就是说,它作为函数或脚本的一部分嵌入其中,只能通过编辑脚本本身来更改。
与 ValidateSet 一起使用的新功能是使用 System.Management.Automation.IValidateSetValuesGenerator 类的能力。我们可以使用它作为继承的基础来创建自己的类。要使用 ValidateSet,该类必须基于 System.Management.Automation.IValidateSetValuesGenerator,并且必须实现一个名为 GetValidValues() 的方法。
GetValues() 方法返回您希望接受的值列表。将静态行星列表替换为 [Planet] 类的 Param() 块将如下所示。这个示例目前无法工作。继续阅读以了解如何实现这一点。
使用类作为 ValidateSet 值列表:一个真实的示例
为了演示使用类作为 ValidateSet 值列表,您将使用一个从 CSV 文本文件加载的列表来替换之前使用的静态行星列表。您将不再需要在脚本本身中维护一个静态值列表!
为类创建数据源
首先,您需要创建一个包含每个有效值的 CSV 文件。为此,请将此一组数据复制并粘贴到一个新文本文件中,并将其另存为与 Get-PlanetSize.ps1 脚本相同文件夹中的 planets.csv。
將類別添加到腳本中
在ValidateSet使用之前,任何由ValidateSet使用的類別都必須已經定義。這意味著Get-PlanetSize.ps1的結構目前無法運作。
必須先定義[Planet]
類別才能使用,所以它必須在腳本開頭。一個合適的基本類別定義如下:
在類別的GetValidValues()
方法中,使用Import-CSV
cmdlet匯入之前建立的文本檔planets.csv。檔案被匯入一個全域範圍的變數$planets
,以便在腳本的其他地方存取。
使用return
語句通過GetValidValues()
返回行星名稱的清單。在這些更改後,類別應該如下所示:
接下來,根據下面所示,從腳本中刪除$planets
雜湊表的宣告。被[Planet]
類別填充的全域變數$planets
包含了行星資料。
現在將剩下的原始程式碼封裝在一個名為Get-PlanetDiameter
的函數中,以與腳本的名稱區分開來。將原本位於腳本開頭的Param()
區塊放在函數內。將靜態的行星清單替換為對[Planet]
類別的引用,如下所示。
將這行代碼 $output = "行星 {0} 的直徑為 {1} 公里" -f $_, $planets[$_]
替換為以下兩行代碼。這將使腳本能夠在由 Import-CSV
創建的對象數組中查找行星,而不是之前創建的哈希表,你已經從腳本中刪除了該哈希表:
在進行這些更改之後,你的最終腳本應該如下所示:
請記住,從這一點開始,腳本只能在 PowerShell 6.1 或更高版本上運行
現在,你如何使用這個腳本?
運行腳本
你不能直接執行新版本的腳本來使用腳本。所有有用的代碼現在都包含在一個函數中。你需要使用“點源”來將文件包含到 PowerShell 會話中,以便從中訪問該函數。
將文件點源之後,你現在可以在 PowerShell 會話中使用新的 Get-PlanetDiameter
函數,並進行選項完成。
“這樣做有什麼好處?”,你問道。“腳本似乎以相同的方式工作,但使用代碼更加困難!”
試試這個:
- 打開之前創建的
planets.csv
文件。 - 添加一個新行,包含新的名稱和直徑。
- 保存 CSV 文件。
在您最初dot sourced腳本的同一個會話中,嘗試使用Get-PlanetDiameter
查找新行星的直徑。 它有效了!
以這種方式使用類別給我們帶來了幾個好處:
- 有效值列表現在與代碼本身分開,但文件中的任何更改都會被腳本檔案接收。
- 該文件可以由從不存取腳本的人維護。
- A more complex script could look up information from a spreadsheet, database, Active Directory or a web API.
正如您所見,使用類別提供ValidateSet值時,可能性幾乎無窮。
結束
我們在構建Get-PlanetSize.ps1
時涵蓋了很多內容,所以讓我們回顧一下。
在本文中您學到了:
- 什麼是ValidateSet驗證屬性以及為什麼您可能想使用它
- 如何將ValidateSet添加到PowerShell 函數或腳本中
- Tab鍵自動完成如何與ValidateSet一起工作
- 如何使用
IgnoreCase
屬性來控制您的ValidateSet是否區分大小寫 - 如何在PowerShell 6.1中使用
ErrorMessage
屬性與您的ValidateSet - 如何使用類別使動態的ValidateSet與PowerShell 6.1
您還在等什麼?立即開始使用ValidateSet吧!
進一步閱讀
Source:
https://adamtheautomator.com/powershell-validateset/