PowerShell Append to Array: +=, Lists and Common Mistakes

To append to an array in PowerShell, use the += operator. It adds the new item to the end, so a list of two servers becomes three:

$servers = 'WEB01', 'WEB02'
$servers += 'SQL01'

$servers -join ', '
"Count: $($servers.Count)"

Output:

WEB01, WEB02, SQL01
Count: 3

That’s all you need for small scripts. But += doesn’t really grow the array. It builds a brand-new one each time, which explains most of the surprises below.

I ran each example in PowerShell 7.6 and Windows PowerShell 5.1. The results matched, apart from the speed test, where the two versions are very different.

Add multiple values to an array

Put several values after +=, separated by commas, or add another array. Either way, each value becomes its own item:

$servers = 'WEB01', 'WEB02'
$servers += 'SQL01', 'SQL02'

$newSite = 'APP01', 'APP02'
$servers += $newSite

$servers -join ', '

Output:

WEB01, WEB02, SQL01, SQL02, APP01, APP02

If you want the second array stored as a single item instead, put a comma in front of it. That’s the unary comma operator:

$groups = @('Admins')
$groups += , ('Sales', 'Support')

"Count: $($groups.Count)"
"Last item: $($groups[-1] -join ' + ')"

Output:

Count: 2
Last item: Sales + Support

Create an empty array and add items

Start with @() and add to it with +=:

$servers = @()
"Starting count: $($servers.Count)"

$servers += 'WEB01'
"After adding:   $($servers.Count)"

Output:

Starting count: 0
After adding:   1

Don’t try .Add() on a normal array. PowerShell arrays have a fixed size, so the method throws an error:

$servers = 'WEB01', 'WEB02'
try {
    $servers.Add('SQL01')
}
catch {
    $_.Exception.InnerException.Message
}

Output:

Collection was of a fixed size.

If you need .Add(), use a list instead, as shown further down.

Add an item to the beginning of an array

Put the new item in its own array first and add the old array after it. Leaving out the @() is a common mistake:

$cities = 'Chicago', 'Houston'

$wrong = 'New York' + $cities
"Without @(): $wrong"

$cities = @('New York') + $cities
"With @():    $($cities -join ', ')"

Output:

Without @(): New YorkChicago Houston
With @():    New York, Chicago, Houston

Without @(), PowerShell sees a string on the left, so it joins everything into one string. The left side decides what + does.

Use a List when the array changes a lot

A generic List can grow in place. It has methods for adding, inserting and removing, which a plain array doesn’t:

$servers = [System.Collections.Generic.List[string]]::new()
$servers.Add('WEB01')
$servers.AddRange([string[]]('WEB02', 'SQL01'))
$servers.Insert(0, 'DC01')
$null = $servers.Remove('WEB02')

$servers -join ', '

Output:

DC01, WEB01, SQL01

Insert(0, ...) is the cleanest way to add to the front. Remove() returns true or false, so I send that to $null.

Why ArrayList prints numbers

You’ll see System.Collections.ArrayList in older scripts. Its Add() method returns the new item’s index, and PowerShell prints it:

$list = [System.Collections.ArrayList]::new()
$list.Add('WEB01')
$list.Add('WEB02')
[void]$list.Add('SQL01')

"Items: $($list -join ', ')"

Output:

0
1
Items: WEB01, WEB02, SQL01

Cast the call to [void] to hide the number. Or better, use List[string], which doesn’t return anything.

Is += slow in PowerShell?

It used to be very slow, and it still is in Windows PowerShell 5.1. I timed three ways of building a 10,000-item array on the same PC:

$count = 10000

$plus = Measure-Command {
    $result = @()
    foreach ($i in 1..$count) { $result += $i }
}
$list = Measure-Command {
    $result = [System.Collections.Generic.List[int]]::new()
    foreach ($i in 1..$count) { $result.Add($i) }
}
$direct = Measure-Command {
    $result = foreach ($i in 1..$count) { $i }
}

'+= operator:      {0,7:N0} ms' -f $plus.TotalMilliseconds
'List.Add():       {0,7:N0} ms' -f $list.TotalMilliseconds
'Loop assignment:  {0,7:N0} ms' -f $direct.TotalMilliseconds

Output in PowerShell 7.6:

