Author Posts

December 24, 2015 at 2:28 am

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.

December 24, 2015 at 3:24 am

remove ValueFromPipeline=$True from both parameters
and read some tips here
Tips on Implementing Pipeline Support

todo: move function TestingValues to begin{} block

December 24, 2015 at 4:49 am

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].

December 24, 2015 at 10:32 pm

@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.

December 24, 2015 at 10:45 pm

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 {}

December 25, 2015 at 1:05 am

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

December 25, 2015 at 3:58 am

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!!

December 25, 2015 at 7:30 pm

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.

December 26, 2015 at 8:12 pm

(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