In principle you can use just $MyVariable
to reference the value of a global variable by that name, but you may see a different variable's value, situationally.
Specifically, if any intervening ancestral (parent) scope or even the calling scope itself has also created a $MyVariable
variable (which typically happens implicitly by simple assigmnent; e.g., $MyVariable = ...
), you will see that variable's value instead.
You're only guaranteed to see the global value if you do use the global scope specifier, namely: $global:MyVariable
(or Get-Variable -ValueOnly -Scope Global MyVariable
)[1]
By default, variables are visible, but not directly modifiable in all descendant (child) scopes.
- Therefore you must use
$global:MyVariable
/ Set-Variable -Scope Global
in order to modify (set) a global variable; without $global:
you'll implicitly create a local variable by the same name.
- For more on PowerShell's scoping rules, see the last section of this answer.
[1] In real-world scenarios, even code in PowerShell modules sees global variables with scope specifier $global:
, and the implicit visibility of global variables always applies.
For in-memory modules, there is a way to make $global
/ -Scope global
refer to a different scope, namely the module's own top-level scope, but the technique is obscure, not documented, and its real-world utility is unknown.
Read on, if you want to know more.
Optional reading: Creating an in-memory module that sees its own top-level scope as the global scope:
PetSerAl has discovered a little-known way to create an in-memory module in a manner that makes it see $global:
/ -Scope global
as its own top-level scope rather than the true global scope - curiously, not using an explicit scope reference makes the code still see (non-shadowed) global variables:
$global:MyVariable = 42 # Create a true global variable.
# Create an in-memory module for which its *own top-level scope*
# becomes the "global" scope, by virtue of passing $false to the
# [psmoduleinfo] constructor:
& ([psmoduleinfo]::new($false)) {
@"
'$global:MyVariable',
'$(Get-Variable -ValueOnly -Scope global MyVariable)',
'$MyVariable'
"@
}
yields:
Get-Variable : Cannot find a variable with the name 'MyVariable'.
# ...
'', # $global:MyVariable didn't find the variable
'', # Neither did Get-Variable -Scope Global (see error above)
'42' # OK - implicit visibility of true global variables
Note that neither New-Module
nor Import-Module
(for persisted modules) offer this functionality.
The obscure & <module-info> { ... }
technique used above for invoking a script block in a module's scope is explained in this excellent blog post by Patrick Meinecke.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…