Windows PowerShell: スクリプトでコマンドレットを記述する

Don Jones

Windows PowerShell 2.0 のすばらしい新機能の 1 つは、関数を記述する機能が大幅に強化されたことです。スクリプト内で記述した関数には、C# や Visual Basic で記述されて Visual Studio でコンパイルされるコマンドレットとほぼ同じ機能を持たせることができます。このような "高度な関数" (Windows PowerShell 2.0 の開発サイクルの初期段階では "スクリプト コマンドレット" と呼ばれていました) を使用すると、通常の関数とシームレスに組み合わせて使用できる、より柔軟な関数を記述できます。

重要なのはバインド

単なる関数と完全なコマンドレットの違いは、コマンドレットでは強力なパラメーターのバインドがサポートされることです。シェルに渡すパラメーターを指定するだけで、位置指定パラメーター、名前付きパラメーター、または必須パラメーターを使用することも、パラメーターの基本的な検証チェックを実行することもできます。その例を次に示します。

function Get-Inventory {
    [CmdletBinding()]
    param (
        [parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [string[]]$computername,
        
        [parameter(Mandatory=$false)]
        [alias("PF")]
        [switch]$pingfirst,
        
        [parameter(Mandatory=$true,Position=0)]
        [AllowEmptyString()]
        [string]$class
        
    )
    PROCESS {
    }
}

このステートメントでは、次の 3 つのパラメーターを宣言しています。

  • computername パラメーターは、単一の文字列か文字列の配列です。これは必須パラメーターで、パイプラインによる文字列の入力を受け取ります。つまり、一連の文字列をパイプライン処理すると、これらの文字列が自動的に $computername 変数に格納されます。
  • pingfirst パラメーターは必須パラメーターではありませんが、使用時には -PF エイリアスを使用することをお勧めします。エイリアスを使用すると、入力の手間が少し省けます。これはスイッチ パラメーターなので、値を受け取りません。このパラメーターの状態は、オン/オフのいずれかです。
  • class パラメーターも必須パラメーターですが、-class というパラメーター名を入力する必要すらありません。必要なのは、関数の実行時に、最初の位置の値に適切な値を指定するだけです。これは必須パラメーターですが、空の文字列も受け取ります。

オンライン ヘルプには、他にも多くの属性や豊富な例が収録されています。すべてのパラメーター表示するには、help about_Functions_Advanced_Parameters コマンドを実行してください。

共通パラメーターにアクセスする

シェルでは、すべてのコマンドレットで共有される共通パラメーターがいくつか定義されています。その 1 つに -verbose パラメーターがあります。このパラメーターでは、コマンドレットに対して、処理内容について通常より詳しい情報を出力するよう指示します。しかし、次のように関数を定義するとエラーになります。

function Test-Something {
    [CmdletBinding()]
    param (
        [switch]$verbose
    )
    PROCESS {
    }
}

これは、-verbose などの共通パラメーターを再定義できないことが原因です。では、関数の実行時に -verbose パラメーターを指定したかどうかを判断するにはどうするのでしょうか。実は、何もする必要がありません。詳細情報を出力する必要があるかどうかについては、Windows PowerShell で自動的に追跡されています。Write-Verbose コマンドレットを呼び出すだけで、Windows PowerShell では -verbose パラメーターを使用しない場合に、このような呼び出しが無視されます。

function Test-Something {
    PROCESS {
        Write-Verbose "Starting cmdlet"
    }
}

test-something –verbose

影響を確認する。

共通パラメーターには、他にも -whatif と -confirm という 2 つのパラメーターがあります。コンピューターになんらかの変更を加えるすべてのコマンドレットでは、これらのパラメーターが認識されることになっています。これらのパラメーターを使用すると、コマンドレットの通常の処理結果を表示したり (-whatif)、各操作を 1 つずつ確認したり (-confirm) することができます。この 2 つのパラメーターはまとめて ShouldProcess と呼ばれ、これらのパラメーターをサポートする関数は次のように定義できます。

function Delete-Things {
    [CmdletBinding(
        SupportsShouldProcess=$true,
        ConfirmImpact="Medium"
    )]
    PROCESS {
    }
}

このように定義すると、関数で -whatif パラメーターと -confirm パラメーターの両方を有効にできます。また、ここでは、この関数が OS に与える影響レベルを Medium に指定しています。Medium レベルについての厳密なガイドラインはありませんが、コンピューターが壊滅的なダメージを受けるよりは小さいリスクと考えてよいでしょう。特に留意する必要があるのは、シェルの $ConfirmPreference 変数に High という値が設定されていることです。コマンドレットの影響が $ConfirmPreference 変数の値より低い場合、-whatif パラメーターか -confirm パラメーターを指定しない限り、コマンドレットは確認されることなく実行されます。

コマンドレットの影響レベルが $ConfirmPreference 変数の値以上の場合、コマンドレットを実行するたびに、-confirm パラメーターを指定するのを忘れていても指定したときと同様にコマンドレットが実行されます。したがって、関数で本当に危険な処理を実行する場合は、「ConfirmImpact="High"」のように指定して、そのコマンドレットの実行時には常に確認が要求されるようにしてください。他に指定できるレベルは、None と Low です。

シェルに組み込まれているヘルプには、確認を要求する方法がどこにも提示されていません。しかも、これは自動的に実行される処理ではありません。組み込みヘルプでは MSDN のオンライン ヘルプを参照していますが、これは Microsoft .NET Framework 開発者を対象にしており、シェルのスクリプト言語についてはまったく触れられていません。ですから、以下にその方法を示しましょう。

function Delete-Things {
    [CmdletBinding(
        SupportsShouldProcess=$true,
        ConfirmImpact="High"
    )]
    Param ($param1)
    PROCESS {
        if ($pscmdlet.ShouldProcess($param1)) {
            Write "Deleting..."
        }
    }
}

Delete-Things "organizationalunit"

$pscmdlet 変数は、PROCESS スクリプト ブロック内で使用することでコマンドレット レベルの機能 (ShouldProcess メソッドなど) にアクセスできる組み込み変数です。変更しようとしている対象の説明を関数に渡すと、確認メッセージやスクリプトを実行した場合の処理を表すメッセージが、自動的に表示されます。

ShouldProcess メソッドが $True を返す場合は、処理を続行できます。$False を返す場合は、どのような処理を実行しようとしていたとしても続行できません。$pscmdlet 変数について把握していると、上記の MSDN の開発者向けドキュメントがわかりやすくなります。開発者向けのドキュメントでは、ShouldProcess メソッドやその関連メソッド (ShouldContinue メソッドなど) のさまざまな使用法を正確に示しています。

ヘルプを含める

2010 年 3 月号のコラムで説明したように、関数 (高度な関数であっても) の特殊な形式のコメントには、専用のヘルプを組み込むことができます。通常、私は、関数の冒頭に、コメント ベースのヘルプを記述し、その後 CmdletBinding ステートメント、パラメーター、BEGIN{} スクリプト ブロック、PROCESS{} スクリプト ブロック、および END{} スクリプト ブロックの順に記述します。関数には、必ずヘルプを含めることをお勧めします。ヘルプは、だれの役に立つかわかりません。

パイプライン関数 (別名、フィルター処理関数) を記述したことがある場合、スクリプト コマンドレットを記述するために必要な他の知識は、既に持っているということになります。PROCESS{} スクリプト ブロックは、コードが機能する場所で、コマンドレットにパイプライン処理されたオブジェクトごとに 1 回実行されます。高度な関数に関する他の点も、もう少し単純な通常の関数と同様です。

Windows PowerShell 2.0 提供開始

Windows PowerShell 2.0 は Management Framework コンポーネントと共に Windows Server 2008 R2 および Windows 7 に同梱されていましたが、Windows XP、Windows Server 2003、Windows Vista、および Windows Server 2008 でも利用できるようになりました。support.microsoft.com/kb/968929 (英語) にアクセスして、ご使用の OS のダウンロード リンクからダウンロードできます。Windows PowerShell 2.0 は、お手持ちの Windows PowerShell 1.0 のスクリプトと互換性があります。今後のすべてのコラムは、皆さんが Windows PowerShell 2.0 を使用している前提で執筆します。

幅広いユーザー

Windows PowerShell チームは、Windows PowerShell をさまざまなスキル レベルの幅広いユーザーの役に立つものにしたことを誇りに思っています。ですが、高度な関数は、その名のとおり、高度なスキルを持つユーザーの役にしか立たない機能の一例と言って間違いないでしょう。

シェルを使い始めたばかりで、Help コマンドを実行するよう自分に言い聞かせる必要がある方は、高度な関数を使用するのは、かなり先のことになるかもしれません。高度な関数を記述しなくても、シェルの使用に支障はありません。スキルのレベルが上がり、再利用可能なコンポーネントを記述できるようになれば、高度な関数がそのような作業に大きく役立つことを実感できるでしょう。

こちらのブログ記事 (英語) には、このような成長に役立つ優れた例が掲載されています。最初は、管理者ならだれでも記述しそうな、有益な作業を実行する単純なコマンドを記述します。次に、このコマンドを、関数、フィルター処理関数、最終的には高度な関数へと段階的に拡張することで、ニーズとスキルの成長に応じてシェルを拡張する方法を示しています。

Don Jones は、Concentrated Technology の創設者で、ConcentratedTech.com (英語) で Windows PowerShell や他のテクノロジに関する質問に答えています。また、Nexus.Realtimepublishers.com (英語) の創設者でもあり、このサイトでは、彼の多くの著書が無料でオンライン ブックとして提供されています。

関連コンテンツ

·      Windows PowerShell: Windows Server 2008 R2 以外の OS で Windows PowerSell 2.0 を使用して Active Directory をスクリプトで管理する

·      Windows PowerShell: フィルター処理を左に、書式設定を右に (英語)

·      Windows PowerShell: 席を離れずに済む (英語)