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.