3

I have the following piece of code:

$x = 'xyz'
& {
    $y = 'abc'
    foo
}

The foo function is defined in the foo.psm1 module which is imported before the script block is started.

Inside the foo function, I call Get-Variable which shows me x but it doesn't show y. I tried playing with the -Scope parameter: Local, Script, Global, 0 - which is the local scope from what I understood from the docs, 1 - which is the parent scope.

How could I get the y variable inside the foo function?

I'm not looking for a solution such as passing it as an argument. I want something as Get-Variable but sadly it doesn't see it for some reason.

UP

Based on the comments received, probably more context is needed.

Say that foo receives a ScriptBlock which is using the $using: syntax.

$x = 'xyz'
& {
    $y = 'abc'
    foo -ScriptBlock {
        Write-Host $using:x
        Write-Host $using:y
    }
}

I'm 'mining' these variables as follows:

$usingAsts = $ScriptBlock.Ast.FindAll( { param($ast) $ast -is [System.Management.Automation.Language.UsingExpressionAst] }, $true) | ForEach-Object { $_ -as [System.Management.Automation.Language.UsingExpressionAst] }
foreach ($usingAst in $usingAsts) {
    $varAst = $usingAst.SubExpression -as [System.Management.Automation.Language.VariableExpressionAst]
    $var = Get-Variable -Name $varAst.VariablePath.UserPath -ErrorAction SilentlyContinue
}       

This is how I'm using Get-Variable and in the case presented above, y cannot be found.

mklement0
  • 382,024
  • 64
  • 607
  • 775
Vivere
  • 1,919
  • 4
  • 16
  • 35

1 Answers1

2

Modules run in their own scope domain (aka session state), which means they generally do not see the caller's variables - unless (a module-external) caller runs directly in the global scope.

  • For an overview of scopes in PowerShell, see the bottom section of this answer.

However, assuming that you define the function in your module as an advanced one, there is a way to access the caller's state, namely via the automatic $PSCmdlet variable.

Here's a simplified example, using a dynamic module created via the New-Module cmdlet:

# Create a dynamic module that defines function 'foo'
$null = New-Module {
  function foo {    
    # Make the function and advanced (cmdlet-like) one, via
    # [CmdletBinding()].
    [CmdletBinding()] param()
    # Access the value of variable $bar in the
    # (module-external) caller's scope.
    # To get the variable *object*, use:
    #    $PSCmdlet.SessionState.PSVariable.Get('bar')
    $PSCmdlet.GetVariableValue('bar')
  }
}

& {
  $bar = 'abc'
  foo
}

The above outputs verbatim abc, as desired.

mklement0
  • 382,024
  • 64
  • 607
  • 775