Question

My cmdlet tries to take 2 parameters, 1 from pipeline and 1 from user input, and I am wondering is it possible to be done by positional parameter so that it is like:

Set-login name pw | add-view viewName

where add-view is like:

[parameter(position=0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, Mandatory = true)]
public loginInfo Login {}
[parameter(position=1, Mandatory = true)]
public String Name {}
...

however, with the above properties,

Set-login name pw | add-view viewName 

will return error saying cannot convert String to loginInfo, I have to do either:

$a = Set-login name pw
Add-View $a viewnames

or

$a | Add-View -Name viewnames

It seems positional parameter and pipeline are against each other, is this true? what is the work around?

Thanks!

Was it helpful?

Solution

Solution: move Name parameter to the first position to be sure string passed will be bound to this parameter rather than to Login parameter, one that you want to pass values to using pipeline anyways.

Reason: in-line parameter binding is a process that happens before pipeline processing starts. For example simple function, that is somewhat similar to your cmdlet:

function Test-FooBar {
param (
    [Parameter(ValueFromPipeline)]
    $Foo,
    $Bar
)

process {
    "Foo: $Foo Bar: $Bar"
}
}

Depending on positional binding (with one that takes value from pipeline in the first position):

Trace-Command -Name ParameterBinding -Expression { 1 | Test-FooBar 2} -PSHost
DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Foo-Bar]
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Foo-Bar]
DEBUG: ParameterBinding Information: 0 :     BIND arg [2] to parameter [Foo]
DEBUG: ParameterBinding Information: 0 :         BIND arg [2] to param [Foo] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Foo-Bar]
DEBUG: ParameterBinding Information: 0 :     BIND arg [] to parameter [Bar]
DEBUG: ParameterBinding Information: 0 :         BIND arg [] to param [Bar] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
(...)

'2' is already bound to first positional, so you will get error that pipeline input can not be bound (eventually).

Same, but this time we make sure that '2' will be bound to second parameter:

Trace-Command -Name ParameterBinding -Expression { 1 | Test-FooBar -Bar 2} -PSHost
DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Test-FooBar]
DEBUG: ParameterBinding Information: 0 :     BIND arg [2] to parameter [Bar]
DEBUG: ParameterBinding Information: 0 :         COERCE arg to [System.Object]
DEBUG: ParameterBinding Information: 0 :             Parameter and arg types the same, no coercion is needed.
DEBUG: ParameterBinding Information: 0 :         BIND arg [2] to param [Bar] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Test-FooBar]
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Test-FooBar]
DEBUG: ParameterBinding Information: 0 :     BIND arg [] to parameter [Foo]
DEBUG: ParameterBinding Information: 0 :         BIND arg [] to param [Foo] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
DEBUG: ParameterBinding Information: 0 : BIND PIPELINE object to parameters: [Test-FooBar]
DEBUG: ParameterBinding Information: 0 :     PIPELINE object TYPE = [System.Int32]
DEBUG: ParameterBinding Information: 0 :     RESTORING pipeline parameter's original values
DEBUG: ParameterBinding Information: 0 :     Parameter [Foo] PIPELINE INPUT ValueFromPipeline NO COERCION
DEBUG: ParameterBinding Information: 0 :     BIND arg [1] to parameter [Foo]
DEBUG: ParameterBinding Information: 0 :         BIND arg [1] to param [Foo] SUCCESSFUL
(...)

As you can see now - once BeginProcessing is called BIND PIPELINE triggers and because there are still parameters accepting pipeline input present - it works fine.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top