Powershell 5 : Cannot convert value To System.String

12,156

Note: As of this writing, there's no explanation for the specific symptoms described in the question, and Sandy reports their problem as now resolved.
This answer generally explains under what circumstance you'll see the Cannot convert value to type System.String error when passing an argument to a [string]-typed parameter.


With your sample function, which by virtue of using a [Parameter()] attribute is implicitly an advanced function, there are only two ways that passing a value to your [string]-typed parameters can fail:

  • passing $null or an empty string (such as '' or "")[1]

  • passing an array[2] instead of a single value.

If you pass a value of any other type, it is automatically converted to a string.

Given the error message you received, the latter must be the problem, as demonstrated here:

function myFunc { 
  param(
    [Parameter(Mandatory)] # NOTE: This makes the function an *advanced* function.
    [string] $param1
  )
  "[$param1]"
}

# FAILS, because an *array* can't be passed as a *single string*
# to an *advanced* function's [string] parameter.
myFunc -param1 'one', 'two'

This yields the following error:

Cannot process argument transformation on parameter 'param1'. 
Cannot convert value to type System.String

The inability to pass an array to a [string] parameter applies only to advanced functions (the explicit alternative to making a function implicitly an advanced one via a [Parameter() attribute is to place a [CmdletBinding()] attribute above the param(...) block).

A simple (non-advanced) function does accept an array as a [string] argument, and simply joins the array elements with spaces[3] on conversion; e.g.,
'one', 'two' turns into 'one two'

Note: Arguably, passing an array to a [string] parameter should always require a deliberate action on the caller's part - both to confirm the actual intent to pass an array and to control how it is stringified - so it is the behavior of advanced functions that is the more sensible one (except for not consistently applying to collections in general).
Given PowerShell's commitment to backward compatibility, the behavior of non-advanced functions is unlikely to change, however.


[1] The only way to allow these values is to make the parameters non-mandatory, by removing the Mandatory=$true attribute property (or setting it to $false). Curiously, mandatory [string] parameters don't accept these values even when deliberately passed.

[2] Curiously, collections that aren't technically arrays (derived from [System.Array] / [object[]]), such as [System.Collections.ArrayList] or [System.Collections.Generic.List[object]], are accepted and are then stringified as with non-advanced functions.

[3] Technically, you can control the separator character (string) via preference variable $OFS.

Share:
12,156
Sandy
Author by

Sandy

Updated on June 23, 2022

Comments

  • Sandy
    Sandy almost 2 years

    I have a PS script with which I read a csv file line by line into a variable :

    CSV :

      header1;header2
      column1;column2
    

    PS Script :

    #-------------------------
    #   Func declarations    
    #-------------------------
    function myFunc{
       param(
        [Parameter(Mandatory=$true)][string]$param1,
        [Parameter(Mandatory=$true)][string]$param2
       )
       #Do something
    }
    
    #-------------------------
    #       Run    
    #-------------------------
    
    $lines = Import-Csv .\etc\file.csv -Delimiter ";" -Header "header1","header2"
    
    foreach($line in $lines) {
        myFunc -param1 $line.header1 -param2 $line.header1
    }
    

    The call myFunc -param1 $line.header1 throws a:

    Cannot convert value To System.String (...) ParameterBindingArgumentTransformationException

    Checking the type of $line.header1 (or $line.header2) with $line.header1.GetType() returns as expected System.string.

    • If I remove one parameter (whichever), it works
    • If I remove the type definition on the first like so : [Parameter(Mandatory=$true)]$param1, the first one is recognized but the second is null...

    Why?