powershellpowershell-5.0

Powershell 5 : Cannot convert value To System.String


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.

Why?


Solution

  • 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:

    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 (which, sadly, doesn't reveal the specific cause):

    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.