PowerShell Gotcha! - dynamic scoping
PowerShell uses dynamic scoping. Yet the about_Scopes page doesn't mention the word "dynamic".
Wird (wird - so weird that you need to misspell weird to get your point across).
tl;dr;
In PowerShell variables are copied into the stack frame created for the function you're calling. So the "child" function can use your variables but can only modify its own copies.
You can avoid this by setting your variable to private $private:varName=...
and using Set-StrictMode -version latest
to throw an error if "child" functions try to access a undefined variable.
PowerShell uses dynamic scoping. What we know from most programming languages is lexical scoping.
function Do-InnerFunction { Write-Host $t }
function Do-OutterFunction {
$t = "hello"
Do-InnerFunction
}
Do-OutterFunction
Weird! (this is dynamic scoping)
Set-StrictMode -Version Latest
function Do-InnerFunction { Write-Host $t }
function Do-OutterFunction {
$t = "hello"
Do-InnerFunction
}
Do-OutterFunction
Set-StrictMode -Off # remember to turn strict mode off for further testing
Weird! (but makes sense since in PowerShell's world this is perfectly legal hence "strict" changes nothing here)
function Do-InnerFunction { Write-Host $t }
function Do-OutterFunction {
$private:t = "hello"
Do-InnerFunction
}
Do-OutterFunction
Output is empty. No errors but at least $t
behaves more like a variable we know from C#/F#.
Set-StrictMode -Version Latest
function Do-InnerFunction { Write-Host $t }
function Do-OutterFunction {
$private:t = "hello"
Do-InnerFunction
}
Do-OutterFunction
InvalidOperation: C:\Users\...\Temp\44f5ff41-4105-482b-a134-b505049d2c61\test3.ps1:2
Line |
2 | Write-Host $t
| ~~
| The variable '$t' cannot be retrieved because it has not been set.
Finally!
function Do-InnerFunction {
Write-Host $t
$t = "world"
Write-Host $t
}
function Do-OutterFunction {
$t = "hello"
Do-InnerFunction
Write-Host $t
}
Do-OutterFunction
Ah! So variables are copied to the next "scope".
function Do-InnerFunction {
Write-Host $t
$global:t = "world"
Write-Host $t
}
function Do-OutterFunction {
$t = "hello"
Do-InnerFunction
Write-Host $t
}
Do-OutterFunction
Write-Host $t
Now we have created a global
$t
variable.
This https://ig2600.blogspot.com/2010/01/powershell-is-dynamically-scoped-and.html explains it nicely.