Windows PowerShellのFunction入門 (Begin、Process、Endブロック編)

この記事はWindows PowerShellBeginProcessEndブロック、そしてFunction/Filter/ScriptBlockスクリプトファイルの違いに関する基本的な話です


PowerShellの処理はBeginProcessEndの3つのブロックに分かれています

# Sample1.ps1の内容
Begin{
    Write-Host 'Begin';
}
Process{
    Write-Host 'Process';
}
End{
    Write-Host 'End';
}
PS> ./Sample.ps1;
Begin
Process
End

パイプラインから値を渡されたとき、Beginは最初の1回目のProcessが動く前に、Processは値を渡される毎に、Endは最後のProcessが動いた後に実行されます

なお、パイプラインで値を渡す意図がある場合でもForEach-Objectの中で呼ぶとForEach-Objectの中で個別に実行されてしまうので、注意してください

Function SampleFunction1{
    Begin{
        Write-Host 'Begin';
    }
    Process{
        Write-Host 'Process';
    }
    End{
        Write-Host 'End';
    }
}

PS> 1..3 | SampleFunction1
Begin
Process
Process
Process
End
PS> 1..3 | Foreach-Object{SampleFunction1}
Begin
Process
End
Begin
Process
End
Begin
Process
End

BeginProcessEndブロックの記述はそれぞれ省略することができます

何も書かれていない場合、FilterスクリプトファイルはProcessブロックとして、FunctionScriptBlockEndブロックとして処理が動きます

# Sample2.ps1の内容
    Write-Host 'Sample2.sp1';
PS> 1..3 | ./Sample2.ps1
Sample2.sp1
Sample2.sp1
Sample2.sp1
Function SampleFunction2{
    Write-Host 'SampleFunction2';
}

[ScriptBlock] $ScriptBlock1 = {Write-Host 'ScriptBlock1'};

Filter SampleFilter{
    Write-Host 'SampleFilter';
}


PS> 1..3 | SampleFunction2
SampleFunction2
PS> 1..3 | &($ScriptBlock1)
ScriptBlock1
PS> 1..3 | SampleFilter
SampleFilter
SampleFilter
SampleFilter

また、BeginProcessEndブロックを明記することにより、書かなかったブロックが存在しないFunction/Filter/ScriptBlock/スクリプトファイルを作ることもできます

# Endブロックが存在しないFunction
Function SampleFunction3{
    Begin{
        Write-Host 'Begin';
    }
    Process{
        Write-Host 'Process';
    }
}

BeginProcessEndブロックの何れかを記述した場合、デフォルトで省略されていたブロック (FunctionならEndブロック) も明記する必要が生じます

Function SampleFunction4{
    Process{
        Write-Host 'Process';
    }
    # Endブロック内の処理にはならず、Function作成時にエラーになる
    Write-Host 'End';
}

なお、BeginProcessEndブロックをすべて明記した場合、Function/Filterに違いはなくなるようです……が私はよくわかっていません

FunctionFilterGet-Itemで情報を取得すれば、CommandTypeFilterFunctionかで違いが出ますが、処理に違いはないようです

解説記事なのに最後の所がぼやけていて申し訳ありませんが、私は基本的にはFunctionを用い、パイプラインによる処理の連鎖の中で特定のForEach-Objectが大きくなったり繰り返し同じ記述をすることになった場合Filterで処理を外に出すという使い分けをしています