Home Dashboard Directory Help
Search

ScriptBlock created in a module works incorrectly if execute it separately. by Oleg Shevnin


Status: 

Active


13
1
Sign in
to vote
Type: Bug
ID: 559223
Opened: 5/14/2010 11:19:52 AM
Access Restriction: Public
1
Workaround(s)
view
6
User(s) can reproduce this bug

Description

The scriptblock variable that was created in a module may work incorrectly if Invoke it outside the original runspace.
It looks like the following variables become null is this scenario: $_, $args, $input, $this, $pscmdlet
Details
Sign in to post a comment.
Posted by Oleg Shevnin on 8/20/2010 at 5:58 AM
Thank you for the workaround. Unfortunately it doesn't work perfect.

Imagine that these two parts of the script are completely independent (one developer creates a module another one - the script that uses data returned by the module). In this case module developers know nothing about the environment there modules will be executed in. So the solution (or even "best practice") means adding "GetNewClosure()" workaround to ANY scriptblock in ANY module - just in case - to workaround possible issues.

Doesn't sound good :(
Posted by Jason M Archer on 7/21/2010 at 9:44 AM
I don't think this is a bug. Script blocks run in the context they were created in (although $_ being broken may be a bug). The easy solution is to turn the script block into a closure with {}.GetNewClosure().
Posted by Kirk Munro on 5/14/2010 at 11:33 AM
This is by far the worst PowerShell bug to date, with huge impact on tools built on top of PowerShell forcing them to cut functionality or impose unrealistic restrictions on end users (such as not using pipelines in PowerShell modules). :(

Here's another reproduction scenario that doesn't involve C#:

$module = "${env:temp}\a.psm1"
@'
$myvar = 42| Add-Member -Name MyProp -MemberType ScriptProperty -Value { Get-process | %{$_} } -PassThru
Export-ModuleMember -Variable myvar
'@ > $module

$ps = [powershell]::Create()
$null = $ps.AddCommand('Import-Module').AddArgument($module)
$null = $ps.Invoke()
$null = $ps.Commands.Clear()
$null = $ps.AddScript('$myvar')
$ps.Invoke() | % { $_.MyProp }
Sign in to post a workaround.
Posted by Jason M Archer on 7/21/2010 at 9:43 AM
You just need to make the scriptblock a closure if you intend to run it in a different context from where it is created. This is why closures were added.

$module = "${env:temp}\a.psm1"
@'
$myvar = 42| Add-Member -Name MyProp -MemberType ScriptProperty -Value { Get-process | %{$_} }.GetNewClosure() -PassThru
Export-ModuleMember -Variable myvar
'@ > $module

$ps = [powershell]::Create()
$null = $ps.AddCommand('Import-Module').AddArgument($module)
$null = $ps.Invoke()
$null = $ps.Commands.Clear()
$null = $ps.AddScript('$myvar')
$ps.Invoke() | % { $_.MyProp }
File Name Submitted By Submitted On File Size  
Bug.zip (restricted) 5/14/2010 -
Bug.zip 5/14/2010 2 KB