2

When I add to an array in a function, it works in the ISE, but in the command window it does not add.

Clear
$array = @()

FUNCTION AddtoArray() {
    Write "start of function"
    $array
    $global:array += "c "
    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

When I run this in PowerGUI or PowerShell ISE I get:

a

a b

a b

a b c

a b c

When I run this from the Powershell command windows I get:

a

a b

a b

a b

a b

The function += is not adding the "c" when the script is called from the PS cmd window. When I ran it without $global:array += "c " it would work in PowerGui but PS ISE would return just the addition and lose the "a b".

2
  • 1
    What version of PowerShell? I see the ISE results in V2 and V4 consoles. Commented May 21, 2015 at 19:52
  • V3 and V4, yes, ISE is running as expected, it's when it is ran from the PS cmd window that the issue shows Commented May 21, 2015 at 21:52

1 Answer 1

4

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)

Sign up to request clarification or add additional context in comments.

6 Comments

Excellent answer! about_Scopes is also available online, which you can also get to with Get-Help about_Scopes -Online.
Thank you Mathias, that makes sense, and I do have multiple "c" as you explained. What is the correct formatting then to have the array added to instead of replaced?
@Michael Oh, this was in a script file. You should have mentioned that in your post. I just figured you were F5'ing in ISE and pasting into the console. To fix, change $global:array in your function to $script:array.
@Michael updated answer with a solution (ab)using the relativity between child/parent scopes
Sorry Keith, I wasn't sure the proper name for it so i was just calling it Powershell Command Window, I meant the non ISE run space. Changing to $Script:array worked! Thank you, I can't mark this as the correct answer for you to get the points from the comments section. Can you repost as an answer so I can give you credit?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.