Chris Magnuson
Chris Magnuson

Reputation: 5949

How to access variable from calling PowerShell module scope from a called function contained in another module?

Running the following will create two modules with one calling a function in the other where the called function tries to refer to a variable in the scope of the module containing the calling function:

$ModulePath = $env:PSModulePath.Split(";")[0]

New-Item -ItemType Directory -Path $ModulePath\TestModule1 -Force

@"
`$var = 1
function Write-Stuff {
    `$var
}
function Test-WriteStuff {
    Write-Stuff
    Write-Stuff2
}
"@ | Out-File $ModulePath\TestModule1\TestModule1.psm1

New-Item -ItemType Directory -Path $ModulePath\TestModule2 -Force

@"
function Write-Stuff2 {
    `$var
    "`r`nGet-Variable -Scope 0`r`n"
    Get-Variable -Scope 0
   
    "`r`nGet-Variable -Scope 1`r`n"
    Get-Variable -Scope 1
   
    "`r`nGet-Variable -Scope 2`r`n"
    Get-Variable -Scope 2
   
    "`r`nGet-Variable -Scope 3`r`n"
    Get-Variable -Scope 3
}
"@ | Out-File $ModulePath\TestModule2\TestModule2.psm1
 

This results in the following output that shows $Var isn't an available variable in any of the scopes accessible to the called function:

PS C:\Users\user> Test-WriteStuff
1

Get-Variable -Scope 0


Name                           Value                                                                                                                                                                                           
----                           -----                                                                                                                                                                                           
args                           {}                                                                                                                                                                                              
false                          False                                                                                                                                                                                           
input                          System.Collections.ArrayList+ArrayListEnumeratorSimple                                                                                                                                          
MaximumAliasCount              4096                                                                                                                                                                                            
MaximumDriveCount              4096                                                                                                                                                                                            
MaximumErrorCount              256                                                                                                                                                                                             
MaximumFunctionCount           4096                                                                                                                                                                                            
MaximumVariableCount           4096                                                                                                                                                                                            
MyInvocation                   System.Management.Automation.InvocationInfo                                                                                                                                                     
null                                                                                                                                                                                                                           
PSBoundParameters              {}                                                                                                                                                                                              
PSCommandPath                  C:\Users\cmagnuson\OneDrive - tervis.com\Documents\WindowsPowerShell\Modules\testmodule2\testmodule2.psm1                                                                                       
PSScriptRoot                   C:\Users\cmagnuson\OneDrive - tervis.com\Documents\WindowsPowerShell\Modules\testmodule2                                                                                                        
true                           True                                                                                                                                                                                            

Get-Variable -Scope 1

args                           {}                                                                                                                                                                                              
Error                          {}                                                                                                                                                                                              
false                          False                                                                                                                                                                                           
MaximumAliasCount              4096                                                                                                                                                                                            
MaximumDriveCount              4096                                                                                                                                                                                            
MaximumErrorCount              256                                                                                                                                                                                             
MaximumFunctionCount           4096                                                                                                                                                                                            
MaximumVariableCount           4096                                                                                                                                                                                            
MyInvocation                   System.Management.Automation.InvocationInfo                                                                                                                                                     
null                                                                                                                                                                                                                           
PSCommandPath                  C:\Users\cmagnuson\OneDrive - tervis.com\Documents\WindowsPowerShell\Modules\testmodule2\testmodule2.psm1                                                                                       
PSDefaultParameterValues       {}                                                                                                                                                                                              
PSScriptRoot                   C:\Users\cmagnuson\OneDrive - tervis.com\Documents\WindowsPowerShell\Modules\testmodule2                                                                                                        
true                           True                                                                                                                                                                                            

Get-Variable -Scope 2

$                              testmodule2                                                                                                                                                                                     
?                              True                                                                                                                                                                                            
^                              ipmo                                                                                                                                                                                            
args                           {}                                                                                                                                                                                              
ConfirmPreference              High                                                                                                                                                                                            
ConsoleFileName                                                                                                                                                                                                                
DebugPreference                SilentlyContinue                                                                                                                                                                                
Error                          {The scope number '3' exceeds the number of active scopes....                                                                                                                                   
ErrorActionPreference          Continue                                                                                                                                                                                        
ErrorView                      NormalView                                                                                                                                                                                      
ExecutionContext               System.Management.Automation.EngineIntrinsics                                                                                                                                                   
false                          False                                                                                                                                                                                           
FormatEnumerationLimit         4                                                                                                                                                                                               
HOME                           C:\Users\cmagnuson                                                                                                                                                                              
Host                           System.Management.Automation.Internal.Host.InternalHost                                                                                                                                         
InformationPreference          SilentlyContinue                                                                                                                                                                                
input                          System.Collections.ArrayList+ArrayListEnumeratorSimple                                                                                                                                          
MaximumAliasCount              4096                                                                                                                                                                                            
MaximumDriveCount              4096                                                                                                                                                                                            
MaximumErrorCount              256                                                                                                                                                                                             
MaximumFunctionCount           4096                                                                                                                                                                                            
MaximumHistoryCount            4096                                                                                                                                                                                            
MaximumVariableCount           4096                                                                                                                                                                                            
ModulePath                     C:\Users\cmagnuson\OneDrive - tervis.com\Documents\WindowsPowerShell\Modules                                                                                                                    
MyInvocation                   System.Management.Automation.InvocationInfo                                                                                                                                                     
NestedPromptLevel              0                                                                                                                                                                                               
null                                                                                                                                                                                                                           
OutputEncoding                 System.Text.SBCSCodePageEncoding                                                                                                                                                                
PID                            9552                                                                                                                                                                                            
profile                        C:\Users\cmagnuson\OneDrive - tervis.com\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1                                                                                        
ProgressPreference             Continue                                                                                                                                                                                        
PSBoundParameters              {}                                                                                                                                                                                              
PSCommandPath                                                                                                                                                                                                                  
PSCulture                      en-US                                                                                                                                                                                           
PSDefaultParameterValues       {}                                                                                                                                                                                              
PSEdition                      Desktop                                                                                                                                                                                         
PSEmailServer                                                                                                                                                                                                                  
PSHOME                         C:\Windows\System32\WindowsPowerShell\v1.0                                                                                                                                                      
psISE                          Microsoft.PowerShell.Host.ISE.ObjectModelRoot                                                                                                                                                   
PSScriptRoot                                                                                                                                                                                                                   
PSSessionApplicationName       wsman                                                                                                                                                                                           
PSSessionConfigurationName     http://schemas.microsoft.com/powershell/Microsoft.PowerShell                                                                                                                                    
PSSessionOption                System.Management.Automation.Remoting.PSSessionOption                                                                                                                                           
PSUICulture                    en-US                                                                                                                                                                                           
psUnsupportedConsoleApplica... {wmic, wmic.exe, cmd, cmd.exe...}                                                                                                                                                               
PSVersionTable                 {PSVersion, PSEdition, PSCompatibleVersions, BuildVersion...}                                                                                                                                   
PWD                            C:\Users\cmagnuson                                                                                                                                                                              
ShellId                        Microsoft.PowerShell                                                                                                                                                                            
StackTrace                        at System.Management.Automation.SessionStateInternal.GetScopeByID(Int32 scopeID)...                                                                                                          
true                           True                                                                                                                                                                                            
VerbosePreference              SilentlyContinue                                                                                                                                                                                
WarningPreference              Continue                                                                                                                                                                                        
WhatIfPreference               False                                                                                                                                                                                           

Get-Variable -Scope 3

Get-Variable : The scope number '3' exceeds the number of active scopes.
Parameter name: scopeID
Actual value was 3.
At C:\Users\cmagnuson\OneDrive - tervis.com\Documents\WindowsPowerShell\Modules\testmodule2\testmodule2.psm1:21 char:5
+     Get-Variable -Scope 3
+     ~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Get-Variable], PSArgumentOutOfRangeException
    + FullyQualifiedErrorId : ArgumentOutOfRange,Microsoft.PowerShell.Commands.GetVariableCommand

The reason for trying to do this is enable PSTemplateEngine to function without requiring someone to pass in a hash table with the variable names and values or something like -ArgumentsList and then require them to have a param block in their template.

Invoke-ProcessTemplatePath specifically could point to a tree structure with many files each containing many variables each. A single imaginary -ArgumentsList might contain 40 values and each template file would have to have a param block 40 parameters long since the parameters are passed position ally. The hash table would work better but I still want to avoid it if possible.

How can I access the variable $Var from the calling function's module's scope from the called function without passing a hashtable, the value of $Var, a parameter with the value of $(Get-Variable), etc.?

Upvotes: 3

Views: 2853

Answers (2)

bielawski
bielawski

Reputation: 1702

Since the OP didn't mention how they actually solved the problem (only alluding to a hash table but not describing how it's done) I'll flesh it out one way to do it since it may not be obvious.

First I create a variable to test with because your environment will contain other variables and I want to demo accessing one of them. The next line loads a hash table with references to all the variables accessible from the current scope. The hash table can then be passed to any function.

$x = 'Some value'
$a = Get-ChildItem variable:|&{begin{$h=@{}}process{$h[$_.name]=$_}end{$h}}

Because the hash table stores references the variable's content can be modified.

$a['x'].value = 'A different value'

So a working copy of the OP's code could look like this:

$ModulePath = $env:PSModulePath.Split(";")[0]

@'
$var = 1
function Write-Stuff {
    $var
}
function Test-WriteStuff {
    Write-Stuff
    $a = Get-ChildItem variable:|&{begin{$h=@{}}process{$h[$_.name]=$_}end{$h}}
    Write-Stuff2 $a
    Write-Stuff
}
'@ | Out-File $ModulePath\TestModule1\TestModule1.psm1

@'
function Write-Stuff2 {
    param ($all)
    $all['var'].value
    $all['var'].value=101
}
'@ | Out-File $ModulePath\TestModule2\TestModule2.psm1

Where the results would be

1
1
101

Upvotes: 0

briantist
briantist

Reputation: 47792

Modules exist in their own world; it's not a scope but it sort of acts like one. From about_Scopes:

Sessions, modules, and nested prompts are self-contained environments, but they are not child scopes of the global scope in the session.

The privacy of a module behaves like a scope, but adding a module to a session does not change the scope. And, the module does not have its own scope, although the scripts in the module, like all Windows PowerShell scripts, do have their own scope.

So you're not going to be able to access the variable in one module from another using scope semantics.

You can export a variable from one of the modules using Export-ModuleMember -Variable.

I don't fully understand what that templating engine is or does, but on the surface, what you're trying to do sounds very wrong.

Passing values as parameters is probably the right way to pass data into functions.

Upvotes: 3

Related Questions