Powershell: CommandInvocationIntrinsics.InvokeScript(SessionState, ...) should strip ScriptBlock SessionState affinity

Created on 3 Jun 2020  ·  4Comments  ·  Source: PowerShell/PowerShell

/cc @TobiasPSP @rjmholt

Steps to reproduce

[psmoduleinfo]::new{
    function Invoke-InCallerContext {
        [CmdletBinding()]
        param()
        end {
            $sb = { $ExecutionContext.SessionState.Module.Name }
            $ExecutionContext.InvokeCommand.InvokeScript($PSCmdlet.SessionState, $sb, @())
        }
    }

    function Invoke-InCallerContextFixed {
        [CmdletBinding()]
        param()
        end {
            $sb = { $ExecutionContext.SessionState.Module.Name }
            $ExecutionContext.InvokeCommand.InvokeScript($PSCmdlet.SessionState, $sb.Ast.GetScriptBlock(), @())
        }
    }

    Export-ModuleMember -Function Invoke-InCallerContext, Invoke-InCallerContextFixed
} | Import-Module -Force

Expected behavior

PS> Invoke-InCallerContext
# returns nothing
PS> Invoke-InCallerContextFixed
# returns nothing

Actual behavior

PS> Invoke-InCallerContext
# returns __DynamicModule_{guid here}
PS> Invoke-InCallerContextFixed
# returns nothing

Environment data

Name                           Value
----                           -----
PSVersion                      7.1.0-preview.2
PSEdition                      Core
GitCommitId                    7.1.0-preview.2
OS                             Microsoft Windows 10.0.18362
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

This happens because the API sets the ExecutionContext.EngineSessionState instead of the ScriptBlock.SessionState like & $module { } syntax does.

Issue-Bug WG-Engine

All 4 comments

Very interesting. This looks like a bug @daxian-dbw

Yeah when you mentioned it on the panel I was confused because I thought I had tried it before and it just straight up didn't work. Makes sense after looking at the source though.

Also probably better to open a new issue for this, but the API doesn't give you an option to specify if a new scope should be created. As a workaround, you can (but probably shouldn't) do this:

$module = [psmoduleinfo]::new($false)

# Surprised this set accessor is public 🤷‍♂️
$module.SessionState = $PSCmdlet.SessionState

& $module { 'new scope in the target session state' }
. $module { 'no new scope in the target session state' }

@SeeminglyScience PSModuleInfo was only intended to be a public facade for a module that already existed. Take a look at 'ModuleIntrinsics.csfor the details of module construction. Really, the only recommended way to create a new module is with theNew-Module` cmdlet. Is that insufficient?

@bpayette I don't think that's what this issue is about at all.

@SeeminglyScience was just demonstrating a hacky workaround that works in the meantime.

Was this page helpful?
0 / 5 - 0 ratings