Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.7k views
in Technique[技术] by (71.8m points)

powershell - Is it optional to use the $global: scope prefix when referencing a global variable?

If I declare and initialize a PowerShell variable with $global:MyVariable = "123" do I then need to use $global: anywhere I use the variable or can I just use $MyVariable?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
  • 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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...