Declare a parameter, and:
assign it a default value.
make it pipeline-binding, and be sure to process each pipeline input object in the function body, namely via a process
block
- Note: Declaring a parameter pipeline-binding (with
[Parameter(ValueFromPipeline)]
below) implicitly makes a function an advanced one, which has (generally beneficial) behavioral implications - see this answer.
function Hello {
param(
[Parameter(ValueFromPipeline)]
$InputObject = 'Hello, World' # default value
)
process {
# Called for each pipeline input object, or once with the default value.
Write-Host $InputObject
}
}
For robustness, it's generally preferable to declare parameters explicitly, as shown above.
The - less desirable - parameter-less, simple-function alternative is the following, which collects all pipeline input up front, as it too implicitly runs in an end
block, and uses the automatic $input
variable and $MyInvocation.ExpectingInput
to detect if pipeline input was provided, as suggested by Santiago Squarzon:
function Hello {
if ($MyInvocation.ExpectingInput) { # input from the pipeline
$input | Write-Host # pass each pipeline input object to Write-Host
} else { # no pipeline input -> use default value
'Hello, World' | Write-Host
}
}
As for what you tried in your answer:
By not using a process
block, in effect only the last input object from the pipeline is bound to parameter $InputObject
, because a function body without (any one of) begin
, process
and end
blocks implicitly runs in an end
block, i.e. after all pipeline input has been received.
Generally, there's no good reason to type a parameter [PSObject]
or [PSObject[]]
, given that [psobject]
is a usually invisible helper type used behind the scenes.
Not typing a parameter is the same as typing it [object]
, which is what should be used to accept arguments of any type.
Typing it [array]
is the same as typing it [object[]]
, but note that if you type a pipeline-binding parameter as an array, each individual input object is automatically converted to an array - which slows down processing.
Only if you need to accept multiple values as a single command-line argument (as opposed to via the pipeline) is declaring a parameter as an array warranted - and when you do, you then need to enumerate each bound parameter value in your process
block, as it may itself be a true array.
As an aside: That pipeline-binding parameters declared with scalar types only accept multiple values via the pipeline, but not also implicitly as an argument is the subject of GitHub issue #4242