TypeAccelerators.psm1

Function Get-TypeAccelerator {
    <#
    .SYNOPSIS
    Gets Type Accelerators in the PowerShell Session
    .DESCRIPTION
    Get-TypeAccelerator gets the type accelerators of the current PowerShell session. It can also get indvidual accelerators using either the name of the accelerator or the type it references.
    
    There is a behavior to make note of when passing the type to the Type parameter:
    A type object can be piped in as a literal (surrounded by []), but cannot be supplied to the Type parameter as a literal. Instead, a string must be passed or cast to a type object before passing (using parentheses). This behavior does not affect input when the type is previously stored in a variable. See the examples for additional clarification.
    .PARAMETER Type
    The type to get from the type accelerators.
    .PARAMETER Name
    The name of the type accelerator to get.
    .INPUTS
    System.RuntimeType
    You can pipe System.RuntimeType objects to Add-TypeAccelerator
 
    System.String
    You can pipe type names as System.String to be converted to System.Type
    .OUTPUTS
    System.Collections.Generic.KeyValuePair[[System.String],[System.Type]]
    .EXAMPLE
    Get-TypeAccelerator
 
    This command will output all type accelerators in the PowerShell session.
    .EXAMPLE
    [System.Collections.ArrayList] | Get-TypeAccelerator
 
    This command will get any type accelerator that references the ArrayList type. Note the use of square brackests.
    .EXAMPLE
    Get-TypeAccelerator -Type System.Collections.ArrayList
 
    This command will get any type accelerator that references the ArrayList type. Note the lack of square brackests.
    .EXAMPLE
    Get-TypeAccelerator -Name AList
 
    This command will get any type acclerator with the name AList.
    .NOTES
    This script is based on the funciton found at http://poshcode.org/1869, but had to be updated to accomodate a change made in PowerShell 3.0/4.0.
 
    Author: Chris Carter
    Version: 1.2
 
    .LINK
    http://poshcode.org/1869
    #>


    #Requires -Version 2.0
    [CmdletBinding(DefaultParameterSetName="Name")]

    Param(
        [Parameter(Position=0,ValueFromPipeline=$true,ParameterSetName="Name")]
            [String[]]$Name,

        [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="Type")]
            [Type[]]$Type
    )

    Process {
        $Collection = $Name, $Type | Where-Object {$_}
       
        if ($Collection) {
            foreach ($object in $Collection) {
                $aClone = New-Object TADict -ArgumentList $accel::Get
                try {
                    #Test to exclude accelerator names from being cast to type
                    if (!$accel::Get.ContainsKey($object)) {
                        $object = [Type]$object
                    }
                } catch {}

                if ($object -is [Type]) {
                    $output = $aClone.GetEnumerator() | Where-Object {$_.Value -eq $object}
                }
                elseif ($object -is [String]) {
                    $output = $aClone.GetEnumerator() | Where-Object {$_.Key -eq $object}
                }

                foreach ($o in $output) {
                    $o.PSObject.TypeNames.Insert(0, 'TypeAccelerator.KeyValuePair')
                    $o
                }
            }
        }
        else {
            $kvPairs = (New-Object TADict -ArgumentList $accel::Get).GetEnumerator()
            foreach ($pair in $kvPairs) {
                $pair.PSObject.TypeNames.Insert(0, 'TypeAccelerator.KeyValuePair')
                $pair
            }
        }
    }
}

