Private/Add-ObjectDetail.ps1

#requires -Version 2
function Add-ObjectDetail
{
    <#
            .SYNOPSIS
            Decorate an object with
            - A TypeName
            - New properties
            - Default parameters
 
            .DESCRIPTION
            Helper function to decorate an object with
            - A TypeName
            - New properties
            - Default parameters
 
            .PARAMETER InputObject
            Object to decorate. Accepts pipeline input.
 
            .PARAMETER TypeName
            Typename to insert.
         
            This will show up when you use Get-Member against the resulting object.
         
            .PARAMETER PropertyToAdd
            Add these noteproperties.
         
            Format is a hashtable with Key (Property Name) = Value (Property Value).
 
            Example to add a One and Date property:
 
            -PropertyToAdd @{
            One = 1
            Date = (Get-Date)
            }
 
            .PARAMETER DefaultProperties
            Change the default properties that show up
 
            .PARAMETER Passthru
            Whether to pass the resulting object on. Defaults to true
 
            .EXAMPLE
            #
            # Create an object to work with
            $Object = [PSCustomObject]@{
            First = 'Cookie'
            Last = 'Monster'
            Account = 'CMonster'
            }
 
            #Add a type name and a random property
            Add-ObjectDetail -InputObject $Object -TypeName 'ApplicationX.Account' -PropertyToAdd @{ AnotherProperty = 5 }
 
            # First Last Account AnotherProperty
            # ----- ---- ------- ---------------
            # Cookie Monster CMonster 5
 
            #Verify that get-member shows us the right type
            $Object | Get-Member
 
            # TypeName: ApplicationX.Account ...
 
            .EXAMPLE
            #
            # Create an object to work with
            $Object = [PSCustomObject]@{
            First = 'Cookie'
            Last = 'Monster'
            Account = 'CMonster'
            }
 
            #Add a random property, set a default property set so we only see two props by default
            Add-ObjectDetail -InputObject $Object -PropertyToAdd @{ AnotherProperty = 5 } -DefaultProperties Account, AnotherProperty
 
            # Account AnotherProperty
            # ------- ---------------
            # CMonster 5
 
            #Verify that the other properties are around
            $Object | Select -Property *
 
            # First Last Account AnotherProperty
            # ----- ---- ------- ---------------
            # Cookie Monster CMonster 5
 
            .NOTES
            This breaks the 'do one thing' rule from certain perspectives...
            The goal is to decorate an object all in one shot
    
            This abstraction simplifies decorating an object, with a slight trade-off in performance. For example:
 
            10,000 objects, add a property and typename:
            Add-ObjectDetail: ~4.6 seconds
            Add-Member + PSObject.TypeNames.Insert: ~3 seconds
 
            Initial code borrowed from Shay Levy:
            http://blogs.microsoft.co.il/scriptfanatic/2012/04/13/custom-objects-default-display-in-powershell-30/
         
            .LINK
            http://ramblingcookiemonster.github.io/Decorating-Objects/
 
            .FUNCTIONALITY
            PowerShell Language
    #>

    [CmdletBinding()] 
    param(
        [Parameter( Mandatory = $true,
                Position = 0,
        ValueFromPipeline = $true )]
        [ValidateNotNullOrEmpty()]
        [psobject[]]$InputObject,

        [Parameter( Mandatory = $false,
        Position = 1)]
        [string]$TypeName,

        [Parameter( Mandatory = $false,
        Position = 2)]    
        [System.Collections.Hashtable]$PropertyToAdd,

        [Parameter( Mandatory = $false,
        Position = 3)]
        [ValidateNotNullOrEmpty()]
        [Alias('dp')]
        [System.String[]]$DefaultProperties,

        [boolean]$Passthru = $true
    )
    

    Begin
    {
         Write-Verbose -Message 'Adding details to custom object'
         
        if($PSBoundParameters.ContainsKey('DefaultProperties'))
        {
            # define a subset of properties
            $ddps = New-Object -TypeName System.Management.Automation.PSPropertySet -ArgumentList DefaultDisplayPropertySet, $DefaultProperties
            $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]$ddps
        }
    }
    Process
    {
        foreach($Object in $InputObject)
        {
            switch ($PSBoundParameters.Keys)
            {
                'PropertyToAdd'
                {
                    foreach($Key in $PropertyToAdd.Keys)
                    {
                        #Add some noteproperties. Slightly faster than Add-Member.
                        $Object.PSObject.Properties.Add( ( New-Object -TypeName System.Management.Automation.PSNoteProperty -ArgumentList ($Key, $PropertyToAdd[$Key]) ) )  
                    }
                }
                'TypeName'
                {
                    #Add specified type
                    [void]$Object.PSObject.TypeNames.Insert(0,$TypeName)
                }
                'DefaultProperties'
                {
                    # Attach default display property set
                    Add-Member -InputObject $Object -MemberType MemberSet -Name PSStandardMembers -Value $PSStandardMembers
                }
            }
            if($Passthru)
            {
                $Object
            }
        }
    }
}