PowerShell Arrays: Complete Guide to Creating and Managing Arrays [2026]
PowerShell arrays are fundamental data structures that provide a structured way to store and manipulate collections of items. Whether you’re managing server lists, processing log files, or automating AD tasks, understanding arrays is essential for efficient PowerShell scripting.
In this comprehensive guide, you’ll learn everything about PowerShell arrays—from basic creation to advanced manipulation techniques. We’ll cover string arrays, nested arrays, array properties, methods, and real-world use cases with practical examples.
Table of Contents
- What is a PowerShell Array?
- Why Use Arrays in PowerShell?
- Creating Arrays
- Accessing Array Elements
- Adding Elements
- Removing Elements
- Array Properties
- Array Methods
- Looping Through Arrays
- String Arrays
- Nested Arrays
- Array vs ArrayList vs Generic List
- Real-World Use Cases
- Troubleshooting
- Common Mistakes
- Best Practices
- Advanced Tips
- FAQs
What is a PowerShell Array?
A PowerShell array is an ordered collection of objects stored in a single variable. Arrays can hold multiple values of the same type (homogeneous) or different types (heterogeneous), making them incredibly flexible for data management.
Key characteristics of PowerShell arrays:
- Zero-indexed: First element is at position
[0] - Fixed-size by default: Once created, the size is fixed (though you can create new arrays)
- Type-flexible: Can store strings, integers, objects, or mixed types
- Reference type: Arrays are objects, not primitive types
- Immutable size: Adding/removing elements creates a new array
# PowerShell array example
$servers = @("DC01", "DC02", "FS01", "SQL01")
Write-Host "Server count: $($servers.Count)"
Write-Host "First server: $($servers[0])"
Output:
Server count: 4
First server: DC01
Why Use Arrays in PowerShell?
Arrays are essential for PowerShell automation and scripting. Here’s why:
1. Manage Multiple Items Efficiently Instead of creating separate variables for each server, user, or file, store them in a single array:
# Without arrays (inefficient)
$server1 = "DC01"
$server2 = "DC02"
$server3 = "DC03"
# With arrays (efficient)
$servers = @("DC01", "DC02", "DC03")
2. Enable Batch Processing Process multiple items in loops for automation:
# Check disk space on multiple servers
$servers = @("DC01", "DC02", "FS01")
foreach ($server in $servers) {
Get-WmiObject Win32_LogicalDisk -ComputerName $server -Filter "DeviceID='C:'" |
Select-Object @{Name="Server";Expression={$server}}, FreeSpace, Size
}
3. Store Command Results Capture output from cmdlets for further processing:
# Get all stopped services
$stoppedServices = Get-Service | Where-Object {$_.Status -eq 'Stopped'}
Write-Host "Found $($stoppedServices.Count) stopped services"
4. Pass Data Between Functions Arrays make it easy to pass multiple values to functions:
function Test-ServerConnection {
param([string[]]$ServerList)
foreach ($server in $ServerList) {
Test-Connection -ComputerName $server -Count 1 -Quiet
}
}
$servers = @("DC01", "DC02", "FS01")
Test-ServerConnection -ServerList $servers
5. Work with CSV and JSON Data Import data from files as arrays for processing:
# Import CSV as array of objects
$users = Import-Csv -Path "C:\Users\users.csv"
foreach ($user in $users) {
New-ADUser -Name $user.Name -SamAccountName $user.SamAccountName
}
For more advanced PowerShell concepts, see our Complete PowerShell Guide.
How to Create Array in PowerShell {#creating-arrays}
PowerShell offers multiple ways to create arrays. Here are all the methods you need to know:
Method 1: Array Subexpression Operator @()
The @() operator explicitly creates an array, even with zero or one element:
# Create an empty array
$empty = @()
# Create an array with one element
$single = @("Apple")
# Create an array with multiple elements
$fruits = @("Apple", "Banana", "Orange", "Grape")
# Verify it's an array
$fruits.GetType().Name # Output: Object[]
Output:
Object[]
Method 2: Comma-Separated Values
PowerShell automatically creates an array when you use commas:
# Simple array creation
$numbers = 1, 2, 3, 4, 5
# Mixed type array
$mixed = "Server01", 42, $true, (Get-Date)
# Check the count
$numbers.Count # Output: 5
Output:
5
Method 3: Range Operator (..)
Create sequential number arrays quickly:
# Create array of numbers 1-10
$range = 1..10
# Create array from 0 to 100
$hundred = 0..100
# Reverse range
$reverse = 10..1
# Display range
$range
Output:
1
2
3
4
5
6
7
8
9
10
Method 4: From Cmdlet Output
Capture cmdlet results directly into arrays:
# Get all .txt files in a directory
$textFiles = Get-ChildItem -Path "C:\Logs" -Filter "*.txt"
# Get all running processes
$runningProcesses = Get-Process
# Get AD users from specific OU
$users = Get-ADUser -Filter * -SearchBase "OU=Users,DC=contoso,DC=com"
# Display count
Write-Host "Found $($textFiles.Count) text files"
Method 5: Strongly Typed Arrays
Create arrays that only accept specific types:
# String array only
[string[]]$names = "John", "Jane", "Bob"
# Integer array only
[int[]]$ages = 25, 30, 35
# Try to add wrong type (this will error)
# [int[]]$numbers = 1, 2, "three" # Error: Cannot convert "three" to int
# DateTime array
[datetime[]]$dates = (Get-Date), (Get-Date).AddDays(1)
Method 6: ArrayList (Dynamic Size)
For frequently modified arrays, use ArrayList:
# Create ArrayList
$list = [System.Collections.ArrayList]@()
# Add items (more efficient than array +=)
$list.Add("Item1") | Out-Null
$list.Add("Item2") | Out-Null
$list.Add("Item3") | Out-Null
# Display
$list
Output:
Item1
Item2
Item3
💡 Pro Tip: Use @() when you need to ensure the result is always an array, even if the command returns zero or one item. This prevents errors when using array methods.
How to Access Array Elements {#accessing-array-elements}
PowerShell provides flexible indexing to access array elements. Arrays are zero-indexed, meaning the first element is at position [0].
Basic Index Access
$fruits = @("Apple", "Banana", "Orange", "Grape", "Mango")
# Access first element
$fruits[0] # Output: Apple
# Access third element
$fruits[2] # Output: Orange
# Access last element
$fruits[4] # Output: Mango
Output:
Apple
Orange
Mango
Negative Indexing
Access elements from the end of the array using negative indices:
$fruits = @("Apple", "Banana", "Orange", "Grape", "Mango")
# Last element
$fruits[-1] # Output: Mango
# Second to last
$fruits[-2] # Output: Grape
# Third from end
$fruits[-3] # Output: Orange
Output:
Mango
Grape
Orange
Range Access (Slicing)
Extract multiple elements using ranges:
$numbers = 1..10
# Get first three elements (index 0, 1, 2)
$numbers[0..2] # Output: 1, 2, 3
# Get elements 5-8
$numbers[4..7] # Output: 5, 6, 7, 8
# Get last three elements
$numbers[-3..-1] # Output: 8, 9, 10
Output:
1
2
3
Multiple Index Access
Access non-consecutive elements:
$servers = @("DC01", "DC02", "FS01", "SQL01", "WEB01", "APP01")
# Get first, third, and fifth elements
$servers[0,2,4] # Output: DC01, FS01, WEB01
# Get elements using variable indices
$indices = 1, 3, 5
$servers[$indices] # Output: DC02, SQL01, APP01
Output:
DC01
FS01
WEB01
Accessing Nested Array Elements
For multi-dimensional arrays:
# Create nested array
$matrix = @(
@(1, 2, 3),
@(4, 5, 6),
@(7, 8, 9)
)
# Access row 2, column 3
$matrix[1][2] # Output: 6
# Access first row
$matrix[0] # Output: 1, 2, 3
Output:
6
Safe Access (Avoiding Index Errors)
Prevent errors when accessing potentially non-existent indices:
$fruits = @("Apple", "Banana", "Orange")
# This will cause an error if index doesn't exist
# $fruits[10] # Error: Index was out of range
# Safe access with bounds checking
if ($fruits.Count -gt 10) {
$fruits[10]
} else {
Write-Host "Index out of bounds"
}
# Using try-catch
try {
$value = $fruits[10]
} catch {
Write-Host "Cannot access index 10"
}
⚠️ Warning: Accessing an index beyond the array size will return $null or throw an error depending on the context. Always check $array.Count before accessing by index.
How to Add Elements to Array {#adding-elements}
Adding elements to PowerShell arrays requires understanding that standard arrays are fixed-size. The += operator creates a new array with the additional element.
Method 1: Using += Operator
The simplest way to add elements:
$fruits = @("Apple", "Banana")
# Add single element
$fruits += "Orange"
# Add multiple elements
$fruits += "Grape", "Mango"
# Display result
$fruits
Output:
Apple
Banana
Orange
Grape
Mango
Method 2: Array Concatenation
Combine two arrays:
$array1 = @("Item1", "Item2")
$array2 = @("Item3", "Item4")
# Concatenate arrays
$combined = $array1 + $array2
# Display result
$combined
Output:
Item1
Item2
Item3
Item4
Method 3: Using ArrayList (Better Performance)
For frequent additions, use ArrayList instead:
# Convert array to ArrayList
$list = [System.Collections.ArrayList]@("Apple", "Banana")
# Add elements (much faster than +=)
$list.Add("Orange") | Out-Null
$list.Add("Grape") | Out-Null
# Or add multiple at once
$list.AddRange(@("Mango", "Peach"))
# Display
$list
Output:
Apple
Banana
Orange
Grape
Mango
Peach
Method 4: Using Generic List (Best Performance)
For maximum performance with type safety:
# Create generic list of strings
$list = [System.Collections.Generic.List[string]]::new()
# Add elements
$list.Add("Apple")
$list.Add("Banana")
$list.Add("Orange")
# Add multiple
$list.AddRange(@("Grape", "Mango"))
# Display
$list
Method 5: Insert at Specific Position
Insert elements at specific index using ArrayList:
$list = [System.Collections.ArrayList]@("First", "Third", "Fourth")
# Insert at index 1
$list.Insert(1, "Second")
# Display
$list
Output:
First
Second
Third
Fourth
Performance Comparison
# Measure performance of += operator (slow)
Measure-Command {
$array = @()
for ($i = 0; $i -lt 1000; $i++) {
$array += $i
}
}
# Time: ~450ms
# Measure ArrayList performance (fast)
Measure-Command {
$list = [System.Collections.ArrayList]@()
for ($i = 0; $i -lt 1000; $i++) {
$list.Add($i) | Out-Null
}
}
# Time: ~15ms
💡 Pro Tip: If you need to add elements frequently (more than 5-10 times), use ArrayList or List<T> instead of the += operator. The performance difference is significant for large datasets.
⚠️ Warning: Each += operation creates a new array and copies all elements, making it O(n²) complexity for multiple additions. For loops with many additions, this becomes very slow.
How to Remove Elements from Array {#removing-elements}
Since PowerShell arrays are fixed-size, removing elements requires creating a new array without the unwanted elements.
Method 1: Using Where-Object
Filter out specific values:
$fruits = @("Apple", "Banana", "Orange", "Banana", "Grape")
# Remove all "Banana" elements
$fruits = $fruits | Where-Object { $_ -ne "Banana" }
# Display result
$fruits
Output:
Apple
Orange
Grape
Method 2: Remove by Index
Remove element at specific position:
$numbers = 1, 2, 3, 4, 5
# Remove element at index 2 (value 3)
$numbers = $numbers[0..1] + $numbers[3..4]
# Or using Where-Object with index
$numbers = $numbers | Where-Object { $numbers.IndexOf($_) -ne 2 }
# Display
$numbers
Output:
1
2
4
5
Method 3: Remove Using ArrayList
More efficient for multiple removals:
# Create ArrayList
$list = [System.Collections.ArrayList]@("Apple", "Banana", "Orange", "Grape")
# Remove specific item
$list.Remove("Banana")
# Remove at specific index
$list.RemoveAt(0) # Removes "Apple"
# Remove range
$list.RemoveRange(0, 2) # Removes first 2 elements
# Display
$list
Method 4: Remove Duplicates
Keep only unique values:
$numbers = 1, 2, 2, 3, 3, 3, 4, 5, 5
# Remove duplicates using Select-Object
$unique = $numbers | Select-Object -Unique
# Or using Get-Unique (requires sorted array)
$unique = $numbers | Sort-Object | Get-Unique
# Display
$unique
Output:
1
2
3
4
5
Method 5: Remove Null or Empty Values
Clean up arrays with empty elements:
$mixed = @("Apple", "", "Banana", $null, "Orange", " ", "Grape")
# Remove null and empty strings
$cleaned = $mixed | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
# Display
$cleaned
Output:
Apple
Banana
Orange
Grape
Method 6: Remove Elements Matching Pattern
Use regex or wildcard patterns:
$files = @("report.txt", "data.csv", "summary.txt", "output.log", "notes.txt")
# Remove all .txt files
$filtered = $files | Where-Object { $_ -notlike "*.txt" }
# Or using regex
$filtered = $files | Where-Object { $_ -notmatch '\.txt$' }
# Display
$filtered
Output:
data.csv
output.log
Method 7: Bulk Remove Using -notin
Remove multiple values at once:
$servers = @("DC01", "DC02", "FS01", "SQL01", "WEB01")
$decommissioned = @("FS01", "SQL01")
# Remove decommissioned servers
$active = $servers | Where-Object { $_ -notin $decommissioned }
# Display
$active
Output:
DC01
DC02
WEB01
💡 Pro Tip: For performance-critical code with frequent removals, use List<T>.RemoveAll() method instead of filtering arrays repeatedly.
Array Properties and Length {#array-properties}
PowerShell arrays have several useful properties for getting information about the array.
Count vs Length Property
Both properties return the number of elements:
$fruits = @("Apple", "Banana", "Orange", "Grape", "Mango")
# Using Count property
$fruits.Count # Output: 5
# Using Length property
$fruits.Length # Output: 5
# Both are equivalent for arrays
$fruits.Count -eq $fruits.Length # Output: True
Output:
5
5
True
Checking for Empty Arrays
$empty = @()
$notEmpty = @("Item")
# Check if array is empty
if ($empty.Count -eq 0) {
Write-Host "Array is empty"
}
# Or use Length
if ($notEmpty.Length -gt 0) {
Write-Host "Array has $($notEmpty.Length) elements"
}
Output:
Array is empty
Array has 1 elements
Other Useful Properties
$numbers = 1, 2, 3, 4, 5
# Get array rank (dimensions)
$numbers.Rank # Output: 1 (one-dimensional)
# Check if array is fixed size
$numbers.IsFixedSize # Output: True
# Check if array is read-only
$numbers.IsReadOnly # Output: False
# Get array type
$numbers.GetType().Name # Output: Object[]
LongLength for Large Arrays
For arrays with more than 2 billion elements (theoretical):
$largeArray = 1..1000000
# Use LongLength for very large arrays
$largeArray.LongLength # Returns as Int64 (long)
Bounds Information
Get the upper and lower bounds:
$fruits = @("Apple", "Banana", "Orange")
# Get lower bound (always 0 for PowerShell arrays)
$fruits.GetLowerBound(0) # Output: 0
# Get upper bound (last index)
$fruits.GetUpperBound(0) # Output: 2
# Calculate length from bounds
$length = $fruits.GetUpperBound(0) - $fruits.GetLowerBound(0) + 1
Write-Host "Array length: $length"
Output:
0
2
Array length: 3
💡 Pro Tip: Use .Count instead of .Length for consistency across all PowerShell collections (some collection types only have .Count).
Looping Through Arrays {#looping-through-arrays}
PowerShell provides multiple ways to iterate through array elements. Each method has specific use cases.
Method 1: foreach Loop (Fastest)
The most common and fastest method:
$servers = @("DC01", "DC02", "FS01", "SQL01")
foreach ($server in $servers) {
Write-Host "Processing: $server"
# Test connection
Test-Connection -ComputerName $server -Count 1 -Quiet
}
Output:
Processing: DC01
Processing: DC02
Processing: FS01
Processing: SQL01
Method 2: ForEach-Object Cmdlet (Pipeline)
Use when working with pipeline data:
$numbers = 1..5
# Using ForEach-Object
$numbers | ForEach-Object {
$_ * 2
}
# With named parameter
$numbers | ForEach-Object -Process { $_ * 2 }
Output:
2
4
6
8
10
Method 3: for Loop with Index
When you need the index position:
$fruits = @("Apple", "Banana", "Orange", "Grape")
for ($i = 0; $i -lt $fruits.Count; $i++) {
Write-Host "[$i] = $($fruits[$i])"
}
Output:
[0] = Apple
[1] = Banana
[2] = Orange
[3] = Grape
Method 4: while Loop
Less common but useful for conditional iteration:
$numbers = 1..5
$index = 0
while ($index -lt $numbers.Count) {
Write-Host "Number: $($numbers[$index])"
$index++
}
Method 5: .ForEach() Method
PowerShell 4.0+ intrinsic method:
$numbers = 1..5
# Execute script block for each element
$numbers.ForEach({ $_ * 2 })
# With multiple statements
$servers = @("DC01", "DC02", "FS01")
$servers.ForEach({
Write-Host "Server: $_"
Test-Connection -ComputerName $_ -Count 1 -Quiet
})
Method 6: Reverse Iteration
Loop through array backwards:
$fruits = @("Apple", "Banana", "Orange", "Grape")
# Method 1: Reverse for loop
for ($i = $fruits.Count - 1; $i -ge 0; $i--) {
Write-Host $fruits[$i]
}
# Method 2: Reverse the array first
$fruits[($fruits.Count-1)..0] | ForEach-Object {
Write-Host $_
}
Output:
Grape
Orange
Banana
Apple
Method 7: Nested Loops (Multi-dimensional Arrays)
Iterate through nested arrays:
$matrix = @(
@(1, 2, 3),
@(4, 5, 6),
@(7, 8, 9)
)
foreach ($row in $matrix) {
foreach ($value in $row) {
Write-Host $value -NoNewline
Write-Host " " -NoNewline
}
Write-Host "" # New line
}
Output:
1 2 3
4 5 6
7 8 9
Performance Comparison
$largeArray = 1..10000
# foreach loop (fastest)
Measure-Command {
foreach ($item in $largeArray) { $item * 2 }
}
# ~15ms
# ForEach-Object (slower due to pipeline overhead)
Measure-Command {
$largeArray | ForEach-Object { $_ * 2 }
}
# ~180ms
# .ForEach() method (fast)
Measure-Command {
$largeArray.ForEach({ $_ * 2 })
}
# ~25ms
💡 Pro Tip: Use foreach loop for maximum performance. Use ForEach-Object when working with pipelines or when you need advanced features like -Parallel in PowerShell 7+.
Array Methods {#array-methods}
PowerShell arrays inherit methods from the .NET System.Array class, providing powerful manipulation capabilities.
Sort Arrays
$numbers = 5, 2, 8, 1, 9, 3
# Sort ascending
[Array]::Sort($numbers)
$numbers # Output: 1, 2, 3, 5, 8, 9
# Sort descending
[Array]::Reverse($numbers)
$numbers # Output: 9, 8, 5, 3, 2, 1
Reverse Arrays
$fruits = @("Apple", "Banana", "Orange")
# Reverse the array
[Array]::Reverse($fruits)
$fruits # Output: Orange, Banana, Apple
Find Elements
$servers = @("DC01", "DC02", "FS01", "SQL01", "WEB01")
# Find index of element
$index = [Array]::IndexOf($servers, "SQL01")
Write-Host "SQL01 is at index: $index" # Output: 3
# Find last index
$lastIndex = [Array]::LastIndexOf($servers, "DC01")
# Check if element exists
$exists = [Array]::Exists($servers, [Predicate[string]]{ $args[0] -eq "FS01" })
Write-Host "FS01 exists: $exists" # Output: True
Clear and Copy
$original = 1, 2, 3, 4, 5
$destination = New-Object int[] 5
# Copy array
[Array]::Copy($original, $destination, 5)
$destination # Output: 1, 2, 3, 4, 5
# Clear array elements
[Array]::Clear($original, 0, $original.Length)
$original # Output: 0, 0, 0, 0, 0 (for int arrays)
Filter and Find
$numbers = 1..20
# Find all even numbers
$even = [Array]::FindAll($numbers, [Predicate[int]]{ $args[0] % 2 -eq 0 })
$even # Output: 2, 4, 6, 8, 10, 12, 14, 16, 18, 20
# Find first element matching condition
$firstEven = [Array]::Find($numbers, [Predicate[int]]{ $args[0] % 2 -eq 0 })
$firstEven # Output: 2
Convert and Join
$array = @("PowerShell", "is", "awesome")
# Join array elements into string
$joined = $array -join " "
Write-Host $joined # Output: PowerShell is awesome
# Join with custom separator
$csv = $array -join ", "
Write-Host $csv # Output: PowerShell, is, awesome
# Convert array to different type
$strings = @("1", "2", "3")
$integers = [int[]]$strings
$integers # Output: 1, 2, 3 (as integers)
String Arrays {#string-arrays}
String arrays are one of the most common array types in PowerShell scripting.
Creating String Arrays
# Explicit string array
[string[]]$names = "John", "Jane", "Bob", "Alice"
# String array from split operation
$csv = "Server1,Server2,Server3,Server4"
$servers = $csv -split ","
# String array from file
$lines = Get-Content -Path "C:\servers.txt"
String Array Operations
$servers = @("DC01", "DC02", "FS01", "SQL01")
# Filter strings containing pattern
$filtered = $servers -like "DC*"
$filtered # Output: DC01, DC02
# Case-insensitive matching
$matches = $servers -match "dc01"
$matches # Output: DC01
# Replace in all strings
$updated = $servers -replace "01", "02"
$updated # Output: DC02, DC02, FS02, SQL02
String Array Comparison
$array1 = @("Apple", "Banana", "Orange")
$array2 = @("Banana", "Grape", "Mango")
# Find common elements
$common = $array1 | Where-Object { $array2 -contains $_ }
$common # Output: Banana
# Find differences
$unique1 = $array1 | Where-Object { $array2 -notcontains $_ }
$unique1 # Output: Apple, Orange
Converting String Arrays
# Convert to uppercase
$names = @("john", "jane", "bob")
$upper = $names.ForEach({ $_.ToUpper() })
$upper # Output: JOHN, JANE, BOB
# Convert to lowercase
$lower = $names.ForEach({ $_.ToLower() })
# Trim whitespace
$messy = @(" Apple ", " Banana", "Orange ")
$clean = $messy.ForEach({ $_.Trim() })
$clean # Output: Apple, Banana, Orange
For more string manipulation techniques, see our PowerShell Strings guide.
Nested Arrays (Multi-dimensional) {#nested-arrays}
Nested arrays (arrays of arrays) allow you to create matrix-like structures.
Creating Nested Arrays
# 2D array (matrix)
$matrix = @(
@(1, 2, 3),
@(4, 5, 6),
@(7, 8, 9)
)
# Access elements
$matrix[0][0] # Output: 1
$matrix[1][2] # Output: 6
$matrix[2][1] # Output: 8
# Get entire row
$matrix[0] # Output: 1, 2, 3
Jagged Arrays
Arrays with varying row lengths:
$jagged = @(
@(1, 2),
@(3, 4, 5),
@(6, 7, 8, 9)
)
# Access elements
$jagged[1][2] # Output: 5
$jagged[2].Count # Output: 4
Creating Multi-dimensional Arrays
# Create 3x3 multi-dimensional array
$multiArray = New-Object 'int[,]' 3, 3
# Populate values
for ($i = 0; $i -lt 3; $i++) {
for ($j = 0; $j -lt 3; $j++) {
$multiArray[$i, $j] = ($i * 3) + $j + 1
}
}
# Access elements
$multiArray[1, 1] # Output: 5
Practical Example: Server Inventory
# Server inventory as nested array
$inventory = @(
@{Name="DC01"; IP="192.168.1.10"; Role="Domain Controller"},
@{Name="FS01"; IP="192.168.1.20"; Role="File Server"},
@{Name="SQL01"; IP="192.168.1.30"; Role="Database Server"}
)
# Access server details
foreach ($server in $inventory) {
Write-Host "$($server.Name) - $($server.IP) - $($server.Role)"
}
Output:
DC01 - 192.168.1.10 - Domain Controller
FS01 - 192.168.1.20 - File Server
SQL01 - 192.168.1.30 - Database Server
Array vs ArrayList vs Generic List {#array-comparison}
Understanding the differences helps you choose the right collection type.
Comparison Table
| Feature | Array | ArrayList | List |
|---|---|---|---|
| Size | Fixed | Dynamic | Dynamic |
| Performance (Add) | O(n) | O(1)* | O(1)* |
| Type Safety | Optional | No | Yes |
| Syntax | @() | [ArrayList]@() | [List[string]]::new() |
| Memory | Efficient | More overhead | Most efficient |
| Use Case | Static data | Legacy code | Modern scripts |
When to Use Each
Use Array when:
- Size is known and won’t change
- Working with small datasets (<100 items)
- Simple read-only operations
- Interfacing with cmdlets expecting arrays
# Good use of array
$daysOfWeek = @("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
Use ArrayList when:
- Size changes frequently
- Working with legacy code
- Need dynamic collection without type safety
# ArrayList for dynamic collection
$log = [System.Collections.ArrayList]@()
foreach ($file in Get-ChildItem) {
$log.Add($file.Name) | Out-Null
}
Use List
- Need type safety
- Frequent additions/removals
- Modern PowerShell scripts (5.1+)
- Performance is critical
# Generic List for best performance
$servers = [System.Collections.Generic.List[string]]::new()
$servers.Add("DC01")
$servers.Add("DC02")
Performance Benchmark
# Array += (slowest)
$array = @()
Measure-Command {
1..1000 | ForEach-Object { $array += $_ }
}
# ~450ms
# ArrayList (fast)
$list = [ArrayList]@()
Measure-Command {
1..1000 | ForEach-Object { $list.Add($_) | Out-Null }
}
# ~15ms
# Generic List (fastest)
$genericList = [System.Collections.Generic.List[int]]::new()
Measure-Command {
1..1000 | ForEach-Object { $genericList.Add($_) }
}
# ~12ms
Real-World Use Cases {#real-world-use-cases}
Here are practical scenarios where arrays are essential.
Use Case 1: Bulk Server Management
# List of servers to manage
$servers = @("DC01", "DC02", "FS01", "SQL01", "WEB01")
# Check disk space on all servers
foreach ($server in $servers) {
$disk = Get-WmiObject Win32_LogicalDisk -ComputerName $server -Filter "DeviceID='C:'"
$freeGB = [math]::Round($disk.FreeSpace / 1GB, 2)
$totalGB = [math]::Round($disk.Size / 1GB, 2)
$percentFree = [math]::Round(($freeGB / $totalGB) * 100, 2)
Write-Host "$server - Free: ${freeGB}GB / ${totalGB}GB ($percentFree%)"
}
Use Case 2: User Provisioning from CSV
# Import users from CSV
$users = Import-Csv -Path "C:\NewUsers.csv"
# Create AD accounts
foreach ($user in $users) {
try {
New-ADUser -Name $user.Name `
-SamAccountName $user.SamAccountName `
-EmailAddress $user.Email `
-Department $user.Department `
-Enabled $true
Write-Host "Created: $($user.Name)" -ForegroundColor Green
}
catch {
Write-Host "Failed: $($user.Name) - $_" -ForegroundColor Red
}
}
For more on Active Directory management, see our Complete Active Directory Guide.
Use Case 3: Log File Analysis
# Read log file into array
$logLines = Get-Content -Path "C:\Logs\app.log"
# Filter error lines
$errors = $logLines | Where-Object { $_ -match "ERROR" }
# Group by error type
$errorSummary = $errors | ForEach-Object {
if ($_ -match "ERROR:\s*(.+)") {
$matches[1]
}
} | Group-Object | Sort-Object Count -Descending
# Display summary
$errorSummary | Select-Object Count, Name
Use Case 4: File Batch Operations
# Get all .txt files
$textFiles = Get-ChildItem -Path "C:\Documents" -Filter "*.txt"
# Rename with date prefix
$textFiles | ForEach-Object {
$newName = "{0:yyyy-MM-dd}_{1}" -f (Get-Date), $_.Name
Rename-Item -Path $_.FullName -NewName $newName
Write-Host "Renamed: $($_.Name) -> $newName"
}
Use Case 5: Email Distribution List
# Email recipients array
$recipients = @(
"admin@contoso.com",
"manager@contoso.com",
"support@contoso.com"
)
# Send report to all recipients
$reportPath = "C:\Reports\DailyReport.pdf"
foreach ($recipient in $recipients) {
Send-MailMessage -To $recipient `
-From "reports@contoso.com" `
-Subject "Daily Report - $(Get-Date -Format 'yyyy-MM-dd')" `
-Body "Please find attached today's report." `
-Attachments $reportPath `
-SmtpServer "smtp.contoso.com"
Write-Host "Sent report to $recipient"
}
Troubleshooting Common Array Issues {#troubleshooting}
Issue 1: “Index was outside the bounds of the array”
Cause: Accessing an index that doesn’t exist
$array = @("One", "Two", "Three")
$array[5] # Error!
Solution: Check array bounds before accessing
$index = 5
if ($index -lt $array.Count) {
$array[$index]
} else {
Write-Host "Index $index is out of bounds (array size: $($array.Count))"
}
Issue 2: += Operator Performance
Cause: Each += operation creates a new array
Solution: Use ArrayList or List
# Slow
$array = @()
1..1000 | ForEach-Object { $array += $_ } # ~450ms
# Fast
$list = [System.Collections.Generic.List[int]]::new()
1..1000 | ForEach-Object { $list.Add($_) } # ~12ms
Issue 3: Null Array Elements
Cause: Uninitialized array elements or failed operations
$array = @(1, 2, $null, 4, 5)
# This might cause issues
$array | ForEach-Object { $_ * 2 } # Error on $null
Solution: Filter null values
$array | Where-Object { $null -ne $_ } | ForEach-Object { $_ * 2 }
Issue 4: Array vs Single Object
Cause: Cmdlets may return single object instead of array
$files = Get-ChildItem -Path "C:\SingleFile"
$files.Count # Returns $null if only one file!
Solution: Force array with @()
$files = @(Get-ChildItem -Path "C:\SingleFile")
$files.Count # Always returns valid count
Issue 5: Modifying Array During Iteration
Cause: Changing array size while looping
# This will fail
$array = 1, 2, 3, 4, 5
foreach ($item in $array) {
$array += 100 # Don't modify during iteration!
}
Solution: Create new array or use copy
$original = 1, 2, 3, 4, 5
$modified = $original.Clone()
foreach ($item in $original) {
$modified += 100
}
Common Mistakes to Avoid {#common-mistakes}
Mistake 1: Forgetting Arrays Are Zero-Indexed
# Wrong: Assuming first element is [1]
$servers = @("DC01", "DC02", "FS01")
$first = $servers[1] # This is DC02, not DC01!
# Correct: First element is [0]
$first = $servers[0] # DC01
Mistake 2: Using += in Loops
# Inefficient
$results = @()
foreach ($i in 1..1000) {
$results += $i # Creates 1000 new arrays!
}
# Efficient
$results = [System.Collections.Generic.List[int]]::new()
foreach ($i in 1..1000) {
$results.Add($i) # O(1) operation
}
Mistake 3: Not Checking for Empty Arrays
# Dangerous
$files = Get-ChildItem -Path "C:\NonExistent"
$files[0] # Error if path doesn't exist
# Safe
$files = @(Get-ChildItem -Path "C:\MayNotExist" -ErrorAction SilentlyContinue)
if ($files.Count -gt 0) {
$files[0]
}
Mistake 4: Assuming Type Consistency
# Mixed types can cause issues
$mixed = @(1, "two", $true, 4.5)
$sum = $mixed | ForEach-Object { $_ + 10 } # Fails on "two"
# Better: Use strongly typed arrays
[int[]]$numbers = 1, 2, 3, 4, 5
$sum = $numbers | ForEach-Object { $_ + 10 } # Works correctly
Mistake 5: Comparing Arrays with -eq
$array1 = @(1, 2, 3)
$array2 = @(1, 2, 3)
# Wrong: This doesn't work as expected
$array1 -eq $array2 # Returns elements, not $true/$false
# Correct: Compare as strings or use Compare-Object
($array1 -join ",") -eq ($array2 -join ",") # True
# Or use Compare-Object
$diff = Compare-Object $array1 $array2
$isEqual = $diff.Count -eq 0 # True if equal
Best Practices {#best-practices}
✅ Use Strongly Typed Arrays
# Good: Type safety prevents errors
[string[]]$servers = "DC01", "DC02", "FS01"
[int[]]$ports = 80, 443, 3389
✅ Initialize Arrays Properly
# Good: Explicit empty array
$results = @()
# Better: Use List<T> for dynamic collections
$results = [System.Collections.Generic.List[object]]::new()
✅ Check Bounds Before Access
# Good: Safe array access
if ($index -ge 0 -and $index -lt $array.Count) {
$value = $array[$index]
}
✅ Use Appropriate Collection Type
# For static data
$daysOfWeek = @("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
# For dynamic data with frequent changes
$log = [System.Collections.Generic.List[string]]::new()
✅ Clone Arrays When Needed
# Good: Create independent copy
$original = 1, 2, 3, 4, 5
$copy = $original.Clone()
$copy[0] = 999 # Doesn't affect $original
✅ Use -contains for Membership Tests
# Efficient membership test
$servers = @("DC01", "DC02", "FS01")
if ($servers -contains "DC01") {
Write-Host "DC01 found"
}
✅ Document Array Purpose
# Good: Clear variable names and comments
# List of production domain controllers
$productionDCs = @("DC01", "DC02", "DC03")
# Email recipients for critical alerts
$criticalAlertRecipients = @("admin@contoso.com", "manager@contoso.com")
Advanced Tips and Tricks {#advanced-tips}
Tip 1: Array Splatting
Pass array elements as individual parameters:
# Array splatting
$copyParams = @{
Path = "C:\Source\file.txt"
Destination = "C:\Dest\file.txt"
Force = $true
}
Copy-Item @copyParams
Tip 2: Parallel Processing (PowerShell 7+)
# Process array elements in parallel
$servers = @("DC01", "DC02", "FS01", "SQL01", "WEB01")
$results = $servers | ForEach-Object -Parallel {
Test-Connection -ComputerName $_ -Count 1 -Quiet
} -ThrottleLimit 5
Tip 3: Array Destructuring
# Destructure array into variables
$data = @("John", "Doe", 30, "Developer")
$firstName, $lastName, $age, $role = $data
Write-Host "$firstName $lastName is a $age year old $role"
Tip 4: Using -split and -join Effectively
# Split string into array
$path = "C:\Users\Admin\Documents\file.txt"
$parts = $path -split "\\"
$filename = $parts[-1] # file.txt
# Join array into string
$servers = @("DC01", "DC02", "FS01")
$serverList = $servers -join ", " # "DC01, DC02, FS01"
Tip 5: Array Filtering with .Where() Method
# PowerShell 4.0+ .Where() method (faster than Where-Object)
$numbers = 1..1000
# Filter even numbers
$even = $numbers.Where({ $_ % 2 -eq 0 })
# With options: 'First' to get first N matches
$firstFive = $numbers.Where({ $_ % 2 -eq 0 }, 'First', 5)
Tip 6: Creating Lookup Hashtables from Arrays
# Convert array to hashtable for O(1) lookups
$servers = @("DC01", "DC02", "FS01", "SQL01")
# Create hashtable
$serverLookup = @{}
$servers | ForEach-Object { $serverLookup[$_] = $true }
# Fast lookup
if ($serverLookup["DC01"]) {
Write-Host "DC01 exists"
}
Tip 7: Array Reduction/Aggregation
# Sum array using Measure-Object
$numbers = 1..100
$sum = ($numbers | Measure-Object -Sum).Sum
Write-Host "Sum: $sum" # 5050
# Custom aggregation
$total = $numbers | ForEach-Object -Begin { $sum = 0 } -Process { $sum += $_ } -End { $sum }
Frequently Asked Questions {#faqs}
Q: How do I check if a variable is an array?
A: Use the -is operator to check the type:
$var = @(1, 2, 3)
if ($var -is [array]) {
Write-Host "It's an array with $($var.Count) elements"
}
# Or check specific array type
if ($var -is [int[]]) {
Write-Host "It's an integer array"
}
Q: What’s the difference between Count and Length?
A: For PowerShell arrays, Count and Length are equivalent. Both return the number of elements. However, .Count is more universally supported across different collection types, so it’s recommended.
$array = @(1, 2, 3, 4, 5)
$array.Count # 5
$array.Length # 5
Q: How do I create an array with a specific size?
A: Use the New-Object cmdlet with array type and size:
# Create integer array with 10 elements (initialized to 0)
$array = New-Object int[] 10
# Create string array with 5 elements (initialized to $null)
$strings = New-Object string[] 5
Q: Can I have arrays of different types mixed together?
A: Yes, PowerShell arrays can be heterogeneous (mixed types):
$mixed = @(
"String",
42,
$true,
(Get-Date),
@{Name="John"}
)
$mixed.GetType().Name # Object[]
Q: How do I convert an array to a string?
A: Use the -join operator or [string]::Join():
$array = @("Apple", "Banana", "Orange")
# Join with space
$string = $array -join " "
# Join with comma
$csv = $array -join ", "
# Using .NET method
$string = [string]::Join(", ", $array)
Q: How do I find the largest/smallest value in an array?
A: Use Measure-Object cmdlet:
$numbers = 15, 42, 8, 23, 16, 4, 31
# Get min and max
$stats = $numbers | Measure-Object -Minimum -Maximum
Write-Host "Min: $($stats.Minimum), Max: $($stats.Maximum)"
# Or use [Linq]
[Linq.Enumerable]::Max($numbers) # 42
[Linq.Enumerable]::Min($numbers) # 4
Q: How do I remove duplicate values from an array?
A: Use Select-Object -Unique or Get-Unique:
$array = 1, 2, 2, 3, 3, 3, 4, 5, 5
# Method 1: Select-Object (doesn't require sorting)
$unique = $array | Select-Object -Unique
# Method 2: Get-Unique (requires sorted array)
$unique = $array | Sort-Object | Get-Unique
# Method 3: Use hashtable
$unique = $array | Sort-Object -Unique
Q: Can I use negative indices to access array elements from the end?
A: Yes! Negative indices count from the end of the array:
$array = @("First", "Second", "Third", "Fourth", "Fifth")
$array[-1] # Fifth (last element)
$array[-2] # Fourth (second to last)
$array[-3] # Third (third from end)
Q: How do I check if an array contains a specific value?
A: Use the -contains operator:
$servers = @("DC01", "DC02", "FS01", "SQL01")
if ($servers -contains "DC01") {
Write-Host "DC01 is in the list"
}
# Case-insensitive
if ($servers -icontains "dc01") {
Write-Host "Found (case-insensitive)"
}
Q: What happens when I assign an array to another variable?
A: You create a reference, not a copy. Both variables point to the same array:
$array1 = @(1, 2, 3)
$array2 = $array1 # Reference, not copy
$array2[0] = 999
$array1[0] # Also 999!
# To create a copy, use Clone()
$array3 = $array1.Clone()
$array3[0] = 100
$array1[0] # Still 999
Q: How do I concatenate multiple arrays?
A: Use the + operator:
$array1 = @(1, 2, 3)
$array2 = @(4, 5, 6)
$array3 = @(7, 8, 9)
# Concatenate
$combined = $array1 + $array2 + $array3
$combined # 1, 2, 3, 4, 5, 6, 7, 8, 9
Q: Can I sort an array in descending order?
A: Yes, use Sort-Object -Descending:
$numbers = 5, 2, 8, 1, 9, 3
# Sort ascending
$ascending = $numbers | Sort-Object
$ascending # 1, 2, 3, 5, 8, 9
# Sort descending
$descending = $numbers | Sort-Object -Descending
$descending # 9, 8, 5, 3, 2, 1
Q: How do I flatten a nested array?
A: Use recursion or the -join and -split approach:
$nested = @(
@(1, 2),
@(3, @(4, 5)),
@(6, 7, @(8, 9))
)
# Method 1: Recursive function
function Flatten-Array ($array) {
$result = @()
foreach ($item in $array) {
if ($item -is [array]) {
$result += Flatten-Array $item
} else {
$result += $item
}
}
return $result
}
$flat = Flatten-Array $nested
$flat # 1, 2, 3, 4, 5, 6, 7, 8, 9
Q: What’s the most efficient way to add many items to an array?
A: Use List<T> instead of array with +=:
# Slow (O(n²) complexity)
$array = @()
1..1000 | ForEach-Object { $array += $_ }
# Fast (O(n) complexity)
$list = [System.Collections.Generic.List[int]]::new()
1..1000 | ForEach-Object { $list.Add($_) }
# Convert back to array if needed
$array = $list.ToArray()
Q: How do I randomize/shuffle an array?
A: Use Get-Random with the array:
$array = 1..10
# Shuffle array
$shuffled = $array | Get-Random -Count $array.Count
$shuffled # Random order: 3, 7, 1, 9, 2, 5, 10, 4, 8, 6
Conclusion
PowerShell arrays are fundamental data structures essential for efficient scripting and automation. In this comprehensive guide, you’ve learned:
✅ Creating arrays using multiple methods (@(), comma-separated, ranges, cmdlet output)
✅ Accessing elements with positive and negative indices, slicing, and safe access patterns
✅ Adding and removing elements efficiently with ArrayList and List
Key Takeaways:
- Use standard arrays for static data with known size
- Use
List<T>for dynamic collections with frequent modifications - Always check array bounds before accessing elements
- Prefer
foreachloops for best performance - Use strongly typed arrays when possible for type safety
Related Articles
Core Data Structures
- PowerShell Hashtables - Key-value pair collections
- PowerShell Strings - String manipulation and parsing
- PowerShell Variables - Variable storage and management
- PowerShell Data Types - All PowerShell data types
Iteration & Processing
- PowerShell ForEach-Object - Process array elements
- PowerShell Where-Object - Filter arrays
- PowerShell Select-Object - Extract array data
- PowerShell For Loops - Loop constructs for arrays
- PowerShell While Loops - Conditional looping
Control Flow & Logic
- PowerShell If-Else Statement - Conditional logic with arrays
- PowerShell Switch Statement - Switch-based array processing
- PowerShell Try-Catch - Error handling with arrays
File Operations
- PowerShell Get-Content - Read files into arrays
- PowerShell Output to File - Write arrays to files
- PowerShell Delete Files - Delete file arrays
- PowerShell List Files - Get file arrays
- PowerShell Copy-Item - Copy multiple files
Data Export & Conversion
- PowerShell Export CSV - Export arrays to CSV
- PowerShell Import CSV - Import CSV into arrays
- PowerShell Replace Strings - Transform array strings
Functions & Parameters
- PowerShell Functions - Use arrays in functions
- PowerShell Function Parameters - Array parameters
System Administration
- PowerShell Get-Process - Get process arrays
- PowerShell Get CPU Usage - System metrics in arrays
- PowerShell Get Memory Usage - Memory info in arrays
- PowerShell Get File Properties - File metadata arrays
Active Directory
- PowerShell Active Directory Guide - AD object arrays
- PowerShell AD Security Guide - AD security arrays
- DSACLS Permission Management - Permissions in arrays
- PowerShell Get-ADUser - AD user arrays
Performance & Optimization
- PowerShell Performance Tuning - Array optimization
- PowerShell Benchmarking - Performance testing
Comprehensive Guides
- Complete PowerShell Guide - Full PowerShell with arrays section
- Complete PowerShell Tutorial - Comprehensive course
- PowerShell Tutorial Complete - Full tutorial
You can find more topics about Active Directory tools and PowerShell automation on the ActiveDirectoryTools home page.