powershellparameter-passingpipelinepositional-parameter

Function Parameter Position suddenly acting weird


Code:

This example illustrates what I mean:

Function test{
    param(
    [parameter(Position = 0, ValueFromPipeline)]
    [string]$Param0,
    [parameter(Position = 1)]
    [ArgumentCompletions("Param1_Opt1", "Param1_Opt2")]
    [Array]$Param1 = ('Param1_Opt3', 'Param1_Opt4'),
    [switch]$NoHeader
    )
    "This is $Param0"
    "Header :$Param1"
}

My issue:

For a long time I have been relying on parameter positions in all my functions today when writing a function, suddenly its stopped working the way I have been using them. The above test function demonstrates this issue.

If a parameter has a parameter Position = 0 property and also has the ValueFromPipeline property. When its used in pipeline. The next parameter that has a Position property takes its position. This also means this next parameters ArgumenCompletions, such as "Param1_Opt1" /"Param1_Opt2" get suggested.

But I am not getting this behaviour at all.

Test "This is For Parameter Zero" "This is For Parameter One"

---- Ouput -----
This is For Parameter Zero
This is For Parameter One

The above works as expected, The first string is correctly assigned to Param0 and the second to Param1,further more Param1 argument suggestions works, but the following fails with an error and the pipeline string is assigned to Param1. Also Param1 argument completions don't work:

"This is For Parameter Zero" | Test "This is For Parameter One"
---- Error ----
test: The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
--- OutPut ----
This is For Parameter One
Header :Param1_Opt0 Param1_Opt0

Desired Output:

Test "This is For Parameter Zero" "This is For Parameter One"

---- Ouput -----
This is For Parameter Zero
This is For Parameter One

The above is what I am expecting in normal usage and the following for when the pipeline is used and for Param1 argument suggestions to work:

"This is For Parameter Zero" | Test "This is For Parameter One"

---- Ouput -----
This is For Parameter Zero
This is For Parameter One

Solution

  • Santiago has provided the crucial pointer in a comment, but let me spell it out:

    In your pipeline-based invocation, you'll need to use a named argument to bind to -Param1:

    # Note the required use of -Param1
    "This is For Parameter Zero" | Test -Param1 "This is For Parameter One"
    

    The reason this is necessary is the order of parameter binding:

    Therefore: