すべてのPowerShellコマンドには1つ以上のパラメータ(引数とも呼ばれることがあります)があります。PowerShell関数でPowerShellパラメータを使用していない場合、適切なPowerShellコードを書いていません!
この記事では、PowerShellパラメータまたは引数の作成と使用のほぼすべての側面について学びます!
これは私の書籍「PowerShell for SysAdmins」の一部です。PowerShellを学びたい、またはトレードのいくつかのトリックを学びたい場合は、チェックしてみてください!
なぜパラメータが必要なのですか?
関数の作成を開始すると、パラメータを含めるかどうか、およびそれらのパラメータの動作方法を選択できます。
たとえば、Microsoft Officeをインストールする関数があるとしましょう。おそらく、関数内部でOfficeインストーラをサイレントモードで呼び出しているかもしれません。関数が行うことは、私たちの目的には関係ありません。関数の基本的な構造は、次のようになります(関数名とスクリプトブロック)。
この例では、パラメータなしでInstall-Office
を実行しました。それはやりたいことを行いました。
Install-Office
関数にパラメータがあるかどうかは問題ではありませんでした。明らかに、必須のパラメータがなかったようです。そうでなければ、PowerShellはパラメータを使用せずに実行させてくれなかったはずです。
いつPowerShellパラメータを使用するか
Officeにはさまざまなバージョンがあります。おそらくOffice 2013と2016をインストールする必要があります。現在、これを指定する方法はありません。振る舞いを変更するたびに関数のコードを変更する必要があります。
たとえば、異なるバージョンをインストールするために2つの別々の関数を作成することができます。
これを行うことはできますが、スケーラブルではありません。Officeの各バージョンごとに個別の関数を作成する必要があります。不必要にコードを重複することになります。
代わりに、関数の振る舞いを変更するためにランタイムで異なる値を渡す方法が必要です。どのようにすれば良いですか?
そうです!パラメータ、または一部の人々が引数と呼ぶものです。
コードを変更せずに異なるOfficeのバージョンをインストールしたいのであれば、この関数に少なくとも1つのパラメータを追加する必要があります。
すばやくPowerShellのパラメータを考える前に、まず自分に質問することが重要です。「この関数で必要な最小の変更または変更は何ですか?」
この関数のコードを変更せずにこの関数を再実行する必要があることを覚えておいてください。この例では、おそらくVersion
パラメータを追加する必要があると思われます。ただし、数十行のコードを持つ関数の場合、答えは明らかではありません。できるだけ正確にその質問に答える限り、常に役立ちます。
したがって、Version
パラメータが必要であることを知っています。では、次はどうすればよいでしょうか?追加することができますが、優れたプログラミング言語のように、それを実現するための複数の方法があります。
このチュートリアルでは、私の10年近いPowerShellの経験に基づいて、パラメータを作成するための「最良の」方法を紹介します。ただし、これが唯一の方法ではありませんことを知っておいてください。
位置パラメータというものが存在します。これらのパラメータを使用すると、パラメータ名を指定せずに値をパラメータに渡すことができます。位置パラメータは機能しますが、「ベストプラクティス」とは考えられていません。なぜなら、特に多くのパラメータが関数に定義されている場合、読みにくくなるからです。
シンプルなPowerShellパラメータの作成
関数にパラメータを作成するには、2つの主要なコンポーネントが必要です。1つはparamブロックであり、もう1つはパラメータ自体です。paramブロックは、param
キーワードに続くカッコで定義されます。
この時点では、関数の実際の機能はまったく変わりません。ただ、いくつかのプランビングをまとめて、最初のパラメータに備えています。
paramブロックが準備できたら、次にパラメータを作成します。私が提案するパラメータの作成方法は、Parameter
ブロックの後に、パラメータの型を記述し、その下にパラメータ変数名を続ける方法です。
これで、PowerShellで関数パラメータを作成しましたが、ここで実際に何が起こったのでしょうか?
Parameter
ブロックは、パラメータのオプションですが推奨される部分です。paramブロックと同様に、これはパラメータに追加の機能を追加するための「関数プランビング」です。2行目では、パラメータの型を定義します。
この場合、Versionパラメータを文字列にキャストすることを選択しました。明示的な型の定義は、このパラメータに渡される値が既に文字列でない場合、常に文字列に「変換」されることを意味します。
型は必須ではありませんが、強く推奨されます。パラメータの型を明示的に定義することで、将来の多くの予期しない状況を大幅に減らすことができます。信じてください。
パラメータが定義されたので、Version
パラメータを使用してInstall-Office
コマンドを実行できます。バージョン文字列(2013など)をVersion
パラメータに渡します。パラメータに渡される値は、パラメータの引数または値と呼ばれることがあります。
ここで何が起こっているのでしょうか?バージョン2013をインストールしたいと伝えたのに、まだ2016がインストールされていると言われています。パラメータを追加すると、関数のコードを変数に変更することを忘れないでください。パラメータが関数に渡されると、その変数は渡された値に展開されます。
2016の静的テキストを変更し、Version
パラメータの変数に置き換え、シングルクォーテーションをダブルクォーテーションに変換して、変数が展開されるようにします。
これで、Version
パラメータに渡された値は、$Version
変数として関数に渡されることがわかります。
必須パラメータ属性
[Parameter()]
行はただの「関数の配管」であり、関数をさらなる作業に準備する必要があると述べたことを思い出してください。パラメータにパラメータ属性を追加することが、先ほど話していた追加作業です。
A parameter doesn’t have to be a placeholder for a variable. PowerShell has a concept called parameter attributes and parameter validation. Parameter attributes change the behavior of the parameter in a lot of different ways.
たとえば、最も一般的なパラメータ属性の1つはMandatory
キーワードです。デフォルトでは、Version
パラメータを使用せずにInstall-Office
関数を呼び出すことができ、正常に実行されます。Versionパラメータはオプションです。ただし、関数内の$Version変数を展開しないため、値がない場合でも実行されます。
パラメータを作成する際には、ユーザーに常にそのパラメータを使用してもらいたい場合があります。関数のコードの中でパラメータの値に依存し、パラメータが渡されない場合、関数は失敗します。このような場合、ユーザーにこのパラメータ値を関数に渡すように強制したいと思います。そのパラメータを必須にしたいのです。
パラメータを強制することは、ここで構築した基本的なフレームワークがあれば簡単です。パラメータのカッコ内にMandatory
キーワードを含める必要があります。これを設定すると、パラメータなしで関数を実行すると、値が入力されるまで実行が停止します。
関数はVersion
パラメータの値が指定されるまで待機します。値を指定してEnterを押すと、PowerShellは関数を実行し、次に進みます。パラメータに値を指定すると、PowerShellはパラメータを毎回プロンプトで要求しません。
PowerShellパラメータの検証属性
パラメータを必須にすることは、追加できる最も一般的なパラメータ属性の1つですが、パラメータの検証属性も使用できます。プログラミングでは、ユーザーの入力をできるだけ厳密に制限することが常に重要です。関数やスクリプトにユーザー(あるいはあなた自身)が渡すことができる情報を制限することで、あらゆる状況に対応するための不要なコードを関数内に含める必要がなくなります。
例による学習
たとえば、Install-Office
関数では、値2013
を渡すことで、それが動作することを示しました。私がコードを書いたからです!私は(コードでは絶対にこれをしないでください!)あなたが何かを知っている人はバージョンを2013または2016と指定するということが明らかであると仮定しています。しかし、あなたにとって明らかなことが他の人にとってはそうではないかもしれません。
バージョンに関して技術的なことを言うと、Microsoftが過去に使用していたバージョン管理スキーマを引き続き使用している場合、2013バージョンを15.0
、2016バージョンを16.0
と正確に指定する方が適切かもしれません。しかし、もしも彼らが2013または2016のバージョンを指定すると仮定して、そのバージョンのフォルダを探すなどのコードが関数内にある場合はどうでしょうか?
以下は、$Version
文字列をファイルパスで使用している例です。もしも誰かがOffice2013
またはOffice2016
のフォルダ名を完全に指定しない値を渡した場合、エラーが発生するか、予期しないフォルダが削除されたり、予期しない変更が行われる可能性があります。
ユーザーが入力することを予想される内容に制限を加えるために、PowerShellのパラメーター検証を追加することができます。
ValidateSetパラメーター検証属性を使用する
使用できるさまざまな種類のパラメーター検証があります。完全なリストについては、Get-Help about_Functions_Advanced_Parameters
を実行してください。この例では、ValidateSet
属性がおそらく最適です。
ValidateSet
検証属性では、パラメーターの値として許可される値のリストを指定できます。ここでは、文字列2013または2016のみを考慮しているため、ユーザーがこれらの値のみを指定できるようにしたいと思います。それ以外の場合、関数はすぐに失敗し、なぜ失敗したのかを通知します。
パラメーターの検証属性は、元のParameter
キーワードのすぐ下に追加できます。この例では、パラメーター属性の括弧の中に、2013と2016のアイテムの配列があります。パラメーターの検証属性は、Version
の有効な値が2013または2016であることをPowerShellに伝えます。セット内に存在しない値を渡そうとすると、特定のオプションのみが利用可能であることを示すエラーメッセージが表示されます。
ValidateSet
属性は一般的なバリデーション属性です。パラメータの値を制限する方法の詳細については、Get-Help about_Functions_Advanced_Parameters
を実行して、Functions_Advanced_Parameters
のヘルプトピックを参照してください。
パラメータセット
たとえば、特定のPowerShellパラメータを他のパラメータと一緒に使用したい場合があります。おそらく、Install-Office
関数にPath
パラメータを追加しました。このパスは、インストーラのバージョンをインストールします。この場合、ユーザーがVersion
パラメータを使用しないようにしたいです。
パラメータセットが必要です。
パラメータはセットにグループ化され、同じセット内の他のパラメータとのみ使用できるようになります。以下の関数を使用すると、Version
パラメータとPath
パラメータの両方を使用してインストーラのパスを作成できます。
ただし、これには問題があります。ユーザーは両方のパラメータを使用する可能性があります。さらに、両方のパラメータが必須であるため、望ましくない場合でも両方を使用する必要があります。これを修正するには、以下のように各パラメータをパラメータセットに配置します。
各パラメータにパラメータセット名を定義することで、パラメータのグループを制御できます。
デフォルトのパラメータセット
ユーザーがパラメータなしでInstall-Office
を実行しようとした場合はどうなりますか?これは考慮されておらず、フレンドリーなエラーメッセージが表示されます。

これを修正するには、CmdletBinding()
の範囲内でデフォルトのパラメーターセットを定義する必要があります。これにより、パラメーターが明示的に使用されなかった場合に、関数が使用するパラメーターセットを指定します。つまり、[CmdletBinding()]
を[CmdletBinding(DefaultParameterSetName = 'ByVersion')]
に変更します。
これで、Install-Office
を実行すると、使用されるパラメーターセットがVersion
パラメーターを要求します。
パイプライン入力
これまでの例では、通常の-ParameterName Valueの構文を使用してのみ渡すことができるPowerShellパラメーターを持つ関数を作成してきました。しかし、既に学んだように、PowerShellには直感的なパイプラインがあり、通常の構文を使用せずにコマンドの出力を別のコマンドにシームレスに渡すことができます。
パイプラインを使用すると、パイプ記号|
を使用してコマンドを「チェーン」することができます。これにより、ユーザーはGet-Service
の出力をStart-Service
に送信することで、Name
パラメーターをStart-Service
に渡すショートカットを作成できます。
「古い」方法:ループを使用する
作業中のカスタム関数では、Officeをインストールし、Version
パラメーターを持っています。次に、1行にコンピューター名のリストがあり、それらのコンピューターにインストールする必要があるOfficeのバージョンが2行目にあります。CSVファイルは次のようなものです:
各コンピューターの隣にあるOfficeのバージョンをそのコンピューターにインストールしたいとします。
まず、各イテレーションごとに異なるコンピュータ名を渡すために、関数にComputerName
パラメータを追加する必要があります。以下に、架空の関数内に存在する可能性のあるコードを示し、変数が関数内でどのように展開されるかを確認するためにWrite-Host
インスタンスを追加しました。
関数にComputerName
パラメータが追加されたら、CSVファイルを読み取り、コンピュータ名とバージョンの値をInstall-Office
関数に渡すことができます。
パラメータのためのパイプライン入力の構築
この方法では、CSVの行を読み取り、各行のプロパティを関数に渡すためのループを完全に省略します。このセクションでは、foreach
ループを完全に省略し、代わりにパイプラインを使用することを望んでいます。
現状では、関数はパイプラインをサポートしていません。パイプラインを使用して各コンピュータ名とバージョンを関数に渡すことができると直感的に思われるかもしれません。以下では、CSVを読み取り、直接Install-Office
に渡していますが、これは機能しません。
あなたが仮定しようとしても、それだけで動作するわけではありません。 Import-Csv
がオブジェクトのプロパティとして送信していることを知っているのに、Version
パラメータの入力を求められています。なぜ動作しないのか?それはまだパイプラインのサポートが追加されていないからです。
PowerShell関数には2つの種類のパイプライン入力があります。 ByValue(完全なオブジェクト)と ByPropertyName(単一のオブジェクトのプロパティ)です。 Import-Csv
の出力を Install-Office
の入力にどのように結合するのが最適だと思いますか?
全くリファクタリングせずに、Import-Csv
が既にCSVの列として Version
と ComputerName
のプロパティを返しているため、ByPropertyName
メソッドを使用できます。
カスタム関数にパイプラインサポートを追加するのは、思っているよりも簡単です。これは、2つのキーワードで表されるパラメータ属性であり、ValueFromPipeline
または ValueFromPipelineByPropertyName
のいずれかです。
この例では、Import-Csv
から返された ComputerName
と Version
のプロパティを Install-Office
の Version
と ComputerName
のパラメータにバインドしたいので、ValueFromPipelineByPropertyName
を使用します。
これらのパラメータの両方にこのキーワードを追加し、パイプラインを使用して関数を再実行します。
それは奇妙です。CSV の最後の行でしか実行されませんでした。なぜでしょうか?これは、パイプラインサポートを持たない関数をビルドする際に必要ではない概念をスキップしたためです。
プロセスブロックを忘れないでください!
パイプラインサポートを必要とする関数を作成する場合、少なくとも “埋め込まれた” ブロックとして process
を含める必要があります。このプロセスブロックは、パイプライン入力を受け取った場合に、すべての反復のために関数を実行するように PowerShell に指示します。デフォルトでは、最後の反復のみが実行されます。
理論的には、begin
や end
のような他のブロックを追加することもできますが、スクリプターはそれらをあまり頻繁に使用しません。
PowerShell にこの関数を入力オブジェクトごとに実行するように指示するために、その内部にコードを含む process
ブロックを追加します。
今では、Import-Csv
から返された各オブジェクトのVersion
とComputerName
のプロパティが、Install-Office
に渡され、Version
とComputerName
のパラメーターにバインドされることがわかります。
リソース
関数のパラメーターの動作についてもっと詳しく知りたい場合は、私のPowerShell関数に関するブログ記事をチェックしてください。
I also encourage you to check my Pluralsight course entitled Building Advanced PowerShell Functions and Modules for an in-depth breakdown of everything there is to know about PowerShell functions, function parameters, and PowerShell modules.