Pivot-Object.ps1

<#PSScriptInfo
  
.DESCRIPTION Converts a stream of input items into properties of a resulting object
.VERSION 1.0.0
.GUID 61645f49-9efe-49c7-8f24-520f134263b5
.AUTHOR Lee Holmes
  
#>


<#
 
.SYNOPSIS
Converts a stream of input items into properties of a resulting object
 
.EXAMPLE
PS > 1..5 | Pivot-Object -Width 3
P1 P2 P3
-- -- --
1 2 3
4 5
 
.EXAMPLE
PS > gc C:\temp\addresses.txt
Name: Joe
Phone: 555-1212
 
Name: Frank
Phone: 555-1213
 
PS > gc C:\temp\addresses.txt | % { $_ -replace '.*: (.*)','$1' } | Pivot-Object -Property Name,Phone,$null
 
Name Phone
---- -----
Joe 555-1212
Frank 555-1213
 
#>


param(
    ## The stream of input objects to convert to properties
    [Parameter(Mandatory, ValueFromPipeline)]
    $InputObject,

    ## The number of properties in the resulting object
    [Parameter(Position = 0)]
    [int] $Width = 2,

    ## Property names of the resulting object. Specify
    ## $null for input items you want to skip.
    [Parameter()]
    [string[]] $Property = @()
)

begin
{
    if($Property.Count -gt $Width)
    {
        $Width = $Property.Count
    }

    ## If the user wants a wider object than the number of properties they've specified,
    ## auto-generate property names.
    $Property = for($propertyIndex = 0; $propertyIndex -lt $Width; $propertyIndex++)
    {
        if($propertyIndex -ge $Property.Count)
        {
            "P" + ($propertyIndex + 1)
        }
        else
        {
            $Property[$propertyIndex]    
        }
    }
    
    ## Initialize the output object
    $currentProperty = 0
    $outputObject = [Ordered] @{}
    $Property | % {
        if($_) { $outputObject[$_] = $null }
    }
}

process
{
    ## Output the output object if we've filled up all the properties
    if($currentProperty -ge $Width)
    {
        $currentProperty = 0
        [PSCustomObject] $outputObject

        ## And re-initialize the output object
        $outputObject = [Ordered] @{}
        $Property | % {
            if($_) { $outputObject[$_] = $null }
        }
    }

    ## If there's an actual property name (i.e.: they haven't used $null to skip it),
    ## add that to the output object.
    if($Property[$currentProperty])
    {
        $outputObject[$Property[$currentProperty]] = $InputObject
    }

    ## Next object, next property
    $currentProperty++;
}

end
{
    ## Output anything we have left
    if($currentProperty -gt 0)
    {
        [PSCustomObject] $outputObject
    }
}