powershell array is a fixed-size data structure in PowerShell storing zero or more items of any type, created with @() or comma-separated syntax. It exposes Count/Length properties and ForEach()/Where() methods for iteration and filtering.
# Create array with @() operator
$fruit = @('Apples','Oranges','Bananas')
# Create array with comma separation
$my_arr = 25, "Codecademy", 1, $False
# Create empty array
$data = @()
# Create array with range operator
$C = 5..8 # $C contains 5, 6, 7, 8
What is a PowerShell array and when to use it?
Arrays in PowerShell are the foundational data structure for storing collections of items — strings, integers, objects, or even nested arrays — in a single variable. Unlike ArrayList or List[[System.Array] type in .NET is fixed-size; you cannot add or remove elements after creation without creating a new array. The @() array subexpression operator enforces array output even for single items, while comma-separated syntax ($a = 1,2,3) is the most concise. Use arrays when you need indexed access, simple iteration, or property-based bulk operations. For dynamic resizing, consider System.Collections.Generic.List[ or ArrayList.
Tested on Windows PowerShell 5.1 and PowerShell 7.4.
Advanced implementation & parameters
ForEach() method overloads
The ForEach() method on arrays (introduced in PowerShell 4.0) supports four overloads. Unlike the ForEach-Object cmdlet, it runs in the caller’s scope and returns a new array.
# Scriptblock expression — returns new array
(1..5).ForEach({$_ * 2})
# Scriptblock with arguments — used for parameterized filters
$multiplier = 3
(1..5).ForEach({$_ * $args[0]}, $multiplier)
# Type conversion — casts each element to target type
("1","2","3").ForEach([int])
# Property name accessor — returns property values
$files = dir 'C:Temp'
$files.ForEach('LastAccessTime')
# Property setter — mutates each element's property
$files.ForEach('LastAccessTime', (Get-Date))
# Method name invoker — calls method on each element
$files.ForEach('Delete') # Deletes every file
Where() method modes
The Where() method accepts a second mode parameter: 'Default', 'Until', 'SkipUntil', and 'Split'. The 'Until' mode returns items until the condition is met for the first time.
# Default mode — return all matching items
(1..50).Where({$_ -gt 10})
# Until mode — return items until the condition is TRUE (stop at first match)
(1..50).Where({$_ -gt 10}, 'Until')
# Output: 1,2,3,4,5,6,7,8,9,10
# Split mode — returns two arrays: matching and non-matching
$matching, $nonMatching = (1..10).Where({$_ -le 5}, 'Split')
Array properties in depth
| Property | Type | Description |
|---|---|---|
Count |
[int] |
Number of elements in the array (alias for Length in PS 3.0+) |
Length |
[int] |
Same as Count for one-dimensional arrays |
LongLength |
[long] |
64-bit count for arrays exceeding 2^31 elements (rare in PowerShell) |
Rank |
[int] |
Number of dimensions — 1 for standard PowerShell arrays; jagged arrays have Rank 1 per sub-array |
Access properties on any array directly:
$arr = @('a','b','c')
$arr.Count # 3
$arr.Length # 3
$arr.Rank # 1 — single-dimensional
# Multi-dimensional array (not jagged)
$md = [int[,]]::new(2,3)
$md.Rank # 2
Common errors and anti-patterns
- Using
+=inside loops: each iteration creates a new array, copying all existing elements — O(n^2) performance for large datasets. UseList[or an] ArrayListinstead. - Assuming single-item output is an array: a function returning one
[pscustomobject]yields a scalar;.Countwill be$nullunless wrapped with@(Get-MyObject). - Indexing beyond bounds:
$array[100]on a 10-element array silently returns$null— no exception by default. EnableSet-StrictMode -Version 2to catch this at runtime. - Storing results of
.Where()without calling it:$array.Wherereturns the method definition, not filtered results. Always include the parentheses and condition. - Modifying array inside
ForEach: because arrays are fixed-size, attempting to$array.Remove($item)throwsMethodNotFoundException. UseArrayListor filter-then-reassign. - Treating
@()as a type cast:@()is the array subexpression operator, not a type accelerator. For strongly-typed arrays, use[int[]]$a = 1,2,3.
Error Resolution & Troubleshooting
| Error Code | Root Cause | Remediation Command |
|---|---|---|
| Index was outside the bounds of the array | Index equals or exceeds Count while Set-StrictMode is enabled |
|
| Cannot index into a null array | Variable is $null because single-object output was not wrapped |
|
| MethodNotFoundException: Remove | Attempting to remove element from [System.Array] which has no Remove method |
|
| Collection was of a fixed size | Using ArrayList.Add() on an array cast with [System.Collections.ArrayList] |
|
Why PowerShell arrays behave uniquely
- Fixed-size after creation: arrays cannot be resized;
+=creates a new array internally, which is expensive for large collections. - Single-item unwrapping: a pipeline returning one item yields a scalar, not an array, unless
@()or comma-separated syntax is used. - Custom objects lack surrogate properties: a single
[pscustomobject]returned from a function does not exposeCountorLengthunless wrapped with@()— a known breaking change from version 3.0. - Zero-or-one collection behavior: starting in PowerShell 3.0, a collection of zero or one object has array-like properties, but this does not apply to arbitrary custom objects.
- Heterogeneous typing by default: items can mix types (
@($True, 5, (Get-Date).DateTime)) without explicit casting, which may cause unexpected type mismatches in strict-mode scripts. - Negative indexing:
$array[-1]returns the last element, supported since PowerShell 3.0, reducing the need for$array[$array.Count-1]. - Range operator
..creates arrays, not ranges:$C = 5..8produces an array of four integers, not a lazy enumerable; misuse on large ranges can exhaust memory.
How to work with PowerShell arrays
- Create an array: use
@(), comma separation, or..range operator. For multi-line arrays, list items line-by-line inside@(). - Access elements: use zero-based indexing —
$array[2]retrieves the third element. Out-of-range indices return$null. - Modify elements: assign to an index —
$colors[1] = "brown". Arrays are mutable in place, but you cannot change their length. - Iterate: use the
ForEach()method with a script block, property name, or method name, or theWhere()method for filtering. - Check size: read
$array.Countor$array.Length. Both are aliases in PowerShell 3.0+.
| Action | CLI Command | Key Flag | Description |
|---|---|---|---|
| Create empty array | $data = @() |
N/A | Returns array of zero elements |
| Create with range | $C = 5..8 |
N/A | Produces array 5,6,7,8 |
| Access property on each | $array.ForEach('propertyName') |
-eq, -gt, -le |
Returns array of property values |
| Filter with condition | $array.Where({$_ -gt 10}) |
-gt, -lt, -eq |
Returns matching items |
| Set property on all | $array.ForEach('propertyName', $newValue) |
N/A | Mutates each element’s property |
| Get element count | $array.Count |
N/A | Returns [int] number of items |
Production-grade implementation
Performance patterns
To minimize latency in array-heavy operations within automation scripts, avoid += in loops that exceed 1,000 iterations. Use System.Collections.Generic.List[ for resizable collections and convert to an array only for final output.
# Inefficient — recreates array each iteration
$results = @()
foreach ($item in (1..10000)) {
$results += $item * 2
}
# Efficient — uses List[T] then converts once
$list = [System.Collections.Generic.List[int]]::new()
foreach ($item in (1..10000)) {
$list.Add($item * 2)
}
$array = $list.ToArray()
IAM and execution context
PowerShell arrays themselves have no security context, but scripts that process arrays of files, users, or cloud resources should run under a least-privilege identity. When using ForEach('Delete') on a collection of file paths, ensure the runtime account has only the necessary NTFS or cloud-storage permissions — never use elevated accounts for bulk enumeration unless explicitly required.
Validating array inputs in functions
function Process-Items {
param(
[Parameter(Mandatory)]
[ValidateScript({ $_.Count -gt 0 }, ErrorMessage = 'Array must not be empty')]
[object[]]$Items
)
# Safe iteration with bounds checking
for ($i = 0; $i -lt $Items.Count; $i++) {
$Items[$i].SomeMethod()
}
}
Frequently Asked Questions
What is the difference between @() and [System.Collections.ArrayList] in PowerShell?
Answer: @() creates a fixed-size array; ArrayList is a dynamic collection.
The @() array operator returns a fixed-size array of type System.Object[]. Each += operation creates a new array with all existing elements copied, resulting in O(n²) complexity. The [System.Collections.ArrayList] class provides O(1) average insertion via .Add() but requires explicit init. Use generic [System.Collections.Generic.List[object]] for type safety.
# Array with @()
$arr = @()
$arr += 1 # Inefficient: copies whole array
# ArrayList
$al = [System.Collections.ArrayList]::new()
$al.Add(1) | Out-Null # Efficient O(1) append
When should I use the -as [array] operator in PowerShell?
Answer: Use -as [array] to force a single scalar into a one-element array, ensuring foreach loops work uniformly when input may be a single object.
If you pipe a single object into foreach that expects an array, the loop runs only once. Using -as [array] before the loop guarantees the input is always an array, even if $null (becomes empty array). This is critical when processing command output that sometimes returns one item. Slightly slower than manual wrapping, but ensures safety.
$result = Get-Service -Name Spooler # Single object
$result -as [array] | ForEach-Object { $_ } # Guarantees iteration
How do I fix ‘Cannot index into a null array’ error in PowerShell?
Answer: Initialize the variable with @() before indexing, or use null coalescing: ($var ?? @())[0] ensures $var is never $null when indexed.
Error Cannot index into a null array occurs when $var is $null and you attempt $var[0]. In PowerShell 7+, use the null-coalescing operator ?? to provide a fallback empty array. For older versions, test with if ($null -ne $var) { ... } or assign default array at declaration.
# PowerShell 7+ fix
$result = $data ?? @()
$result[0]
# Windows PowerShell 5.1
if ($null -ne $data) { $data[0] }
Does PowerShell array syntax work identically in Windows PowerShell 5.1 and PowerShell 7?
Answer: Yes, core array semantics (@(), indexing, slicing) are identical across both major versions.
Both versions support @(), @{} for hashtables, comma operator for literal arrays, and .. range operator. PowerShell 7 introduced the null-coalescing operator ?? and ternary ? : which simplify null-safe array handling. Additionally, [pscustomobject] arrays behave identically. For cross-version scripts, avoid ?? and use explicit if checks.
# Works in both
$arr = @(1,2,3)
$arr[0] # 1
$arr[0..1] # 1,2
What is the fastest way to create and populate a large array in PowerShell?
Answer: Use [System.
The += operator on PowerShell arrays creates a new array each time, leading to O(n²) time for n inserts. Instead, use a generic list and call .Add(). For maximum performance, allocate initial capacity via [System.Collections.Generic.List[object]](1000000). After population, convert to array with .ToArray(). This approach yields ~100x speed improvement for large datasets.
# Fast method
$list = [System.Collections.Generic.List[object]]::new(1000000)
for ($i = 0; $i -lt 1000000; $i++) { $list.Add($i) }
$array = $list.ToArray()
# Slow method – NEVER USE
$arraySlow = @()
for ($i = 0; $i -lt 1000000; $i++) { $arraySlow += $i }

Command Line Expert & Software Engineer
Welcome! I’m Thomas Heinrich, a software engineer and system administrator with a deep passion for the Command Line Interface (CLI). With years of experience navigating the terminal, building backend architectures, and automating server deployments, I created this space to share practical, real-world terminal knowledge.
Whether you are a beginner taking your first steps in a Linux environment or a seasoned DevOps engineer looking to optimize your deployment scripts, you will find actionable solutions here. My goal is to help you ditch the mouse, speed up your workflow, and harness the full power of the command line.