Use-RoughDraftExtension.ps1

function Use-RoughDraftExtension
{
    <#
    .Synopsis
        Uses RoughDraftExtensions
    .Description
        Uses RoughDraft Extensions.

        This is used internally by extensible functions in a few ways:

        * To get -DynamicParameters associated with a -CommandName
        * To see which extensions -CanRun with a given -CommandName
        * To -Run a given extension
    .Example
        # Putting this dynamicParam block in a command adds all dynamic parameters from extensions that extend the command

        dynamicParam {
            $myCmd = $MyInvocation.MyCommand
            Use-RoughDraftExtension -CommandName $myCmd -DynamicParameter
        }
    .Link
        Get-RoughDraftExtension
    #>

    [OutputType([PSObject],[Management.Automation.RuntimeDefinedParameterDictionary])]
    [CmdletBinding(DefaultParameterSetName='DynamicParameter')]
    param(
    # The path to a rough draft extension
    [Parameter(ValueFromPipelineByPropertyName)]
    [ValidatePattern('\.(rd|RoughDraft)\.(extension|ext)\.ps1$')]
    [Alias('Source','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)]
    [Parameter(Mandatory,ParameterSetName='DynamicParameter',ValueFromPipelineByPropertyName)]
    [Parameter(Mandatory,ParameterSetName='CanRun',ValueFromPipelineByPropertyName)]
    [Parameter(Mandatory,ParameterSetName='Run',ValueFromPipelineByPropertyName)]
    [Alias('ThatExtends', 'For')]
    [string]
    $CommandName,

    # If set, will get dynamic parameters for all commands that match a given extension.
    [Parameter(Mandatory,ParameterSetName='DynamicParameter')]
    [Alias('DynamicParameters')]
    [switch]
    $DynamicParameter,

    # The parameters passed to a given
    [Parameter(ParameterSetName='CanRun',ValueFromPipelineByPropertyName)]
    [Parameter(ParameterSetName='Run',ValueFromPipelineByPropertyName)]
    [Collections.IDictionary]
    $ExtensionParameter = @{},

    # If set, will determine if an extension could run.
    [Parameter(Mandatory,ParameterSetName='CanRun')]
    [Alias('CouldRun')]
    [switch]
    $CanRun,

    # If set, will run an extension.
    [Parameter(Mandatory,ParameterSetName='Run')]
    [switch]
    $Run
    )

    process {
        $getExtensionSplat = @{
            ExtensionPath = $ExtensionPath
            Force = $Force -as [bool]
            CommandName = $CommandName
        }

        switch ($PSCmdlet.ParameterSetName) {
            CanRun {
                #region Determine if the Extension Can Run, given input
                foreach ($extensionCommand in Get-RoughDraftExtension @getExtensionSplat) {
                    if ($extensionCommand.InheritanceLevel -notin 'Inherited', 'NotInherited') { continue }
                    $couldRunIt = $extensionCommand.CouldRun($ExtensionParameter)
                    if (-not $couldRunIt) { continue }
                    [PSCustomObject]@{
                        ExtensionCommand = $extensionCommand
                        ExtensionPath = $extensionCommand.Source
                        CommandName = $CommandName
                        ExtensionParameter = $ExtensionParameter
                    }
                }
                #endregion Determine if the Extension Can Run, given input
            }
            DynamicParameter {
                #region Get Dynamic Parameters for the Extension Commands
                $allDynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new()
                $commandExtended = $ExecutionContext.SessionState.InvokeCommand.GetCommand($CommandName,'Function')
                foreach ($extensionCommand in Get-RoughDraftExtension @getExtensionSplat) {
                    if ($extensionCommand.Extends -notcontains $CommandName) { continue }
                    $extensionParams = $extensionCommand.GetDynamicParameters()
                    foreach ($kv in $extensionParams.GetEnumerator()) {
                        if (([Management.Automation.CommandMetaData]$commandExtended).Parameters.$($kv.Key)) {
                            continue
                        }
                        if ($allDynamicParameters.ContainsKey($kv.Key)) {
                            if ($kv.Value.ParameterType -ne $allDynamicParameters[$kv.Key].ParameterType) {
                                Write-Verbose "Extension '$extensionCommand' Parameter '$($kv.Key)' Type Conflict, making type PSObject"
                                $allDynamicParameters[$kv.Key].ParameterType = [PSObject]
                            }
                            foreach ($attr in $kv.Value.Attributes) {
                                if ($allDynamicParameters[$kv.Key].Attributes.Contains($attr)) {
                                    continue
                                }
                                $allDynamicParameters[$kv.Key].Attributes.Add($attr)
                            }
                        } else {
                            $allDynamicParameters[$kv.Key] = $kv.Value
                        }
                    }
                }
                return $allDynamicParameters
                #endregion Get Dynamic Parameters for the Extension Commands
            }
            Run {
                #region Run Extensions
                foreach ($extensionCommand in Get-RoughDraftExtension @getExtensionSplat) {
                    $extensionCommandParameters = [Ordered]@{}
                    foreach ($kv in $ExtensionParameter.getEnumerator()) {
                        if ($extensionCommand.Parameters[$kv.Key]) {
                            $extensionCommandParameters[$kv.Key] = $kv.Value
                        }
                    }
                    $extensionOutput = . $extensionCommand @extensionCommandParameters
                    $extensionOutputWrapper = [PSCustomObject][Ordered]@{
                        CommandName = $CommandName
                        ExtensionCommand = $extensionCommand
                        ExtensionOutput = $ExtensionOutput
                        Done = $ExecutionContext.InheritanceLevel -eq 'NotInherited'
                    }
                    $extensionOutputWrapper
                    if ($extensionOutputWrapper.Done) { break }
                }
                #endregion Run Extensions
            }
        }


    }
}