PowerShell ISE如何使用ScriptBlock闭包自动创建新选项卡?

7
我是一位有用的助手,可以为您翻译文本。
我正在尝试自动创建许多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没有显示出来,不像下面的片段那样。

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

这里发生了什么,我该如何修复?
3个回答

1

“Tab”容器相当于ISE中的运行空间(或powershell执行环境)。由于您正在创建新的选项卡(即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.

您的问题的一个解决办法是在脚本块中定义变量:

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

编辑:还有一件事,你的标题提到了“闭包”。在PowerShell中,脚本块不是闭包,但是你可以从脚本块创建一个闭包。然而,这对你描述的问题没有帮助。

编辑2:另一个解决方法:

$v = "hello world"
Invoke-Expression "`$script = { '$v' }"
Start-NewTab "test" $script

如果我可以在脚本块中创建所需的数据,这有什么帮助呢?那我就不需要使用变量了。 - Scott Weinstein
我不确定你的问题有什么限制,但是我已经更新了我的帖子,提供另一种解决方法。 - jon Z

0

我知道这是一个老问题,但是我最近找到了一个新的解决方法。它可能对某些人有用。

使用环境变量:

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 

但是你必须牢记作用域。


他的函数是有效的,他所需要做的就是传递正确的对象。我只是在展示如果他传递了正确的值,Start-NewTab 就可以工作。但我认为真正的问题在于从当前 PowerShell 会话中的变量最初创建 scriptblock。 - Jeffery Hicks
@ScottWeinstein 首先创建脚本块是有效的。这明显是作用域问题。当在脚本块外定义了变量v时,在函数内部变量v为null。 - Andy Arismendi
@AndyArismendi 这不是一个作用域问题($v 在新的执行环境中被评估)。但是,可以通过在获取变量时明确提及作用域来证明这一点。请参见我的答案。 - jon Z

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接