Windows PowerShell: より良い関数を作成する

Windows PowerShell 2.0 の高度な関数により、比較的単純なスクリプトでネイティブなコマンドレットを模倣できます。

Don Jones

Windows PowerShell 2.0 では、"高度な関数" と呼ばれる新しい種類の関数が導入されました。多くの人は、これを "スクリプト コマンドレット" と呼んでいます。この高度な関数は、Windows PowerShell の簡略化されたスクリプト言語を使用して、外見、動作、におい、および雰囲気が本物のネイティブな Windows PowerShell コマンドレットとほとんど同じものを作成できるようにすることを目的としています。

もちろん、すべてのユーザーが自分や同僚のために再利用可能なツールを作成するわけではありません。しかし、再利用可能なツールを作成する場合には、高度な関数を使用する必要があります。実際、現在私は、トレーニング クラスで使用するコースウェアの内容を、この高度な関数だけを教えるものに変更しているところです。

高度な関数は本物のコマンドレットと非常によく似た動作をするため、適切に作成された関数は他のユーザーが使用しやすいものとなる場合があります。というのも、高度な関数は、シェルの他の動作方法と "調和する" からです。そこで、より迅速に高度な関数を作成するために使用できるテンプレートを紹介しましょう。

function Get-Something {
  <#
  .SYNOPSIS
  Describe the function here
  .DESCRIPTION
  Describe the function in more detail
  .EXAMPLE
  Give an example of how to use it
  .EXAMPLE
  Give another example of how to use it
  .PARAMETER computername
  The computer name to query. Just one.
  .PARAMETER logname
  The name of a file to write failed computer names to. Defaults to errors.txt.
  #>
  [CmdletBinding()]
  param
  (
    [Parameter(Mandatory=$True,
    ValueFromPipeline=$True,
    ValueFromPipelineByPropertyName=$True,
      HelpMessage='What computer name would you like to target?')]
    [Alias('host')]
    [ValidateLength(3,30)]
    [string[]]$computername,
        
    [string]$logname = 'errors.txt'
  )

  begin {
  write-verbose "Deleting $logname"
    del $logname -ErrorActionSilentlyContinue
  }

  process {

    write-verbose "Beginning process loop"

    foreach ($computer in $computername) {
      Write-Verbose "Processing $computer"
      # use $computer to target a single computer
    

      # create a hashtable with your output info
      $info = @{
        'info1'=$value1;
        'info2'=$value2;
        'info3'=$value3;
        'info4'=$value4
      }
      Write-Output (New-Object –TypenamePSObject –Prop $info)
    }
  }
}

この関数についての重要な注意事項は次のとおりです。その多くは、このテンプレートを使用するときに、微調整する必要があるものについてです。

  • 関数名はコマンドレット名と同じ形式にする必要があります。つまり、Get のような Windows PowerShell でよく使用される動詞で始まり、単数名詞で終わる必要があります。
  • コメントベースのヘルプを記述します。各パラメーターの説明、関数全体の説明、および使用例を含めます。このようなヘルプを記述する方法の詳細を表示するには、「help about_comment_based_help」というコマンドを実行します。
  • 最初のパラメーターである $computername は、かなり複雑です。$computername では、パラメーターで指定された値またはパイプラインから値を 1 つ以上受け取ります。このパラメーターで受け取る文字数は、3 ~ 30 文字です。関数の実行時には、–computername の代わりに -host を使用できます。このパラメーターは必須です。コンピューター名を指定せずに関数を実行すると、シェルによって 1 つ以上のコンピューター名を入力するように要求されます。
  • 2 つ目のパラメーターである $logname は、より単純なパラメーターです。$logname では、文字列値しか受け取らず、既定値が用意されています。
  • BEGIN スクリプト ブロックでは、すべての既存のログ ファイルを削除するので、関数を実行するたびに新しいログ ファイルが生成されます。
  • PROCESS スクリプト ブロック内に、関数を 1 台のコンピューターで動作するようにするために、$computer 変数を使用する場所を示しておきました。$computername 変数を直接操作することはありませんが、この変数には、1 つ以上の値が格納されていることがあるため、ForEach ループでは、値を列挙し、一度に 1 つの値が $computer 変数を渡しています。
  • $info ハッシュテーブルには、目的の出力形式が含まれている必要があります。これは表形式の出力だと考えてください。info1、info2、info3、および info4 という名前の列を作成しました。これらの列の値は、$valuex 変数から取得します。これはただの一例です。このテンプレートでは、実際にはこれらの変数に何も格納していません。そのため、$value1 や $value2 などは任意の情報に置き換えることができます。

