Get-RoughDraftExtension.ps1

function Get-RoughDraftExtension
{
    <#
    .Synopsis
        Gets RoughDraft Extensions
    .Description
        Gets RoughDraft Extensions.

        Extensions can be found in:
        * RoughDraft
        * Any module that includes 'RoughDraft' in it's tags.
        * The directory specified in -ExtensionPath
    .Example
        Get-RoughDraftExtension
    .Link
        Use-RoughDraftExtension
    #>

    [OutputType('RoughDraft.Extension')]
    param(
    # If provided, will look beneath a specific path for extensions.
    [Parameter(ValueFromPipelineByPropertyName)]
    [Alias('Fullname')]
    [string]
    $ExtensionPath,

    # If set, will clear caches of extensions, forcing a refresh.
    [switch]
    $Force,

    # If provided, will get extensions that extend a given command
    [Parameter(ValueFromPipelineByPropertyName)]
    [Alias('ThatExtends', 'For')]
    [string]
    $CommandName
    )

    begin {
        $extensionNameRegex = '\.(RoughDraft|rd)\.(extension|ext)\.ps1$'
        #region Define Inner Functions
        function ?.Extends {
            param(
            [Parameter(Position=0)]
            [string]
            $Command,

            [Parameter(ValueFromPipeline)]
            [PSObject]
            $ExtensionCommand
            )
            process {
                if ($Command -and $ExtensionCommand.Extends -contains $Command) {
                    return $ExtensionCommand
                }
                elseif (-not $command) {
                    return $ExtensionCommand
                }
            }

        }
        filter =>[RoughDraft.Extension] {
            $in = $_
            $extCmd =
                if ($in -is [Management.Automation.CommandInfo]) {
                    $in
                }
                elseif ($in -is [IO.FileInfo]) {
                    $ExecutionContext.SessionState.InvokeCommand.GetCommand($in.fullname, 'ExternalScript')
                }
                else {
                    $ExecutionContext.SessionState.InvokeCommand.GetCommand($in, 'Function,ExternalScript')
                }



            $isExtension = $false
            $extends     = @()
            foreach ($attr in $extCmd.ScriptBlock.Attributes) {
                if ($attr -is [Runtime.CompilerServices.ExtensionAttribute]) {
                    $isExtension = $true
                }
                if ($attr -is [Management.Automation.CmdletAttribute]) {

                    $extends +=
                        $ExecutionContext.SessionState.InvokeCommand.GetCommand($attr.VerbName + '-' + $attr.NounName, 'Function')
                }
            }

            if (-not $isExtension) { return }
            if (-not $extends) { return }
            Add-Member NoteProperty Extends $extends.Name -Force -InputObject $extCmd
            Add-Member NoteProperty ExtensionCommands $extends -Force -InputObject $extCmd
            $extCmd.pstypenames.clear()
            $extCmd.pstypenames.add('RoughDraft.Extension')
            $extCmd
        }
        #endregion Define Inner Functions

        #region Find Extensions
        $loadedModules = @(Get-Module)
        $myInv = $MyInvocation
        $myModuleName = $MyInvocation.MyCommand.Module.Name
        if ($myInv.MyCommand.Module -and $loadedModules -notcontains $myInv.MyCommand.Module) {
            $loadedModules = @($myInv.MyCommand.Module) + $loadedModules
        }
        $getCmd    = $ExecutionContext.SessionState.InvokeCommand.GetCommand

        if ($Force) {
            $script:RoughDraftExtensions = $null
            $script:RoughDraftExtensionsAtPath = $null
        }
        if (-not $script:RoughDraftExtensionsAtPath) {
            $script:RoughDraftExtensionsAtPath = @{}
        }
        if (-not $script:RoughDraftExtensions)
        {
            $script:RoughDraftExtensions =
                foreach ($loadedModule in $loadedModules) { # Walk over all modules.
                    if ( # If the module has PrivateData keyed to this module
                        $loadedModule.PrivateData.($myInv.MyCommand.Module.Name)
                    ) {
                        # Determine the root of the module with private data.
                        $thisModuleRoot = [IO.Path]::GetDirectoryName($loadedModule.Path)
                        # and get the extension data
                        $extensionData = $loadedModule.PrivateData.($myInv.MyCommand.Module.Name)
                        if ($extensionData -is [Hashtable]) { # If it was a hashtable
                            foreach ($ed in $extensionData.GetEnumerator()) { # walk each key

                                $extensionCmd =
                                    if ($ed.Value -like '*.ps1') { # If the key was a .ps1 file
                                        $getCmd.Invoke( # treat it as a relative path to the .ps1
                                            [IO.Path]::Combine($thisModuleRoot, $ed.Value),
                                            'ExternalScript'
                                        )
                                    } else { # Otherwise, treat it as the name of an exported command.
                                        $loadedModule.ExportedCommands[$ed.Value]
                                    }
                                if ($extensionCmd) { # If we've found a valid extension command
                                    $extensionCmd | =>[RoughDraft.Extension] # return it as an extension.
                                }
                            }
                        }
                    }
                    elseif ($loadedModule.PrivateData.Tags -contains $myModuleName -or $loadedModule.Name -eq $myModuleName) {
                        $loadedModule |
                            Split-Path |
                            Get-ChildItem -Recurse |
                            Where-Object Name -Match $extensionNameRegex |
                            =>[RoughDraft.Extension]
                    }
                }
        }
        #endregion Find Extensions
    }

    process {
        if ($ExtensionPath) {
            Get-ChildItem -Recurse -Path $ExtensionPath |
                Where-Object Name -Match $extensionNameRegex |
                =>[RoughDraft.Extension] |
                ?.Extends $CommandName
        } else {
            $script:RoughDraftExtensions | ?.Extends $CommandName
        }
    }
}