functions/Get-ModuleCommand.ps1

Function Get-ModuleCommand {
    [cmdletbinding(DefaultParameterSetName = "name")]
    [Alias("gmc")]
    [OutputType("ModuleCommand")]

    Param(
        [Parameter(
            Position = 0,
            Mandatory,
            HelpMessage = "The name of an installed module",
            ParameterSetName = "name",
            ValueFromPipelineByPropertyName
        )]
        [ValidateNotNullOrEmpty()]
        [string]$Name,

        [Parameter(
            Mandatory,
            HelpMessage = "The fully qualified name of an installed module",
            ParameterSetName = "fqdn"
        )]
        [ValidateNotNullOrEmpty()]
        [Microsoft.PowerShell.Commands.ModuleSpecification]$FullyQualifiedName,

        [switch]$ListAvailable
    )

    Begin {
        Write-Verbose "Starting $($MyInvocation.MyCommand)"
        $PSBoundParameters.Add("ErrorAction", "stop")
    }

    Process {
        #getting commands directly from the module because for some unknown reason,
        #probably scope related, when using Get-Command alone to list commands in the module,
        #it includes private functions

        Try {
            Write-Verbose "Listing all matching modules"
            Write-Verbose "Using bound parameters"
            $PSBoundParameters | Out-String | Write-Verbose

            #get newest version of the module
            $mod = Get-Module @PSBoundParameters | Select-Object -First 1
            Write-Verbose "Found $($mod.count) modules"
            if (-not $mod) {
                Throw "Failed to find a matching module. Try again using the -ListAvailable parameter."
            }
            #get prerelease from private data
            if ($mod.PrivateData -and $mod.PrivateData.ContainsKey('PSData') -and $mod.PrivateData.PSData.ContainsKey('PreRelease')) {
                $prerelease = $mod.PrivateData.PSData.PreRelease
            }
            else {
                $prerelease = $null
            }
        } #try
        Catch {
            Write-Verbose "This is weird. There was an exception!"
            Throw $_
            #Bail out
            return
        }

        if ($PSCmdlet.parameterSetName -eq 'name' -AND $mod.count -gt 1) {
            #make sure to get the latest version
            Write-Verbose "Getting the latest version of $($mod[0].name)"
            $mod = $mod | Sort-Object -Property Version -Descending | Select-Object -First 1
        }

        Write-Verbose "Using version $($mod.version)"

        $cmds = @()
        Write-Verbose "Getting exported functions"
        $cmds += $mod.ExportedFunctions.keys | Get-Command
        Write-Verbose "Getting exported cmdlets"
        $cmds += $mod.ExportedCmdlets.keys | Get-Command

        Write-Verbose "Found $($cmds.count) functions and/or cmdlets"

        $out = foreach ($cmd in $cmds) {
            Write-Verbose "Processing $($cmd.name)"
            #get aliases, ignoring errors for those commands without one
            $alias = (Get-Alias -Definition $cmd.Name -ErrorAction SilentlyContinue).name

            #it is assumed you have updated help
            [PSCustomObject]@{
                PSTypeName = "ModuleCommand"
                Name       = $cmd.name
                Alias      = $alias
                Verb       = $cmd.verb
                Noun       = $cmd.noun
                Synopsis   = (Get-Help $cmd.name).synopsis.trim()
                Type       = $cmd.CommandType
                Version    = $cmd.version
                Help       = $cmd.HelpUri
                ModuleName = $mod.name
                Compatible = $mod.CompatiblePSEditions
                PSVersion  = $mod.PowerShellVersion
            }
        } #foreach cmd

    #display results sorted by name for better formatting
    $out | Sort-Object -Property Name
}
End {
    Write-Verbose "Ending $($MyInvocation.MyCommand)"
}

} #close function

Register-ArgumentCompleter -CommandName Get-ModuleCommand -ParameterName Name -ScriptBlock {
    param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)

    (Get-Module -Name "$WordToComplete*").name |
    ForEach-Object {
        [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
    }
}