2

I am writing a PowerShell function which can take pipeline input. Specifically I am testing it with Import-CSV. Many of the params are not mandatory, which means sometimes the CSV will not have those columns. For boolean values this is working as expected, but with string values, a missing CSV field yields a copy of the row object in the string field.

Here is an example problem parameter:

[Parameter(Mandatory=$False,
       ValueFromPipeline=$True,
       ValueFromPipelinebyPropertyName=$True,
       HelpMessage="TCP Port of the remote server")]
[Alias('Port', 'Remote Server Port')]
[string]$RemoteServerPort = "5500",

Now, if the field is missing, I would expect the value to be "5500" as specified, but instead I get:

$RemoteServerPort = @{Name=KG; IP=10.1.1.1; Username=Admin; Password=}

I've done some looking around, but frankly I'm not even sure what to search for.

1 Answer 1

3

This is because you specified ValueFromPipeline=$True so that PoSh coerces the piped object to a string if it cannot bind the parameter by property name. You could solve that by removing ValueFromPipeline=$True from this parameter and introduce another one to be bound to the piped object, i.e. something like this

function MyTestFunc() {

    param(
        [Parameter(ValueFromPipeline=$True)]
        [object]$PipedObj,

        [Parameter(Mandatory=$False,
               ValueFromPipelinebyPropertyName=$True,
               HelpMessage="TCP Port of the remote server")]
        [Alias('Port', 'Remote Server Port')]
        [string]$RemoteServerPort = "5500"
    )

    Write-Host "Port: $RemoteServerPort / Obj: $PipedObj"
}


$o1 = [pscustomobject]@{"Server" = "123"; "Port" = "12345"}
$o2 = [pscustomobject]@{"Server" = "1234"; "OS" = "Win3.1"}

$o1 | MyTestFunc
$o2 | MyTestFunc

Will result in

Port: 12345 / Obj: @{Server=123; Port=12345}
Port: 5500 / Obj: @{Server=1234; OS=Win3.1}

A way to see in detail what is actually happening behind the scenes is to use Trace-Command like so

Trace-Command ParameterBinding {$o2 | MyTestFunc} -PSHost
Sign up to request clarification or add additional context in comments.

5 Comments

I tried what you suggested and got the same result. $RemoteServerPort is still displaying the object string instead of "5500".
So, I had ValueFromPipeline=$True on a basically all the properties which I now commented out, leaving on the $PipedObj you suggested and it seems like it worked. I need to do a bit more testing though. Do you know why this would be the case?
Well I guess in that case the whole binding process is confused - there is a blog post about handling pipeline input and there is also mentioned about weird things happening in such edge cases. If one thinks about it, it doesn't make sense to have ValueFromPipeline=$True for multiple parameters of the same type as PoSh don't know to which parameter the pipeline input should be bound to in this case
DAX, thanks so much for your help, I'm not sure I would have solved this one on my own. I have read about the param attributes before and I think the naming and descriptions of the two pipeline parameters are pretty confusing. I'll dig into that article, thanks!
Glad to hear it helped

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.