module.psm1 with contentFunction With-Foo {
param([ScriptBlock]$fn)
$foo = 4
&$fn
}
Export-ModuleMember -Function *
main.ps1 with contentImport-Module ".../module.psm1"
With-Foo { Write-Host $foo }
main.ps14
<nothing>
&$fn is replaced with &([ScriptBlock]::Create($fn.ToString())) the code also works across modules.> $PSVersionTable
Name Value
---- -----
PSRemotingProtocolVersion 2.3
PSVersion 6.0.0-alpha
GitCommitId v6.0.0-alpha.17
WSManStackVersion 3.0
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
PSEdition Core
CLRVersion
BuildVersion 3.0.0.0
SerializationVersion 1.1.0.1
To clarify, the same issue occurs when using modules defined via New-Module.
$m = New-Module -ScriptBlock {
Function With-Foo {
param([ScriptBlock]$fn)
$foo = 4
&$fn
}
}
With-Foo { Write-Host $foo }
will not output anything.
A script block is associated with the SessionState that it was created in, and it will execute in that same SessionState, because the script block is very likely depending on the state (functions, variables and etc) of the SessionState it was created in.
In your example, With-Foo will run in the module SessionState while {write-host $foo} is defined in a different SessionState, and thus it won't be able to see the variables defined in the module SessionState when running within With-Foo.
Here is an example to demonstrate that:
PS:1> $m = New-Module -ScriptBlock {
>> Function With-Foo {
>> param([ScriptBlock]$fn)
>> $foo = 4
>> &$fn
>> }
>> }
PS:2> & { $foo = 100; With-Foo { Write-Host $foo } }
100
PS:3>
To achieve what you expect, you can define With-Foo like this:
$m = New-Module -ScriptBlock {
Function With-Foo {
param([ScriptBlock]$fn)
$foo = 4
$newfn = $fn.Ast.GetScriptBlock() # create a new script block via the AST
& $newfn
}
}
Then you will get what you expect:
PS:1> $m = New-Module -ScriptBlock {
>> Function With-Foo {
>> param([ScriptBlock]$fn)
>> $foo = 4
>> $newfn = $fn.Ast.GetScriptBlock() # create a new script block via the AST
>> & $newfn
>> }
>> }
PS:2>
PS:2> With-Foo { Write-Host $foo }
4
PS:3>
Most helpful comment
A script block is associated with the SessionState that it was created in, and it will execute in that same SessionState, because the script block is very likely depending on the state (functions, variables and etc) of the SessionState it was created in.
In your example,
With-Foowill run in the module SessionState while{write-host $foo}is defined in a different SessionState, and thus it won't be able to see the variables defined in the module SessionState when running withinWith-Foo.Here is an example to demonstrate that:
To achieve what you expect, you can define
With-Foolike this:Then you will get what you expect: