かわいそうに言うつもりはありませんが、これが問題です。$env:PSModulePath の下にインストールされた PowerShell モジュール Test.psm1 で定義されている次の 2 つの関数について考えてみましょう。
function Start-TestAsync
{
[CmdletBinding()]
param([ScriptBlock]$Block, [string]$Name = '')
Start-Job { Start-Test -Name $using:Name -Block $using:Block }
}
function Start-Test
{
[CmdletBinding()]
param([ScriptBlock]$Block, [string]$Name = '')
# do some work here, including this:
Invoke-Command -ScriptBlock $Block
}
モジュールをインポートした後、同期関数を実行できます...
PS> Start-Test -Name "My Test" -Block { ps | select -first 9 }
...そして、Get-Process からの適切な出力が表示されます。
ただし、非同期バージョンを実行しようとすると...
PS> $testJob=Start-TestAsync -Name "My Test" -Block { ps | select -first 9 }
...そして、その出力を確認します...
PS> Receive-Job $testJob
...パラメーターを Start-Test 関数に持ち込むだけで失敗し、文字列を ScriptBlock に変換できないと報告します。したがって、-Block $using:Block
ScriptBlock ではなく文字列を渡しています。
いくつかの実験の後、回避策を見つけました。$Block パラメーターの型が [ScriptBlock] ではなく [string] になるように Start-Test を変更し、その文字列をブロックに戻して Invoke-Command にフィードすると...
function Start-Test
{
[CmdletBinding()]
param([string]$Block, [string]$Name = '')
$myBlock = [ScriptBlock]::Create($Block)
Invoke-Command -ScriptBlock $myBlock
}
上記と同じコマンドを実行すると、正しい結果が得られます。
PS> $testJob=Start-TestAsync -Name "My Test" -Block { ps | select -first 9 }
PS> Receive-Job $testJob
using
私の最初の例 (ScriptBlock を文字列に変換する) で、スコープは正しく機能していますか? それに関する限られたドキュメント ( about_Remote_Variables、about_Scopes ) は、ほとんどガイダンスを提供しません。最終的に、$Block パラメーターが [ScriptBlock] として入力されている場合に Start-Test を機能させる方法はありますか?