PowerShell Multidimensional Arrays (Jagged and 2D)

A multidimensional array in PowerShell is usually an array of arrays, called a jagged array. Each inner array is a row, and you read a value with two indexes, $array[row][column]:

$sales = @(
    @('Austin', 18250, 21400),
    @('Denver', 12400, 13900),
    @('Miami',  20975, 19800)
)

"Rows: $($sales.Count)"
"Row 1, column 0: $($sales[1][0])"
"Miami Q2 sales:  $($sales[2][2])"

Output:

Rows: 3
Row 1, column 0: Denver
Miami Q2 sales:  19800

PowerShell also has true two-dimensional arrays like [int[,]], covered further down. I ran every example in PowerShell 7.6 and Windows PowerShell 5.1, with the same results.

Use [row][column], not [row,column]

On a jagged array, a comma inside one pair of brackets means “these indexes”, so $sales[0,1] returns rows 0 and 1 instead of one value:

$sales = @(
    @('Austin', 18250, 21400),
    @('Denver', 12400, 13900),
    @('Miami',  20975, 19800)
)

"`$sales[0][1] is one value:  $($sales[0][1])"
"`$sales[0,1] is two rows:    $(($sales[0,1] | ForEach-Object { $_[0] }) -join ', ')"

Output:

$sales[0][1] is one value:  18250
$sales[0,1] is two rows:    Austin, Denver
PowerShell jagged array $a[0][1] vs $a[0,1]
[0][1] returns 18250, [0,1] returns the first two rows (PowerShell 7)

The [row,column] form is only for true 2D arrays. Microsoft explains array indexing in about_Arrays.

Add a row to a multidimensional array

Adding an array with + or += unrolls it, so the new row’s values become separate items. Put the unary comma in front to add it as one row:

$sales = @(
    @('Austin', 18250, 21400),
    @('Denver', 12400, 13900),
    @('Miami',  20975, 19800)
)

$wrong = $sales + @('Seattle', 15100, 16250)
"Adding @(...) gives $($wrong.Count) items, and item 3 is $($wrong[3])"

$sales += ,@('Seattle', 15100, 16250)
"Adding ,@(...) gives $($sales.Count) rows, and row 3 is $($sales[3] -join ' / ')"

Output:

Adding @(...) gives 6 items, and item 3 is Seattle
Adding ,@(...) gives 4 rows, and row 3 is Seattle / 15100 / 16250
PowerShell add a row to a jagged array with the unary comma
Without the comma, Seattle’s values became three loose items (Windows PowerShell 5.1)

The comma operator wraps the row in a one-item array, which += then unwraps once. Microsoft describes it as the comma operator in about_Operators.

A single row needs the comma too

For the same reason, @(@(…)) with only one row collapses into a flat array:

$one = @(@('Austin', 18250))
"Without a comma: $($one.Count) items, first is $($one[0])"

$one = ,@('Austin', 18250)
"With a comma:    $($one.Count) row, first is $($one[0] -join ' / ')"

Output:

Without a comma: 2 items, first is Austin
With a comma:    1 row, first is Austin / 18250

If you build rows in a loop, add each one with ,@() or use the List shown at the end.

True two-dimensional arrays

For a fixed grid, like a seat map, create a real 2D array with a type and size. Index it with [row, column], and use GetLength for each dimension:

$seats = [string[,]]::new(3, 4)
for ($r = 0; $r -lt $seats.GetLength(0); $r++) {
    for ($c = 0; $c -lt $seats.GetLength(1); $c++) { $seats[$r, $c] = '-' }
}
$seats[1, 2] = 'X'
$seats[0, 0] = 'X'

"Rank: $($seats.Rank), rows: $($seats.GetLength(0)), columns: $($seats.GetLength(1)), cells: $($seats.Count)"
for ($r = 0; $r -lt 3; $r++) {
    "Row $($r + 1): " + ((0..3 | ForEach-Object { $seats[$r, $_] }) -join ' ')
}

Output:

Rank: 2, rows: 3, columns: 4, cells: 12
Row 1: X - - -
Row 2: - - X -
Row 3: - - - -
PowerShell two-dimensional string array seat map
A 3×4 grid with two seats marked (PowerShell 7)

Count is the total number of cells, 12 here, not the number of rows. Rank tells you how many dimensions the array has.

2D arrays have a fixed size

You can’t add rows to a [,] array, and an index outside it throws an error:

$matrix = [int[,]]::new(2, 2)
try { $matrix[2, 0] = 5 } catch { 'Row 2 does not exist, a 2x2 array has rows 0 and 1' }
"Total cells stay fixed at $($matrix.Count)"

Output:

Row 2 does not exist, a 2x2 array has rows 0 and 1
Total cells stay fixed at 4

Pick a jagged array when rows can differ in length or grow, and a [,] array for grids whose size you know up front.

Loop through a multidimensional array

foreach over a jagged array gives you one row at a time:

$sales = @(
    @('Austin', 18250, 21400),
    @('Denver', 12400, 13900),
    @('Miami',  20975, 19800)
)

foreach ($row in $sales) {
    $total = $row[1] + $row[2]
    '{0,-7} Q1 {1,7:C0}  Q2 {2,7:C0}  Total {3,8:C0}' -f $row[0], $row[1], $row[2], $total
}

Output:

Austin  Q1 $18,250  Q2 $21,400  Total  $39,650
Denver  Q1 $12,400  Q2 $13,900  Total  $26,300
Miami   Q1 $20,975  Q2 $19,800  Total  $40,775

For a [,] array, use two for loops with GetLength(0) and GetLength(1), as in the seat map example.

A better option for tables: objects

If each row describes one thing, an array of objects is easier to read, sort and export than an array of arrays:

$sales = @(
    @('Austin', 18250, 21400),
    @('Denver', 12400, 13900),
    @('Miami',  20975, 19800)
)

$sales | ForEach-Object {
    [pscustomobject]@{ City = $_[0]; Q1 = $_[1]; Q2 = $_[2] }
} | Sort-Object -Property Q2 -Descending | Format-Table

Output:

City      Q1    Q2
----      --    --
Austin 18250 21400
Miami  20975 19800
Denver 12400 13900

Named properties replace magic column numbers like $_[2]. Creating an array of objects covers this in detail.

A growable list of rows

For rows you’ll add and remove often, use a List of arrays. Add takes the row as one item, with no comma needed:

$rows = [System.Collections.Generic.List[object[]]]::new()
$rows.Add(@('WEB01', 'Online'))
$rows.Add(@('SQL01', 'Offline'))

"Rows: $($rows.Count), second server: $($rows[1][0]) is $($rows[1][1])"

Output:

Rows: 2, second server: SQL01 is Offline

Frequently Asked Questions

How do I create a multidimensional array in PowerShell?

Use an array of arrays: $grid = @(@(1, 2), @(3, 4)). For a fixed grid, use [int[,]]::new(3, 4).

How do I access an element in a multidimensional array?

Use $grid[row][column] for an array of arrays, and $grid[row, column] for a [,] array.

How do I add a row to a multidimensional array?

Use the unary comma: $grid += ,@('Seattle', 15100). Without it, the values are added as separate items.

How do I get the number of rows and columns?

For a [,] array, use $grid.GetLength(0) for rows and $grid.GetLength(1) for columns. For an array of arrays, use $grid.Count and $grid[0].Count.

Why does my one-row array have the wrong count?

@(@(‘a’, ‘b’)) flattens into two items. Write ,@('a', 'b') to keep it as one row.

More array techniques you can combine with these: