Is there any way for a powershell module to get at its caller's scope? Is there any way for a powershell module to get at its caller's scope? powershell powershell

Is there any way for a powershell module to get at its caller's scope?


$PSCmdlet.SessionState seems to provide a function inside a script module access to the call site's variables provided the call site is outside the module. (If the call site is inside the module, you can just use Get- and Set-Variable -Scope.) Here is an example using SessionState:

New-Module {    function Get-CallerVariable {        param([Parameter(Position=1)][string]$Name)        $PSCmdlet.SessionState.PSVariable.GetValue($Name)    }    function Set-CallerVariable {        param(            [Parameter(ValueFromPipeline)][string]$Value,            [Parameter(Position=1)]$Name        )        process { $PSCmdlet.SessionState.PSVariable.Set($Name,$Value)}    }} | Import-Module$l = 'original value'Get-CallerVariable l'new value' | Set-CallerVariable l$l

which outputs

original valuenew value

I'm not sure whether SessionState was intended to be used in this manner. For what it's worth, this is the same technique used in Get-CallerPreference.ps1. There are also some test cases here which pass on PowerShell versions 2 through 5.1.


Not sure if I understand completely what you are after. I believe you would like to know where is the code implemented that invokes the cmdlets of you module. Maybe even further up.

If I'm correct then you can use Get-PSCallStack to retrieve the stack trace. For example from an unsaved script it looks like this

PS C:\Users\asarafian> Get-PSCallStackCommand       Arguments Location -------       --------- -------- <ScriptBlock> {}        <No file>

If the file was saved then it would look like this

PS C:\Users\asarafian> Get-PSCallStackCommand       Arguments Location -------       --------- -------- File1.ps1           <No file>

Depending on what you want to achieve, which is not clear to me, you need to walk the list from [0] which is the code that executed Get-PSCallStack to [x].

When building the XWrite I wanted also to figure out if an entry from the stack was a script file, a cmdlet part of a module or unknown like <ScriptBlock>.

My implementation is in Get-XCommandSource.ps1 and it follows the following logic for the command value from the stacktrace

  1. if it ends with .ps1 then it's a script file.
  2. if it is <ScriptBlock> then it's a script block.
  3. if the command can be loaded with Get-Command then
    1. if it has a module then it's a cmdlet in a module.
    2. if not then it's a cmdlet/function imported with .\cmdlet.ps1 pattern.

Here is the implementation:

function Get-XCommandSource{    [CmdletBinding(SupportsShouldProcess=$true)]    Param(        [Parameter(Mandatory=$true)]        [AllowEmptyString()]        [AllowNull()]        [string]$Command    )    begin {    }    process {        if(-not $Command)        {            "Unknown"        }        elseif($Command.EndsWith(".ps1"))        {            "Script"        }        elseif($Command -eq "<scriptblock>")        {            "Unknown"        }        else        {            $cmdlet=Get-Command -Name $command -ErrorAction SilentlyContinue            if($cmdlet)            {                $moduleName=$cmdlet|Select-Object -ExpandProperty ModuleName                if($moduleName)                {                    $moduleName                }                else                {                    "Function"                }            }            else            {                "Unknown"            }        }    }    end {    }}