Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PowerShell ISE how to automate new tab creation with ScriptBlock closures?

I'm trying to automate creation of a bunch of tabs in PowerShell ISE

I've started with a function such as

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

however when I run it like so

$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 }

What's going on here and how do I fix it?

like image 861
Scott Weinstein Avatar asked Feb 06 '12 15:02

Scott Weinstein


People also ask

How to close a tab in PowerShell?

To close a tab, you can use any of the following techniques: 1 Click the tab that you want to close. 2 On the File menu, click Close PowerShell Tab, or click the Close button ( X) on an active tab to close the tab. More ...

What is a ScriptBlock in PowerShell?

A script block is an instance of a Microsoft.NET Framework type System.Management.Automation.ScriptBlock. Commands can have script block parameter values. For example, the Invoke-Command cmdlet has a ScriptBlock parameter that takes a script block value, as shown in this example:

How to add begin process and end to a ScriptBlock?

Like a function, Begin process and End can be added to a scriptblock. The begin block is used to define variables, path etc. The process block contains the code for manipulation. End block is cleaning up the code. $username = { Write-Host "my name is $ ($args [0])..."

How do I create a new PowerShell tab?

On the File menu, click New PowerShell Tab. The new PowerShell tab always opens as the active window. PowerShell tabs are incrementally numbered in the order that they are opened. Each tab is associated with its own Windows PowerShell console window.


1 Answers

A "Tab" container is equated to a runspace (or powershell execution environment) in the ISE. Since you are creating a new Tab (i.e. powershell execution environment) the variable v is undefined in that execution environment. The scriptblock is evaluated in the new execution environment and outputs the value of v (nothing).

It's easy to see how variable resolutions differs in the case of Test-Scriptblock from the case of Start-NewTab if you try to get the variable in the scriptblock by explicitly mentioning the scope where the variable should be found.

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.

One workaround for your problem is to define your variable in the 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
like image 175
jon Z Avatar answered Nov 15 '22 09:11

jon Z