2012-10-02 15 views
7

一部のデータを列挙するPowerShell関数を作成し、すべての発生時にスクリプトブロックを起動します。今私が持っていることでパラメータ化されたスクリプトブロックを使用するPowerShell関数

は(これは、実際のコードではありませんが、それは私の問題を示している):

function Invoke-TenTimes 
{ 
    [CmdletBinding()] 
    param 
    (
     [Parameter(Mandatory=$true, Position=0)] 
     [ScriptBlock]$Action 
    ) 
    process 
    { 
     $digits = 0..10 
     $digits | % { 
      $Action.Invoke($_); 
     } 
    } 
} 

私は自分のモジュールでこの機能を置きます。しかし、私は電話しても何の結果も得られません。

Invoke-TenTimes { $_ } 

出力は空白です(何も表示されません)。

私は

Invoke-TenTimes { $_ -eq $null } 

を呼び出す場合、私は10 trueを取得します。実際、$_がnullであることがわかります。

$_に入力する適切な方法は何ですか?狂気私を運転している何

、私は、同じPS1ファイルにこの関数とコールを置けば、それが動作することである(しかし、私はオンデマンドでスクリプトブロックを渡したい):

function Invoke-TenTimes 
{ 
    [CmdletBinding()] 
    param 
    (
     [Parameter(Mandatory=$true, Position=0)] 
     [ScriptBlock]$Action 
    ) 
    process 
    { 
     $digits = 0..10 
     $digits | % { 
      $Action.Invoke($_); 
     } 
    } 
} 


Invoke-TenTimes { $_ } 

答えて

2

これはスコープの問題は、それが実行されている場所とは異なる範囲に属するスクリプトブロックに渡されています。スクリプトブロックに渡された変数がそのコンテキストから変数を参照する必要がない場合は、スクリプトブロックをクローンして、実行中のスコープに強制的に入れることができます。

$action = [scriptblock]::Create($action) 

面白いことは、ACCIDENTで最初に働いただけです。スクリプトブロックの所属先の親スコープから$ _を取得していましたが、これはあなたの内部にあったものです。

しかし、あなたの元のバージョンを取り、その後、この

"gotcha" | % { 
Invoke-TenTimes { $_ } 
} 

を実行すると、あなたは$ _ので、することはあなたの呼び出し元のスコープ内のNULLではありませんが、何かで、あなたが知っておかなけれ10倍を得ることができます表示されます。

+0

ありがとう!これは私の問題を解決し、$ _でスクリプトブロックを使用できるようになりました。 –

3

問題がありますそれはモジュール固有のものです。これはバグかもしれません。この質問を見てみてください:

Strange behavior with Powershell scriptblock variable scope and modules, any suggestions?あなたの特定のケースについては、このようなあなたの関数を呼び出す:

Invoke-TenTimes { $args[0] } 

を期待通りに動作するはずです。このように。

+0

これは私の問題を解決しました。しかし、私は誰かが提案する実際の解決策を持っているかどうかを確認するために数日待つでしょう。 –

5

は、ここに私達は行く:

$scriptblock = {param($number) Write-Host "Current Number is $number"} 

function Invoke-TenTimes 
{ 
    [CmdletBinding()] 
    param 
    (
     [Parameter(Mandatory=$true, Position=0)] 
     [ScriptBlock]$Action 
    ) 
    $digits = 1..10 
    $digits | ForEach-Object{Invoke-Command -ScriptBlock $Action -Args $_} 
} 

用途:

Invoke-TenTimes $scriptblock 
0

誰よりも簡単です。

$ Aと$ Bはグローバルレベルで定義され、$ Bのみがモジュールレベルで定義されています。スクリプトブロックは3番目のスコープです。その中で$ Aを参照し、グローバル値を取得します。同様に、$ Bを参照すると、グローバル・インスタンスを隠すのでモジュール・レベルの値を取得します。

問題:いずれかに書き込もうとすると、ローカルインスタンスが作成されます。

回答:

([ref]$A).value = 'Something malicious' 

注 ".VALUE" は実際の変数に到達するために必要とされるように、 "([参考文献] $ {名前})が" 基準オブジェクトであること。だから、

([ref]$B).value.Length 

あなたがスコープオーバーは直接制御することはできませんいずれの場合も

$B.Length 

と同じです。あなたはあなたが読むだろうインスタンスを取得します。したがって、最初の例はGlobal $ Aを変更し、2番目の例は$ Bのモジュールレベルのインスタンスを参照します。