PowerShellスクリプトや関数を作成する際、パラメーターを介してユーザーからの入力を受け取ることがよくあります。これらのパラメーターが受け入れる値を制限しない場合、不適切な値が指定される状況が発生する可能性があります。この記事では、PowerShellのValidateSetパラメーター検証属性を使用して、指定した値のみを許可する方法について学びます。
PowerShellスクリプトや関数を作成する際、さまざまな検証属性を使用して、パラメーターに指定された値が受け入れ可能かどうかを確認し、受け入れ不可の場合にはユーザーに警告することができます。
この記事では、ValidateSet検証属性に焦点を当てます。ValidateSetの役割や、コードでValidateSetを使用する理由、使用方法について学びます。また、ValidateSetによって有効になるタブ補完機能についても説明します。この機能は、コードのユーザーが有効なパラメーターの値を提供するのに役立ちます。
PowerShell ValidateSet: 簡概
ValidateSetは、パラメーター属性であり、そのパラメーターの値として受け入れられる要素のセットを定義することができます。
たとえば、Active Directoryドメインコントローラーと連携するスクリプトがあるとします。このスクリプトには、ドメインコントローラーの名前を指定するパラメーターがあります。事前にどの値がスクリプトに必要であるかわかっている場合、ユーザーが「foobar」という値を使用できる理由はありません。ValidateSetを使用すると、そのような制限が可能になります。
要件
この記事は学習用の手順書です。この手順に従って進める場合、以下のものが必要です:
- Visual Studio Codeまたは他のコードエディタ。私はVisual Studio Codeを使用します。
- この記事のほとんどのコードには、少なくともPowerShell 5.1が必要です。ただし、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
パラメータを使用して特定の惑星についての情報のみを表示できます。
素晴らしいですね。スクリプトは完了しましたか?でも、まだかもしれません。
オプションがあまりにもオープンすぎる
Barsoomという惑星の直径をGet-PlanetSize.ps1を使って調べようとすると、どうなるでしょうか?
うーん、それは正しくありませんね。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.
を入力して、スクリプトを再実行してみてください。PlanetパラメータにBarsoomを使用してください。すると、役立つエラーメッセージが返されます。メッセージは、何が間違っているのか具体的に示しており、パラメータの可能な値のリストも提供しています。
PowerShellのValidateSetを大文字と小文字を区別するようにする
ValidateSet属性は、デフォルトでは大文字と小文字を区別しません。つまり、許可されたリスト内の任意の文字列を、大文字小文字の区別なく受け入れます。たとえば、上記の例では、Mars
と同じくらい簡単にmars
も受け入れます。必要に応じて、IgnoreCase
オプションを使用してValidateSetを大文字と小文字を区別するように強制することができます。
ValidateSetのIgnoreCase
オプションは、検証属性で、パラメータに指定された値が正確に有効な値リストと一致するかどうかを判断します。デフォルトでは、IgnoreCase
は$True
(大文字小文字を区別しない)に設定されています。これを$False
に設定すると、Get-PlanetSize.ps1
のPlanet
パラメータにmarsを指定すると、エラーメッセージが生成されます。
以下に示すように、有効な値リストの末尾に$true
の値を割り当てることで、IgnoreCase
オプションを使用できます。
今回は、リスト内の値と Planet
の値が完全に一致しない場合、バリデーションが失敗します。
タブ補完の使用
ValidateSetを使用すると、タブ補完が利用できます。これにより、パラメータの可能な値をTABキーを使用してサイクルすることができます。これにより、スクリプトや関数の使いやすさが大幅に向上します。特にコンソールからの利用においては、非常に便利です。
以下の例には、いくつかの注意点があります。
- タブ補完は、最後の値を表示した後に最初の値に戻ります。
- 値はアルファベット順に表示されますが、ValidateSet 内でアルファベット順にリスト化されているわけではありません。
- 最初の文字を入力して TAB キーを押すと、タブ補完によって提供される値がその文字で始まる値に制限されます。


また、ValidateSet のタブ補完を PowerShell 統合スクリプト環境 (ISE) でも利用することができます。以下の例では、ISEの Intellisense 機能が、素敵な選択ボックスで可能な値のリストを表示しています。
Intellisense は、入力した文字を含むすべての値を返します。文字で始まる値だけでなく。

Windows 5.1 の ValidateSet バリデーション属性について説明しましたが、PowerShell Core 6.1 で追加された機能を見てみて、スクリプトにより多くのバリデーション機能を追加できるかどうかを見てみましょう。
PowerShell 6.1 での ValidateSet の変更の理解
PowerShell Core 6.1の登場により、ValidateSet検証属性には2つの新機能が追加されました。
- ErrorMessageプロパティ
- ValidateSetを介したクラスの使用、
System.Management.Automation.IValidateSetValuesGenerator
へのアクセス
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ファイルを作成する必要があります。そのために、このデータセットを新しいテキストファイルにコピーして貼り付け、それをplanets.csvとして保存し、Get-PlanetSize.ps1スクリプトと同じフォルダに保存します。
スクリプトにクラスを追加する
ValidateSetで使用されるクラスは、ValidateSetが使用する前に定義されている必要があります。これは、Get-PlanetSize.ps1の構造では機能しません。
使用する前に[Planet]
クラスを定義する必要があるため、スクリプトの先頭に配置する必要があります。適切なスケルトンクラス定義は以下のようになります。
クラスのGetValidValues()
メソッド内では、テキストファイルplanets.csvをインポートするためにImport-CSV
コマンドレットを使用します。ファイルは$planets
というグローバルスコープの変数にインポートされるため、スクリプト内で後でアクセスすることができます。
GetValidValues()
を介して惑星名のリストを返すためにreturn
ステートメントを使用します。これらの変更後、クラスは以下のようになります。
次に、スクリプトから$planets
ハッシュテーブルの宣言を削除します。代わりに、[Planet]
クラスによってポピュレートされるグローバル変数$planets
に惑星データが含まれます。
残りのオリジナルコードを関数にラップし、それをGet-PlanetDiameter
と呼びます。スクリプトの先頭にあったParam()
ブロックを関数内に配置します。静的な惑星のリストを[Planet]
クラスへの参照に置き換えます。以下のようになります。
$output = "惑星 {0} の直径は {1} kmです" -f $_, $planets[$_]
という行を以下の2行に置き換えます。これにより、スクリプトは以前に作成したハッシュテーブルではなく、Import-CSV
で作成したオブジェクトの配列から惑星を検索できるようになります。
これらの変更を行った後、最終的なスクリプトは次のようになります:
これ以降のスクリプトは、PowerShell 6.1以降でのみ動作します
それでは、このスクリプトをどのように使用するのでしょうか?
スクリプトの実行
スクリプトを実行するだけでは、スクリプトの新しいバージョンを直接使用することはできません。すべての有用なコードは関数に包まれています。そのため、PowerShellセッション内から関数にアクセスできるようにするために、ファイルをdot sourceする必要があります。
dot source化された後は、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検証属性とその使用目的
- PowerShell関数またはスクリプトにValidateSetを追加する方法
- ValidateSetとのタブ補完の動作方法
- ValidateSetが大文字小文字を区別するかどうかを制御する
IgnoreCase
プロパティの使用方法 - ValidateSetとPowerShell 6.1での
ErrorMessage
プロパティの使用方法 - PowerShell 6.1で動的なValidateSetを作成するためのクラスの使用方法
さあ、何を待っていますか?今すぐValidateSetを使いましょう!
さらに読む
Source:
https://adamtheautomator.com/powershell-validateset/