+= operator:           53 ms
List.Add():           130 ms
Loop assignment:        6 ms
PowerShell 5.1 array += compared with List.Add and loop assignment speed
The same test in Windows PowerShell 5.1

In 5.1, += took well over a second, because it copies the whole array on every loop. PowerShell 7.5 made += much faster, so 7.6 did it in 53 ms.

The winner in both versions is to let the loop build the array for you. Assign the whole foreach to a variable, and every value it outputs is collected:

$results = foreach ($server in 'WEB01', 'WEB02', 'SQL01') {
    "$server checked"
}

"Collected $($results.Count) results: $($results -join '; ')"

Output:

Collected 3 results: WEB01 checked; WEB02 checked; SQL01 checked

Microsoft describes the 7.5 change, with its own timings, in What’s New in PowerShell 7.5.

How do I add only unique values to an array?

Check the array with -notcontains before you add. It ignores case, so “chicago” counts as a duplicate of “Chicago”:

$cities = 'New York', 'Chicago'

foreach ($city in 'Houston', 'chicago', 'Phoenix') {
    if ($cities -notcontains $city) {
        $cities += $city
    }
}
$cities -join ', '

Output:

New York, Chicago, Houston, Phoenix

Watch the parentheses with -not

A version you’ll find online is if (-not $cities -contains $city). It never adds anything, because -not runs first, on the array:

$cities = 'New York', 'Chicago'
$city   = 'Houston'

if (-not $cities -contains $city) { "Added $city" } else { "Skipped $city" }
if (-not ($cities -contains $city)) { "Added $city" } else { "Skipped $city" }

Output:

Skipped Houston
Added Houston
PowerShell -not -contains precedence mistake when adding unique values to an array
Why the parentheses matter (PowerShell 7)

Wrap the test in parentheses, or just use -notcontains, which avoids the problem entirely.

A HashSet for large lists

For thousands of values, a HashSet is faster, and its Add() tells you whether the value was new. Pass OrdinalIgnoreCase, because a HashSet is case-sensitive by default:

$comparer = [System.StringComparer]::OrdinalIgnoreCase
$cities   = [System.Collections.Generic.HashSet[string]]::new($comparer)

foreach ($city in 'Houston', 'Chicago', 'houston', 'Phoenix') {
    if ($cities.Add($city)) { "Added   $city" } else { "Skipped $city (already there)" }
}

Output:

Added   Houston
Added   Chicago
Skipped houston (already there)
Added   Phoenix

Add to an array inside a function

This one catches a lot of people. Using += inside a function creates a new array there, so the caller’s array doesn’t change:

function Add-Server {
    param($List, $Name)
    $List += $Name
    "Inside the function: $($List.Count) servers"
}

$servers = @('WEB01', 'WEB02')
Add-Server -List $servers -Name 'SQL01'
"Back in the script:  $($servers.Count) servers"

Output:

Inside the function: 3 servers
Back in the script:  2 servers
PowerShell add to array inside a function does not change the original array
The caller still has two servers (PowerShell 7)

Either return the new array and assign it in the script, or pass a List. The function then adds to the same list the caller has:

function Add-Server {
    param([System.Collections.Generic.List[string]]$List, [string]$Name)
    $List.Add($Name)
}

$servers = [System.Collections.Generic.List[string]]::new()
$servers.Add('WEB01')
Add-Server -List $servers -Name 'SQL01'

"Back in the script: $($servers -join ', ')"

Output:

Back in the script: WEB01, SQL01

Frequently Asked Questions

How do I append to an array in PowerShell?

Use $array += 'NewItem'. It creates a new array with the item added to the end. For many additions, use a generic List or collect a loop’s output instead.

Why can’t I use .Add() on a PowerShell array?

Arrays have a fixed size, so .Add() throws “Collection was of a fixed size.” Use +=, or create a [System.Collections.Generic.List[string]].

How do I add an item to the start of an array?

Use $array = @('NewItem') + $array. Without the @(), PowerShell joins everything into a single string.

Is += slow in PowerShell?

In Windows PowerShell 5.1, yes, because it copies the array every time. PowerShell 7.5 and later made it much faster. Assigning a loop’s output to a variable is fastest in both.

Why doesn’t my function change the array I passed in?

+= inside the function creates a new local array. Return it and assign the result, or pass a List and call its Add() method.

Next, try one of these array guides: