To make a PowerShell array parameter, give the parameter an array type such as [string[]]. Callers can then pass several values separated by commas, or just one value:
function Get-ServerReport {
param(
[string[]]$ComputerName
)
foreach ($computer in $ComputerName) {
"Checking $computer"
}
"Total: $($ComputerName.Count)"
}
Get-ServerReport -ComputerName WEB01, WEB02, SQL01
Get-ServerReport -ComputerName WEB01
Output:
Checking WEB01
Checking WEB02
Checking SQL01
Total: 3
Checking WEB01
Total: 1
With [string[]], a single value still arrives as an array with one item, so the same foreach loop handles both calls.
I tested every example in PowerShell 7.6 and Windows PowerShell 5.1, and they behaved the same in both. Most of this guide is about the mistakes that make array parameters misbehave.
Pass an array to a function
Use the parameter name, then the values separated by commas. Don’t call a PowerShell function like a method with parentheses. Here’s what happens when you do:
function Send-Report {
param([string[]]$To, [int]$Days)
"To: $($To -join '; ') | Days: $Days"
}
Send-Report -To 'maria@contoso.com', 'it@contoso.com' -Days 7
Send-Report('maria@contoso.com', 'it@contoso.com', 7)
Output:
To: maria@contoso.com; it@contoso.com | Days: 7
To: maria@contoso.com; it@contoso.com; 7 | Days: 0

In the second call, PowerShell sees one array, ('maria@contoso.com', 'it@contoso.com', 7), and binds all of it to -To. The number 7 ends up in the email list, and -Days is left at 0.
In PowerShell, spaces separate arguments and commas build an array. Save the parentheses-and-commas style for .NET methods like $text.Replace('a', 'b').
Accept an array from the pipeline
Add ValueFromPipeline so you can pipe values into the function. But if you forget the process block, only the last item is used:
function Test-Server {
param(
[Parameter(ValueFromPipeline)]
[string[]]$ComputerName
)
"Checking $ComputerName"
}
'WEB01', 'WEB02', 'SQL01' | Test-Server
Output:
Checking SQL01

Code that isn’t in a named block runs once, after the pipeline has finished, when the parameter holds only the last value. Put the work in process, which runs once for each piped item:
function Test-Server {
param(
[Parameter(ValueFromPipeline)]
[string[]]$ComputerName
)
process {
foreach ($computer in $ComputerName) {
"Checking $computer"
}
}
}
'WEB01', 'WEB02' | Test-Server
Test-Server -ComputerName SQL01, SQL02
Output:
Checking WEB01
Checking WEB02
Checking SQL01
Checking SQL02
The inner foreach is what makes the second call work. When you pass the array by name instead of piping it, process runs only once, with the whole array.
Validate the array
Validation attributes check every item in the array before your code runs. ValidateCount limits how many items are allowed, and ValidateSet limits which values:
function Restart-WebServer {
param(
[ValidateCount(1, 3)]
[ValidateSet('WEB01', 'WEB02', 'WEB03')]
[string[]]$ComputerName
)
"Would restart: $($ComputerName -join ', ')"
}
Restart-WebServer -ComputerName WEB01, WEB03
try {
Restart-WebServer -ComputerName WEB01, SQL01
}
catch {
$_.Exception.Message
}
Output:
Would restart: WEB01, WEB03
Cannot validate argument on parameter 'ComputerName'. The argument "SQL01" does not belong to the set "WEB01,WEB02,WEB03" specified by the ValidateSet attribute. Supply an argument that is in the set and then try the command again.
The error names the bad value, which is much friendlier than a script that fails halfway through a restart.
Make the array parameter mandatory
Mark it Mandatory and PowerShell prompts for the values when they’re missing, one item per line. Press Enter on an empty line to finish. Here’s what that looked like when I ran it and typed two names:
function Get-ServerReport {
param(
[Parameter(Mandatory)]
[string[]]$ComputerName
)
"Checking $($ComputerName.Count) servers: $($ComputerName -join ', ')"
}
Get-ServerReport
Output:
cmdlet Get-ServerReport at command pipeline position 1
Supply values for the following parameters:
ComputerName[0]: WEB01
ComputerName[1]: WEB02
ComputerName[2]:
Checking 2 servers: WEB01, WEB02
This only works when someone is at the keyboard. In a scheduled task, pass the values on the command line instead.
Pass an array to a script from the command line
This catches people who call scripts from Task Scheduler or a batch file. With -File, a comma-separated list arrives as a single string. With -Command, it becomes a real array:
pwsh -NoProfile -File C:\psfaqs\report.ps1 -ComputerName WEB01,WEB02
pwsh -NoProfile -Command "& C:\psfaqs\report.ps1 -ComputerName WEB01,WEB02"
Output in PowerShell 7:
Count: 1 -> WEB01,WEB02
Count: 2 -> WEB01 | WEB02

Windows PowerShell 5.1 printed exactly the same with powershell.exe. If you must use -File, split the value inside the script, for example with $ComputerName = $ComputerName -split ','.
For more on script arguments, see how to run a PowerShell script with parameters.
Can a function change the array you pass in?
Partly. The function gets the same array, so changing an item is visible to the caller. Adding with += builds a new array that the caller never sees:
function Update-List {
param($List)
$List[0] = 'DC01'
$List += 'NEW01'
"Inside: $($List -join ', ')"
}
$servers = 'WEB01', 'WEB02'
Update-List -List $servers
"Outside: $($servers -join ', ')"
Output:
Inside: DC01, WEB02, NEW01
Outside: DC01, WEB02
If a function needs to add items, return the new array and assign it, or pass a List. Appending to arrays in PowerShell shows both ways.
Return an array from a function
PowerShell unrolls arrays when a function outputs them. That means a one-item array comes back as a plain value:
function Get-SiteServers {
param([string]$Site)
if ($Site -eq 'Austin') { @('WEB01') } else { @('WEB01', 'WEB02') }
}
$austin = Get-SiteServers -Site Austin
$dallas = Get-SiteServers -Site Dallas
"Austin: $($austin.GetType().Name)"
"Dallas: $($dallas.GetType().Name)"
$wrapped = @(Get-SiteServers -Site Austin)
"Austin in @(): $($wrapped.GetType().Name)"
Output:
Austin: String
Dallas: Object[]
Austin in @(): Object[]
If you then use $austin[0], you get the first letter, W, instead of WEB01. Wrap the call in @() and you always get an array.
Microsoft documents every parameter attribute in about_Functions_Advanced_Parameters.
Frequently Asked Questions
How do I pass an array to a PowerShell function?
Call it with the parameter name and comma-separated values, like Get-Report -ComputerName WEB01, WEB02. Don’t use parentheses, which send everything to the first parameter.
How do I declare an array parameter in PowerShell?
Give it an array type in the param() block, such as [string[]]$ComputerName or [int[]]$Id. A single value is accepted as an array of one.
Why does my pipeline function only process the last item?
The code isn’t in a process block. Put it in process { } so it runs once for each piped item.
How do I pass an array to a script with pwsh -File?
You can’t directly: -File passes a,b as one string. Use -Command instead, or split the string inside the script with -split ','.
Why does my function return a string instead of an array?
PowerShell unrolls a one-item array when a function outputs it. Wrap the call in @(), like $servers = @(Get-Servers), to always get an array.
If you work with arrays in functions, these help too:
- Append to an array in PowerShell
- Check if an array contains a value
- Print arrays in PowerShell
- PowerShell switch parameters
Bijay Kumar is an esteemed author and the mind behind PowerShellFAQs.com, where he shares his extensive knowledge and expertise in PowerShell, with a particular focus on SharePoint projects. Recognized for his contributions to the tech community, Bijay has been honored with the prestigious Microsoft MVP award. With over 15 years of experience in the software industry, he has a rich professional background, having worked with industry giants such as HP and TCS. His insights and guidance have made him a respected figure in the world of software development and administration. Read more.