log in

PowerShell: pipeline as array

Luke Breuer
2017-09-17 02:50 UTC

PowerShell makes it a bit tricky to access pipeline input as a whole, e.g. an array or IEnumerable. For example, suppose I want to write a cmdlet To-HashSet, which creates a HashSet<string> of stdin. One option is to do this:
function To-HashSet
    begin { $h = New-Object System.Collections.Generic.HashSet[string]; }
    process { $h.Add($_.ToString()); }
    end { return ,$h; }

The use of ,$h prevents PowerShell from converting the HashSet<string> to Object[]. But Why not just use the HashSet<T>(IEnumerable<T>) constructor? It can be done, but only very carefully:
function To-HashSet
    return New-Object System.Collections.Generic.HashSet[string] (,[string[]]@($input))

The , here is required, as otherwise PowerShell would will interpret an array argument as an array of arguments. Or at least a string[]. For more, see this SO answer.

To test To-HashSet and see what happens if one tries to simply them:
$h = 1,2,3 | To-HashSet
"$($h.GetType().Name)  Count = $($h.Count)"

You should get the following:
HashSet`1  Count = 3

In attempting to get that, here are two other outputs (when it didn't error out because I wasn't invoking the constructor properly):
Object[]  Count = 3    # by omitting the , in the end block
HashSet`1  Count = 1   # by omitting @() in the New-Object approach

For more, see: