PowerShell throws “Cannot convert value to type System.String” when an advanced function’s [string] parameter receives an array instead of one value. Call it once per item, or join the items into one string:
foreach ($city in $cities) { Set-Label -City $city } # one call per item
Set-Label -City ($cities -join ', ') # one combined string
In this tutorial, I’ll show you how to reproduce cannot convert value to type system.string, find the hidden array behind it, and choose the right fix in PowerShell 7 and Windows PowerShell 5.1.
What causes Cannot convert value to type System.String?
The error comes from parameter binding. A function with [CmdletBinding()] or a [Parameter()] attribute is an advanced function, and PowerShell won’t squeeze an array into its [string] parameter.
Here’s a tiny function that prints an office label. I passed it two cities:
function Set-Label {
[CmdletBinding()]
param([string]$City)
"Label: $City office"
}
Set-Label -City 'Austin', 'Denver'
Output (PowerShell 7):
Set-Label: C:\psfaqs\err.ps1:7
Line |
7 | Set-Label -City 'Austin', 'Denver'
| ~~~~~~~~~~~~~~~~~~
| Cannot process argument transformation on parameter 'City'. Cannot convert value to type System.String.

Windows PowerShell 5.1 prints the same message, plus the category InvalidData and the error ID ParameterArgumentTransformationError:

The parameter name, City, tells you where to look. “Argument transformation” means the value was rejected before your code ran. If simple and advanced functions are new to you, start with functions in PowerShell.
Why does the same call work in a simple function?
Remove [CmdletBinding()] and the call goes through. A simple function converts the array to text and joins the items with a space:
function Set-Label {
param([string]$City)
"Label: $City office"
}
Set-Label -City 'Austin', 'Denver'
Output:
Labe