Function Add-TypeAccelerator {
    <#
    .SYNOPSIS
    Adds type accelerators to the PowerShell session
    .DESCRIPTION
    Add-TypeAccelerator adds type accelerators to the the PowerShell session to allow shortening of longer type names, such as [switch] for [System.Management.Automation.SwitchParameter].
 
    The Type parameter will accept Type objects, strings of the type's full name, and hashtables with the desired accelerator name as the key and the type (as a string of the full name or the type object itself) as the value.
    
    The Name parameter, by default, is matched to the Name property on type objects or the Name key in a hashtable.
 
    When piping a hashtable, it is best to use the hashtable's GetEnumerator() method so the objects in the hashtable are actually sent in serial
    
    There is a behavior to make note of when passing the type to the Type parameter:
    A type object can be piped in as a literal (surrounded by []), but cannot be supplied to the Type parameter as a literal. Instead, a string must be passed or cast to a type object before passing (using parentheses). This behavior does not affect input when the type is previously stored in a variable. See the examples for additional clarification.
    .PARAMETER Type
    The type to create an accelerator for. Only use the surrounding square brackets in pipeline input. See the examples.
    .PARAMETER Name
    The name of the accelerator to use between square brackets. By default, this will be taken from the type object's Name property.
    .PARAMETER PassThru
    Causes the command to output the KeyValuePair object representing the added type accelerator.
    .INPUTS
    System.Type
    You can pipe System.Type objects to Add-TypeAccelerator
 
    System.String
    You can pipe type names as System.String to be converted to System.Type
 
    System.Collections.Hashtable
    You can pipe hashtables in the format of @{<AcceleratorName> = <Type to reference>}
    .OUTPUTS
    None or System.Collections.Generic.KeyValuePair[[String],[Type]]
    Using the PassThru parameter, Add-TypeAccelerator returns a KeyValuePair object that represents the new type accelerator entry. Otherwise, there is no output.
    .EXAMPLE
    'System.Collections.BitArray' | Add-TypeAccelerator
 
    This command will add the accelerator [BitArray] to the session for the type [System.Collections.BitArray]. The Name for the accelerator comes from the type objects's Name property.
    .EXAMPLE
    Add-TypeAccelerator -Name AL -Type System.Collections.ArrayList
 
    This command will add the accelerator [AL] to the session for the type [System.Collections.ArrayList]. Note the lack of square brackets surrounding the type.
    .EXAMPLE
    [System.Collections.ArrayList] | Add-TypeAccelerator
 
    This command will add the accelerator [ArrayList] to the session for the type [System.Collections.ArrayList]. Note the use of square brackets surrounding the type.
    .EXAMPLE
    @{AList=[System.Collectons.ArrayList]; BitA='System.Collections.BitArray'} | Add-TypeAccelerator
 
    This command will add the accelerators [AList] and [BitA] to the session for the types [System.Collections.ArrayList] and System.Collections.BitArray, respectively.
    .NOTES
    This script is based on the funciton found at http://poshcode.org/1869, but had to be updated to accomodate a change made in PowerShell 3.0/4.0.
 
    Author: Chris Carter
    Version: 1.6
 
    .LINK
    http://poshcode.org/1869
    #>


    #Requires -Version 2.0
    [CmdletBinding(SupportsShouldProcess=$true)]

    Param(
        [Parameter(Position=0,ValueFromPipelineByPropertyName=$true,ParameterSetName="TypeOrString")]
            [String]$Name,

        [Parameter(Mandatory=$true,Position=1,ValueFromPipeline=$true,ParameterSetName="TypeOrString")]
            [Object[]]$Type,

        [Switch]$PassThru
    )

    Begin {
        Function WarnFor-CurrentReference ($AcceleratorName, $AcceleratorType) {
            $warnTitle = "Warning: Accelerator [$AcceleratorName] Already Exists"
            $warnMessage = "[$AcceleratorName] already exists and references type [$($accel::Get[$AcceleratorName].FullName)]. Proceeding will overwrite the current reference to [$($AcceleratorType.FullName)].`nDo you want to proceed?"
            $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Overwrites the current accelerator reference with the new reference."
            $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Leaves the current accelerator reference in place."
            $choices = [System.Management.Automation.Host.ChoiceDescription[]]($yes,$no)
        
            $host.UI.PromptForChoice($warnTitle, $warnMessage, $choices, 1)
        }

        Function PSv5Patch {
            $builtinField = $accel.GetField("builtinTypeAccelerators", [System.Reflection.BindingFlags]"Static,NonPublic")
            $builtinField.SetValue($builtinField, $accel::Get)
        }

        Function Add-TypeAccelerator ($Name, $Type) {
            $keepIntact = 0

            switch ($true) {
                {$Type -is [System.Collections.DictionaryEntry]} {$Name = $Type.Name; $Type = $Type.Value}
                {$Type -is [String]}    {$Type = [Type]$Type}
                {!$Name}                {$Name = $Type.Name}
        
                {$accel::Get.Keys -contains $Name} {$keepIntact = WarnFor-CurrentReference $Name $Type}

                {!$keepIntact} {if ($PSCmdlet.ShouldProcess("$($Type.FullName)", "Add [$Name] accelerator")) {
                                    $accel::Add($Name, $Type)
                                    if ($PSVersionTable.PSVersion.Major -eq 5) {PSv5Patch}  
                                }}
            }
            if ($PassThru) {Get-TypeAccelerator -Name $Name;}
        }
    }

    Process {
        foreach($rt in $Type) {

            if ($rt -is [Hashtable]) {
                foreach ($object in $rt.GetEnumerator()) {
                    Add-TypeAccelerator -Type $object
                }
            }
            else {Add-TypeAccelerator $Name $rt}
        }
    }
}

Function Remove-TypeAccelerator {
    <#
    .SYNOPSIS
       Removes type accelerators from the PowerShell session.
    .DESCRIPTION
       Remove-TypeAccelerator removes type accelerators from the the PowerShell session. Type accelerators are shortened names for types, such as [switch] for [System.Management.Automation.SwitchParameter].
 
       Either the name of an accelerator (without brackets) or types referenced by accelerators may be piped in.
 
       If a type has multiple accelerators, passing that type will remove all of its accelerators.
    
       There is a behavior to make note of when passing the type to the Type parameter:
       If the type is piped in it must be surrounded by square brackets, but if supplied by name or position, it cannot be surrounded by square brackets. This behvior does not affect input when the type is previously stored in a variable. See the examples for additional clarification.
    .PARAMETER Name
        The name of the accelerator to remove without the squre brackets.
    .PARAMETER Type
        The type whose acclerators will be removed. Only use the surrounding square brackets in pipeline input. See the examples.
    .PARAMETER InputObject
        This parameter is used in the pipeline when accepting objects from other commands in the module.
    .INPUTS
        System.Type
        You can pipe System.Type to Remove-TypeAccelerator
 
        System.String
        You can pipe System.String to Remove-TypeAccelerator.
    .OUTPUTS
        None
        Remove-TypeAccelerator does not produce any output.
    .EXAMPLE
        Remove-TypeAccelerator -Name ArrayList
 
        This command will remove the accelerator [ArrayList] from the session for the type [System.Collections.ArrayList].
    .EXAMPLE
        [System.Collections.ArrayList] | Remove-TypeAccelerator
 
        This command will remove the accelerator [ArrayList] from the session for the type [System.Collections.ArrayList]. Note the use of square brackets surrounding the type.
    .NOTES
        This script is based on the funciton found at http://poshcode.org/1869, but had to be updated to accomodate a change made in PowerShell 3.0/4.0.
 
    Author: Chris Carter
    Version: 1.5
 
    .LINK
    http://poshcode.org/1869
    #>


    #Requires -Version 2.0
    [CmdletBinding(SupportsShouldProcess=$true,DefaultParameterSetName="Name")]

    Param(
        [Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$true,ParameterSetName="Name")]
            [String[]]$Name,

        [Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$true,ParameterSetName="Type")]
            [Type[]]$Type,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="KeyValue")]
            [System.Collections.Generic.KeyValuePair[String,Type]]$InputObject
    )

    Process {
        $Collection = $Name, $Type, $InputObject | Where-Object {$_}
        foreach ($object in $Collection) {
            $hits = @()
            if ($object -is [KVPair]) {
                $hits += $object
            }
            else {$hits += Get-TypeAccelerator $object}
            $result = $hits | ForEach-Object {
                if ($PSCmdlet.ShouldProcess("System.Management.Automation.TypeAccelerators", "Remove [$($_.Key)] accelerator")) {
                    $accel::Remove($_.Key)
                }
            }
        }
    }
}

