Back to Basics: Is my Parameter Value from the Pipeline?

I was asked how to check if a supplied parameter value has come from the pipeline. I came up with two different methods, the first only works with v2.

Here are the two test conditions:

Test-ParamSource -MyParam $vals
$vals | Test-ParamSource

 

Where $vals is an array of integers:

$vals = 3,4,5,6,40,50

 

Right, we need to check the source of the parameter value before we start processing it... and there's the clue - Process {} . In an advanced function, we can insert a Begin {} statement to perform actions before we start to process values from the pipeline.

Now, we need a means of differentiating. Let's deal with the v2-only method first. As it happens, if a value is supplied directly to the function, during the Begin {}  statement the variable representing the parameter will be populated. If the value comes from the pipeline, then the parameter variable will be null. Time for some conditional logic. Here's what the complete v2-only function looks like:

#Test parameter source v2
function Test-ParamSource  {

[CmdletBinding()]
Param(
[parameter(Mandatory=$True,ValueFromPipeline=$true)]
[Array]$MyParam
)

Begin {

Write-Output $MyParam.Count

        if ($MyParam.Count -eq $null) {

            Write-Output "Value from pipeline"

        }
else {

            Write-Output "Supplied to function"

        }

}

Process {

write-output $MyParam

}

}

 

Here's what happens when we run the function under the first condition.

Capture141

 

In Begin {} , we get a count of the number of objects in $MyParam - 6 - and some output telling us where the parameter values came from - "Supplied to function" - based on a test of whether the variable in $null or not.

In Process {} , we act upon each element supplied to the pipeline and output its value.

 

Now, for the second condition.

Capture142

 

This  time in Begin{} there isn't a count, but we do have 'Value from pipeline'.

Process {} does what's expected.

 

Now, for the v3+ version. As (almost) every object has count / length available in v3+, we can't use the $null test. We could test for a count of 0, but I prefer to use $PSBoundParameters automatic variable.

#Test parameter source v3
function Test-ParamSource  {

[CmdletBinding()]
Param(
[parameter(Mandatory,ValueFromPipeline)]
[Array]$MyParam
)

    Begin {

        Write-Output $MyParam.Count

        if (-not($PSBoundParameters.ContainsKey("MyParam"))) {

Write-Output "Value from pipeline"

        }
else {

            Write-Output "Supplied to function"

        }

}

    Process {

write-output $MyParam

}

}

 

$PSBoundParameters is a System.Management.Automation.PSBoundParametersDictionary object and includes a ContainsKey() method. We can use that to check if the parameter has been bound and apply some branching logic as per the v2-only method.

Condition 1.

Capture143

 

As before, but the ContainsKey() method performs the test. Now for condition 2.

Capture144

 

Notice that this time we have a value of 0 for $MyParam.Count.

 

Final Word

The question actually concerned testing whether a value came from pipeline AND if a certain switch was present. This could be achieved by tweaking the Begin {} if statement:

if (-not($PSBoundParameters.ContainsKey("MyParam")) -and $Go) {}