PowerShell ISE ScriptBlockクロージャで新しいタブの作成を自動化する方法

私はPowerShell ISEでタブの束の作成を自動化しようとしています

私は、次のような関数から始めました。

function Start-NewTab($name, [ScriptBlock]$scriptBlock)
{
    $tab = $psISE.PowerShellTabs.Add()
    $tab.DisplayName = $name
    sleep 2
    $tab.Invoke($scriptBlock)
}

しかし、私はそれをそう走らせるとき

$v = "hello world"
Start-NewTab "Test" { $v }

hello world isn't shown, unlike the following fragement

function Test-ScriptBlock([ScriptBlock]$sb) { & $sb }
Test-ScriptBlock { $v }

ここでは何が起こっているのですか?どうすれば修正できますか?

7

3 答え

"タブ"コンテナは、ランスペース(または powershell実行環境)と同じです。 )をISEに追加しました。新しいTab(つまりPowerShell実行環境)を作成しているので、変数vはその実行環境では未定義です。スクリプトブロックは、新しい実行環境で評価され、v(何もない)の値を出力します。

Test-Scriptblockの場合、Start-NewTabの場合と同じ変数が見つかるはずのスコープを明示的に記述してスクリプトブロック内の変数を取得しようとすると、変数の解像度がどのように異なるかを簡単に確認できます。

PS>Test-ScriptBlock { get-variable v -scope 0}
Get-Variable : Cannot find a variable with name 'v'.
PS>Test-ScriptBlock { get-variable v -scope 1}
Get-Variable : Cannot find a variable with name 'v'.
PS>Test-ScriptBlock { get-variable v -scope 2} # Variable found in grandparent scope (global in the same execution environment)
Name                           Value                                                                                                                           
----                           -----                                                                                                                           
v                              hello world

PS>Start-NewTab "Test" { get-variable v -scope 0 } # global scope of new execution environment
Get-Variable : Cannot find a variable with name 'v'.
PS>Start-NewTab "Test" { get-variable v -scope 1 } # proof that scope 0 = global scope
Get-Variable : The scope number '1' exceeds the number of active scopes.

問題の回避策の1つは、scriptblockに変数を定義することです。

Start-NewTab "Test" { $v = "hello world";$v }

Edit: One more thing, your title mentions 'closure'. Scriptblocks in Powershell are not closures, however you can create a closure from a scriptblock. This won't help you with the problem you describe, though.

Edit2: Another workaround:

$v = "hello world"
Invoke-Expression "`$script = { '$v' }"
Start-NewTab "test" $script
1
追加された
どのように役立つのですか?スクリプトブロックに必要なデータを作成できれば、変数を使用する必要はありません
追加された 著者 Scott Weinstein,
私はあなたの特定の問題の制限が何であるか分かりませんが、私は別の回避策で自分の投稿を更新しました。
追加された 著者 jon Z,

私はこれが古い質問だと知っていますが、私は最近、この問題の新しい回避策を見つけました。それは誰かにとって有用かもしれません。

環境変数を使用する:

function Start-NewTab($name, [ScriptBlock]$scriptBlock)
{
    $tab = $psISE.PowerShellTabs.Add()
    $tab.DisplayName = $name
    sleep 2
    $tab.Invoke($scriptBlock)
}

$env:v = "hello world"
Start-NewTab "Test" { $env:v }
0
追加された

または、スクリプトブロックを最初に作成するだけです。

$v={"Hello world"}                                                                                                    
start-newtab "test" $v 

しかし、あなたは範囲を念頭に置かなければなりません。

0
追加された
これはどのように役立ちますか?
追加された 著者 Scott Weinstein,
@ScottWeinsteinスクリプトブロックの作成は、最初に動作します。間違いなく範囲の問題のように見えます。変数vは、スクリプトブロック外で定義されている場合、関数内ではnullです。
追加された 著者 Andy Arismendi,
@AndyArismendi実際にはスコープの問題ではありません(新しい実行環境では $ v が評価されます)。ただし、変数をフェッチするときにスコープを明示的に指定することでこれを実証できます。私の答えを見てください。
追加された 著者 jon Z,
彼の機能は有効で、彼がする必要があるのは正しいオブジェクトを渡すことだけです。すべて私は彼が正しい値を渡すと、Start-NewTabが働くことを示していました。しかし、ここでの本当の問題は、最初は現在のPowerShellセッションの変数からスクリプトブロックを作成することだと思います。
追加された 著者 Jeffery Hicks,