Function Rename-TypeAccelerator {
    <#
    .SYNOPSIS
       Renames type accelerators in the PowerShell session.
    .DESCRIPTION
       Rename-TypeAccelerator renames type accelerators in the the PowerShell session. Type accelerators are shortened names for types, such as [switch] for [System.Management.Automation.SwitchParameter].
 
       Either the name of an accelerator (without brackets) or a KeyValuePair object representing its entry in the type accelerators dictionary may be piped in.
 
       A scriptblock may be passed to the NewName parameter while in the pipeline to rename multiple accelerators using the -replace operator. See the examples for details.
    
       There is a behavior to make note of when passing the type to the Type parameter:
       If the type is piped in it must be surrounded by square brackets, but if supplied by name or position, it cannot be surrounded by square brackets. This behvior does not affect input when the type is previously stored in a variable. See the examples for additional clarification.
    .PARAMETER Name
        The name of the accelerator to rename without the squre brackets.
    .PARAMETER InputObject
        This parameter is used in the pipeline when accepting objects from other commands in the module.
    .PARAMETER PassThru
        Causes the command to output an object representing the renamed entry in the type accelerators dictionary
    .INPUTS
        System.Collections.Generic.KeyValuePair[String,Type]
        You can pipe KeyValuePair object to Rename-TypeAccelerator that represent the accelerators entry in the dictionary.
 
        System.String
        You can pipe String objects representing the name of a type accelerator (without bracketss) to Rename-TypeAccelerator.
    .OUTPUTS
        None or a KeyValuePair object representing the renamed type accelerator dictionary entry.
    .EXAMPLE
        Rename-TypeAccelerator -Name List -NewName AList
 
        This command will rename the accelerator [List] to [Alist]].
    .EXAMPLE
        Get-TypeAccelerator List | Rename-TypeAccelerator -NewName Alist
 
        This command will rename the retrieve the entry for [List] then pipe it to Rename-TypeAccelerator to be renamed to [AList]
    .EXAMPLE
        $NamesOfAccelerators | Rename-TypeAccelerator -NewName {$_ -replace '^', 'PS'}
 
        This command will rename all of the accelerators with names that are stored in the variable by inserting the characters 'PS' at the beginning of each name.
    .EXAMPLE
        Get-TypeAccelerator System.Collections.ArrayList | Rename-TypeAccelerator -NewName {$_.Key -replace '^', 'AL'}
 
        This command will rename all of the accelerators that reference the ArrayList class by inserting the characters 'AL' at the begnning of each name.
    .NOTES
        This script is based on the funciton found at http://poshcode.org/1869, but had to be updated to accomodate a change made in PowerShell 3.0/4.0.
 
    Author: Chris Carter
    Version: 1.0
 
    .LINK
    http://poshcode.org/1869
    #>


    #Requires -Version 2.0
    [CmdletBinding(SupportsShouldProcess=$true,DefaultParameterSetName="Name")]

    Param(
        [Parameter(Mandatory=$true,Position=0,ParameterSetName="Name")]
            [String]$Name,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="KeyValue")]
            [Object]$InputObject,

        [Parameter(Mandatory=$true,Position=1,ParameterSetName="Name")]
        [Parameter(Mandatory=$true,Position=0,ParameterSetName="KeyValue")]
            [String]$NewName,

        [Switch]$PassThru
    )

    Begin {
        if ($NewName -match '.*\s-replace\s.*') {
            try {
                $scriptblock = [Scriptblock]::Create($NewName)
                if ($PSCmdlet.ParameterSetName -eq 'Name') {
                    Write-Error "A scriptblock is only accepted in the pipeline."
                    exit
                }
            }
            catch {Write-Error $_; exit}
        }
    }

    Process {
        $object = $Name, $InputObject | Where-Object {$_}
        
        if ($scriptblock) {
            try {$NewName = & $scriptblock}
            catch {Write-Error $_; continue}
        }

        if ($object -is [KVPair] -or $object -is [String]) {
            if ($object -is [String]) {
                $object = Get-TypeAccelerator $object
                if (!$object) {continue}
            }
            
            if ($PSCmdlet.ShouldProcess("System.Management.Automation.TypeAccelerators", "Rename [$($_.Key)] accelerator to [$NewName]")) {
                Add-TypeAccelerator -Name $NewName -Type $object.Value -PassThru:$PassThru -Confirm:$false
                if ($accel::Get[$NewName]) {
                    Remove-TypeAccelerator -Name $object.Key -Confirm:$false
                }
            }
        }
        else {Write-Error "The value passed in the pipeline is not a KeyValuePair or String object"}
    }
}

$accel = [PowerShell].Assembly.GetType("System.Management.Automation.TypeAccelerators")
$accel::Add('TADict','System.Collections.Generic.Dictionary[String,Type]')
$accel::Add('KVPair','System.Collections.Generic.KeyValuePair[String,Type]')

$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = {
    [void]$accel::Remove('TADict')
    [void]$accel::Remove('KVPair')
}

New-Alias -Name gta -Value Get-TypeAccelerator
New-Alias -Name ata -Value Add-TypeAccelerator
New-Alias -Name rta -Value Remove-TypeAccelerator
New-Alias -Name rnta -Value Rename-TypeAccelerator