Private/Add-ObjectDetail.ps1

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
 
        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
 
    .INPUTS
        System.Management.Automation.PSObject[]
 
    .INPUTS
        System.Management.Automation.PSObject
 
    .NOTES
        - Troy Lindsay
        - Twitter: @troylindsay42
        - GitHub: tlindsay42
 
    .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-Object -Property '*'
 
            # First Last Account AnotherProperty
            # ----- ---- ------- ---------------
            # Cookie Monster CMonster 5
 
    .LINK
        https://tlindsay42.github.io/PSRyver/Private/Add-ObjectDetail/
 
    .LINK
        https://github.com/tlindsay42/PSRyver/blob/master/PSRyver/Private/Add-ObjectDetail.ps1
 
    .LINK
        http://ramblingcookiemonster.github.io/Decorating-Objects/
 
    .LINK
        http://blogs.microsoft.co.il/scriptfanatic/2012/04/13/custom-objects-default-display-in-powershell-30/
 
    .FUNCTIONALITY
        PowerShell Language
    #>

    [CmdletBinding(
        HelpUri = 'https://tlindsay42.github.io/PSRyver/Private/Add-ObjectDetail/'
    )]
    [OutputType( [Void] )]
    [OutputType( [PSObject] )]
    [OutputType( [PSObject[]] )]
    param (
        # Specifies the object(s) to decorate.
        [Parameter(
            Mandatory = $true,
            Position = 0,
            ValueFromPipeline = $true
        )]
        [ValidateNotNullOrEmpty()]
        [PSObject[]]
        $InputObject,

        <#
        Typename to insert. This will show up when you use Get-Member against the
        resulting object.
        #>

        [Parameter( Position = 1 )]
        [String]
        $TypeName,

        <#
        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( Position = 2 )]
        [Hashtable]
        $PropertyToAdd = @{},

        # Change the default properties that show up
        [Parameter( Position = 3 )]
        [ValidateNotNullOrEmpty()]
        [Alias( 'dp' )]
        [String[]]
        $DefaultProperties = @(),

        # Whether to pass the resulting object on.
        [Parameter( Position = 4 )]
        [Boolean]
        $PassThru = $true
    )

    begin {
        $function = $MyInvocation.MyCommand.Name

        Write-Verbose -Message (
            "Beginning: '${function}' with ParameterSetName '$( $PSCmdlet.ParameterSetName )' and Parameters: " +
            ( $PSBoundParameters | Remove-SensitiveData | Format-Table -AutoSize | Out-String )
        )

        if ( $PSBoundParameters.ContainsKey( 'DefaultProperties' ) ) {
            # define a subset of properties
            $splat = @{
                TypeName     = 'System.Management.Automation.PSPropertySet'
                ArgumentList = 'DefaultDisplayPropertySet', $DefaultProperties
            }
            $ddps = New-Object @splat
            $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.
                        $splat = @{
                            TypeName     = 'System.Management.Automation.PSNoteProperty'
                            ArgumentList = $key, $PropertyToAdd[$key]
                        }
                        $object.PSObject.Properties.Add( ( New-Object @splat ) )
                    }
                }

                'TypeName' {
                    #Add specified type
                    [Void] $object.PSObject.TypeNames.Insert( 0, $TypeName )
                }

                'DefaultProperties' {
                    # Attach default display property set
                    $splat = @{
                        InputObject = $object
                        MemberType  = 'MemberSet'
                        Name        = 'PSStandardMembers'
                        Value       = $PSStandardMembers
                    }
                    Add-Member @splat
                }
            }

            if ( $PassThru ) {
                $object
            }
        }
    }

    end {
        Write-Verbose -Message "Ending: '${function}'."
    }
}