2

Please, observe:

C:\> $TestVariable
C:\> $a
C:\> get-command Test-VariableExport

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Function        Test-VariableExport                                0.0.0.1    Test


C:\> (get-command Test-VariableExport).ScriptBlock

    $script:TestVariable = Get-Date

C:\> Test-VariableExport
C:\> $TestVariable
C:\> function f() { $script:a = Get-Date }
C:\> f
C:\> $a

Monday, April 15, 2019 2:48:59 PM


C:\> f
C:\> $a

Monday, April 15, 2019 2:49:03 PM


C:\>

The same exact code when inside just a function works - the variable a is exported from the function to the outer scope. But when the function is part of a module as is the case of the Test-VariableExport function - the export does not work.

How can I make it work for a module function?

2

1 Answer 1

6

The behavior is all about scopes. The TLDR:

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

Basically, since modules are not a child scope, they can't set script scoped variables in the "parent" script scope.

Let's test scopes inside a Module:

sampleModule.psm1

Function Test-Local { $local:l = Get-Date }
Function Test-Script { $script:s = Get-Date }
Function Test-Global { $global:g = Get-Date }

#Only present desired functions
Export-ModuleMember -Function Test-Local, Test-Script, Test-Global

And running:

PS C:> Import-Module .\sampleModule.psm1

PS C:> Test-Local
PS C:> Test-Script
PS C:> Test-Global

PS C:> Write-Host "Local $l"
Local
PS C:> Write-Host "Script $s"
Script
PS C:> Write-Host "Global $g"
Global 04/15/2019 17:12:23

As we can see, since Modules run in their own self contained environment but are still a part of the global scope session, the only way to pass variables around in this use case is to use the $global scope.

Functions also act differently depending on how you run them as well. For ex. Take this sample script:

sample.ps1

Function Test-Local { $local:l = Get-Date }
Test-Local

Function Test-Script { $script:s = Get-Date }
Test-Script

Function Test-Global { $global:g = Get-Date }
Test-Global

And at the prompt let's run it in the script scope:

PS C:> .\sample.ps1

PS C:> Write-Host "Local $l"
Local
PS C:> Write-Host "Script $s"
Script
PS C:> Write-Host "Global $g"
Global 04/15/2019 17:14:56

Notice that you can't access the variable from the local or script scope. Let's restart PowerShell and now try the Call Operator (&):

PS C:> & .\sample.ps1

PS C:> Write-Host "Local $l"
Local
PS C:> Write-Host "Script $s"
Script
PS C:> Write-Host "Global $g"
Global 04/15/2019 17:22:07

Same results. Now let's run it in the local scope with the dot (.) operator:

PS C:> . .\sample.ps1

PS C:> Write-Host "Local $l"
Local
PS C:> Write-Host "Script $s"
Script 04/15/2019 17:24:16
PS C:> Write-Host "Global $g"
Global 04/15/2019 17:24:16

Now we can see the variable in the script scope is passed out. We won't ever see the Local scoped variables because they only are present in their current scope. e.g. in this example self contained to the inside of the function.

Sign up to request clarification or add additional context in comments.

1 Comment

In the last sample, do you mean . .\sample.ps1 ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.