Feeding switch parameter from pipeline input

This topic contains 8 replies, has 5 voices, and was last updated by Profile photo of Curtis Smith Curtis Smith 1 year ago.

  • Author
    Posts
  • #33288

    Hello experts, I need to pass parameters to a script from pipeline input by importing the required values from CSV file. The original script has more than 15 parameters to be passed and input values are stored in a CSV file. I am posting a simple example to express the issue.

    Below are the contents of CSV file (Input.csv)

    ResourceGroupName,SetThrottling
    TestRG1,1
    TestRG2,0
    TestRG3,1
    TestRG4,0
    TestRG5,0

    Script file – Switch-FromPipelineTest.ps1

    [CmdletBinding()]
    Param
    (
    [Parameter(Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)]
    [String]$ResourceGroupName,

    [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)]
    [Switch]$SetThrottling
    )

    Begin {}
    Process
    {
    Function TestingValues
    {
    Param
    (
    $ResourceGroupName,
    $SetThrottling
    )

    Write-Host "$ResourceGroupName is set to $SetThrottling"
    }

    TestingValues -ResourceGroupName $ResourceGroupName -SetThrottling $SetThrottling
    }
    End {}

    If I run the command Import-Csv .\Input.csv | .\Switch-FromPipelineTest.ps1 it gives an error as given below:

    C:\Scripts\Switch-FromPipelineTest.ps1 : Cannot process argument transformation
    on parameter 'SetThrottling'. Cannot convert value "System.String" to type
    "System.Management.Automation.SwitchParameter". Boolean parameters accept only
    Boolean values and numbers, such as $True, $False, 1 or 0.
    At line:1 char:26
    + Import-Csv .\Input.csv | .\Switch-FromPipelineTest.ps1
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidData: (@{ResourceGroup...etThrottling=1}:P
    SObject) [Swith-FromPipelineTest.ps1], ParameterBindingArgumentTransformati
    onException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,Switch-FromPi
    pelineTest.ps1

    In order to make this work, I have to run below command:
    Import-Csv -Path .\Input.csv -Verbose | Select-Object -Property ResourceGroupName,@{n='SetThrottling';e={[bool][int]$_.SetThrottling}} | .\Switch-FromPipelineTest.ps1

    Is there a way we can omit the type casting done by using custom property expression in the second command? as in the original script, I have several [switch] parameters and I need to do the same thing for each [switch] parameter.

  • #33290
    Profile photo of Max Kozlov
    Max Kozlov
    Participant

    remove ValueFromPipeline=$True from both parameters
    and read some tips here

    todo: move function TestingValues to begin{} block

  • #33291
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    Hmm, I've never tried to do a switch parameter from the pipeline. However, when you're using splatting, you can do switches with $true or $false, so maybe it'll work in the pipeline if you make it a [bool] instead of [int].

  • #33303

    @Max Kozlov: I went through that link earlier and also tried to remove ValueFromPipeline=$True from both parameters, it didn't help. I still need to manually convert the value from CSV column to [Switch] / [bool] before passing it to the script.

    @Dave Wyatt: I can execute the script if I use:
    Import-Csv -Path .\Input.csv -Verbose | Select-Object -Property ResourceGroupName,@{n='SetThrottling';e={[bool][int]$_.SetThrottling}} | .\Switch-FromPipelineTest.ps1

    But I want to get rid of this extra layer of conversion using Select-Object, since my actual script has now around 30 parameters that I need to pass using CSV and there are many switch parameters that I have to convert like this if I don't get a solution.

  • #33304
    Profile photo of Max Kozlov
    Max Kozlov
    Participant

    sorry, does not test solution before...
    also you need to change or remove parameter types from outer proxy function and do type conversion inplace
    this variant works well

    [CmdletBinding()]
     Param
     (
     [Parameter(Mandatory=$True, ValueFromPipelineByPropertyName=$True)]
     [string]$ResourceGroupName,
    
    [Parameter(ValueFromPipelineByPropertyName=$True)]
     [int]$SetThrottling
     )
    
    Begin {
     Function TestingValues
     {
     Param
     (
     [string]$ResourceGroupName,
     [switch]$SetThrottling
     )
    
    Write-Host "$ResourceGroupName is set to $SetThrottling"
     }
    }
     Process
     {
    	TestingValues -ResourceGroupName $ResourceGroupName -SetThrottling:([bool]$SetThrottling)
     }
     End {}
    
  • #33305
    Profile photo of Max Kozlov
    Max Kozlov
    Participant

    btw, import-csv afaik always import values as string thus you always need conversion as you do with select, as I suggest with inplace conversion or by using foreach-object:

    Import-Csv -Path .\Input.csv -Verbose | Foreach-Object { $_.SetThrottling=[bool][int]$_.SetThrottling; $_ }  | .\Switch-FromPipelineTest.ps1
    

    if you need to convert many parameters you can do this in cycle like

    $toconvert = 'SetThrottling','param1','param2'
    
    Import-Csv -Path .\Input.csv -Verbose | Foreach-Object {
    foreach ($param in $toconvert) {
    $_.$param = [bool][int]$_.$param 
    }
    $_
    }  |
     .\Switch-FromPipelineTest.ps1
    
  • #33306
    Profile photo of Peter Jurgens
    Peter Jurgens
    Participant

    As Max said, the main problem here is that Import-Csv makes all values from the CSV file as String values, and powershell obviously does not like trying to convert the string values to bool.

    I too would recommend just placing a Select-Object between your Import-Csv and your function with a calculated property to try to convert the property from the CSV file into a Boolean value. It may seem like unnecessary work but unfortunately it's due to the way the Import-Csv cmdlet was designed (to this point at least).

    PS Merry Christmas!!

  • #33310

    Thank you all for your inputs. After looking at all possibilities I think I have to convert the switch parameter to a string parameter by sung a validate set of "Yes" and "No". I will change the CSV format to use Yes and NO instead of 1 and 0.

    In script I will check the value using If condition whether $SetThrottling = Yes or No.

    That seems to be the only option for now as there is no other way we can pass Bool values through pipeline while importing CSV.

  • #33314
    Profile photo of Curtis Smith
    Curtis Smith
    Participant

    (Post update: Scratch that, I see the problem and the below does not help the issue)

    @savindrasingh-shahoo use [System.Convert]::ToBoolean()

    https://social.technet.microsoft.com/Forums/windowsserver/en-US/300b5602-b16a-4a10-96fd-3e2e6ba29ed6/importcsv-with-true-and-false-values?forum=winserverpowershell

    [pscustomobject]@{
        Value1 = $true
        Value2 = $false
        Value3 = "string"
    } | Export-Csv test.csv
    
    $a = Import-Csv test.csv
    
    [System.Convert]::ToBoolean($a.Value1)
    [System.Convert]::ToBoolean($a.Value2)
    [System.Convert]::ToBoolean($a.Value3)
    
    ($a.Value1).GetType()
    ($a.Value2).GetType()
    ([System.Convert]::ToBoolean($a.Value1)).GetType()
    ([System.Convert]::ToBoolean($a.Value2)).GetType()
    

    Results:

    True
    False
    Exception calling "ToBoolean" with "1" argument(s): "String was not recognized as a valid Boolean."
    At line:11 char:1
    + [System.Convert]::ToBoolean($a.Value3)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : FormatException
    
    IsPublic IsSerial Name                                     BaseType                                                                                                                  
    -------- -------- ----                                     --------                                                                                                                  
    True     True     String                                   System.Object                                                                                                             
    True     True     String                                   System.Object                                                                                                             
    True     True     Boolean                                  System.ValueType                                                                                                          
    True     True     Boolean                                  System.ValueType
    

You must be logged in to reply to this topic.