views:

121

answers:

2

I have a Powershell script that reads values off of the pipeline:

PARAM (
    [Parameter(ValueFromPipeline = $true)] 
    $s
)

PROCESS {
    echo "* $s"
}

Works just fine:

PS > my.ps1 foo
* foo

I would like the script to have list of default values, as the most common usage will always use the same values and storing them in the default will be most convenient. I did the usual assignment:

PARAM (
    [Parameter(ValueFromPipeline = $true)] 
    $s = 'bar'
)

PROCESS {
    echo "* $s"
}

Again, works just fine:

PS > my.ps1
* bar
PS > my.ps1 foo
* foo

However when setting the default to be a list, I get back something entirely reasonable but not at all what I want:

PARAM (
    [Parameter(ValueFromPipeline = $true)] 
    $s = @('bar', 'bat', 'boy')
)

PROCESS {
    echo "* $s"
}

Result:

PS > my.ps1
* bar bat boy

I expected:

PS > my.ps1
* bar
* bat
* boy

How can I get one call in to the Process loop for each default value? (This is somewhat different than getting one call in to Process, and wrapping the current body of in a big foreach loop over $s).

+2  A: 

It is worky as you would expect as shown more explicitly by this change to your code:

PARAM ( 
    [Parameter(ValueFromPipeline = $true)]  
    $s = @('bar', 'bat', 'boy') 
) 

PROCESS { 
    $s | %{$_ + " is a " + $_.GetType().Name}
}

What you are getting confused by is a feature of PowerShell where it flattens arrays when asked to render them to a string e.g.:

PS> $arr = 1,2,3
PS> "$arr"
1, 2, 3
PS> $OFS = ', '
PS> "$arr"
1, 2, 3

By default, PowerShell displays each array item one after another using a space separator. You can change the default separator to any string by setting the output field separator variable $OFS.

Keith Hill
Shoot. I was hoping not to have to do a foreach on each incoming object. Thank you.
fatcat1111
In general, you need to be able to account for collections and not just scalars for your pipelinebound (by value) parameter. The standard template out to be something like `Process { foreach ($obj in $pipelineParam) { ... } }`
Keith Hill
That sounds like solid advice. Thank you.
fatcat1111
A: 

Rather than:

PROCESS { 
    echo "* $s" 
}

do:

PROCESS { 
    $s | foreach-object {
       "* $_"
    }
}

and try to get out of the habit of using echo (write-output) as anything not captured will be output for you.

x0n
I actually need one call into process per object from the pipeline. That's what I meant by the parenthetical statement at the end. Thx though.
fatcat1111