The Global scope represents the topmost scope of any session, and when you open a prompt and assign $a = "123", then you're implicitly writing to $Global:a.
But when you launch a script, such as:
PS C:\> # Inside our global scope here at the prompt we just opened
PS C:\> .\TestAddToArray.ps1
a
a b
a b
a b
a b
PS C:\>
Any variable assignment inside the TestAddToArray.ps1 file defaults to a Script scope - one that's shared among all the variables and functions inside that script file, but still a child scope to Global.
So, when you first initialize $array, you believe $array to mean $Global:array, but depending on the execution context, it might actually mean $Script:array (skipped the duplicate output):
PS C:\> # Inside our global scope here at the prompt we just opened
PS C:\> .\TestAddToArray.ps1
a # $Script:array is now "a" - $Global:array doesn't exist
a b # $Script:array is now "a ","b " - $Global:array doesn't exist
a b # $Script:array is still "a ","b " - $Global:array is now "c "
PS C:\>
As an experiment, try and call the script 4-5 times, and then type $Global:array and see how many "c "s have been added
The dynamic scope model used in PowerShell can be a little confusing, but it's pretty well explained in the help files:
Get-Help about_Scopes -Full | more
As the help file mentions, you can reference ancestor scopes by supplying an [int] as the -Scope parameter argument (where 0 represents the local/current scope, 1 is the direct parent scope etc.), and herein lies a powerful "workaround":
function AddToArray {
$temp = (Get-Variable -Name array -Scope 1).Value
$temp += "c "
Set-Variable -Name array -Scope 1 -Value $temp
}
Now, if AddToArray is defined and called from the Global scope, it'll write back to $Global:array (the immediate parent scope), but if it happens inside a script file, it now writes back to $Script:array since the Script scope is the immediate parent scope in this context.
The script then becomes:
clear
$array = @()
function AddtoArray {
Write "start of function"
$array
$temp = (Get-Variable -Name array -Scope 1).Value
$temp += "c "
Set-Variable -Name array -Scope 1 -Value $temp
Write "result of add to array function"
$array
}
$array = "a "
Write "New array"
$array
$array += "b "
Write "Add to array"
$array
AddtoArray
Write "Back from Function"
$array
And you'll find that the output is consistent no matter if it's pasted into the command line, executed from a nested prompt, a separate script file, the editor in ISE (you get the idea)