このテンプレートは、情報を取得する必要がある高度な関数で役立ちますが、システムの状態は実際のところまったく変更していません。システムの状態を変更する高度な関数で使用するには、いくつかの追加のアイテムを実装する必要があります。これを念頭に置き、次に 2 つ目のテンプレートを紹介します。

function Do-Something {
  <#
  .SYNOPSIS
  Describe the function here
  .DESCRIPTION
  Describe the function in more detail
  .EXAMPLE
  Give an example of how to use it
  .EXAMPLE
  Give another example of how to use it
  .PARAMETER computername
  The computer name to query. Just one.
  .PARAMETER logname
  The name of a file to write failed computer names to. Defaults to errors.txt.
  #>
  [CmdletBinding(SupportsShouldProcess=$True,ConfirmImpact='Low')]
  param
  (
    [Parameter(Mandatory=$True,
    ValueFromPipeline=$True,
    ValueFromPipelineByPropertyName=$True,
      HelpMessage='What computer name would you like to target?')]
    [Alias('host')]
    [ValidateLength(3,30)]
    [string[]]$computername,
        
    [string]$logname = 'errors.txt'
  )

  begin {
  write-verbose "Deleting $logname"
    del $logname -ErrorActionSilentlyContinue
  }

  process {

    write-verbose "Beginning process loop"

    foreach ($computer in $computername) {
      Write-Verbose "Processing $computer"
      if ($pscmdlet.ShouldProcess($computer)) {
        # use $computer here
      }
    }
  }
}

このテンプレートでは、ConfirmImpact の設定を変更して、高度な関数の潜在的な危険を示す相対的な指標を提供する必要があります。たとえば、ファイルの ReadOnly 属性を変更するなどの小さな変更を行う場合、ConfirmImpact は Low でしょう。一方、コンピューターを再起動する場合は、High になるでしょう。Windows PowerShell では、組み込みの $ConfirmPreference 変数と共に、この設定を使用し、関数を実行するときに、本当に実行するかどうかを確認するプロンプトを自動的に表示するかどうかを決定します。

$computer 変数を使用して、特定の 1 台のコンピューターを対象にする操作を実際に実行する必要がある場所は明記されています。この処理は、組み込みの $pscmdlet オブジェクトを使用する If 構文に含まれています。関数が、(関数でサポートしている) –whatif または –confirm パラメーターを指定して実行された場合、$pscmdlet オブジェクトでは、予想される処理結果 (what if) の出力または本当に実行するかどうかを確認するプロンプトの生成に対応します。

この 2 つのテンプレートはどちらも、-verbose パラメーターをサポートしており、関数の実行時にステータス メッセージを生成するために Write-Verbose コマンドレットを使用しています。もちろん、すべての関数がコンピューターを対象にする必要があるわけではありません。パラメーターで、ファイル名やユーザー名などの情報を受け取る場合もあるでしょう。その場合は、単にパラメーター宣言を適宜変更してください。

検証、必須、パイプライン入力などのパラメーター属性の詳細については、シェルで「help about_functions_advanced_parameter」というコマンドを実行してください。ぜひ、高度な関数を試してみてください。

Don Jones

Don Jones は、Windows PowerShell の著名な執筆者、トレーナー、および講演者です。最新の著書である『Learn Windows PowerShell in a Month of Lunches』(Manning Publications Co.、2011 年) の詳細および無償の付属コンテンツについては、MoreLunches.com (英語) を参照してください。また、オンサイトのトレーニング クラスも開講しています (詳細については、ConcentratedTech.com/training (英語) を参照してください)。

関連コンテンツ