Retrieve synopsis and help URLs for all PowerShell cmdlets/functions in your Modules

Sometimes you search for cmdlets in your Modules and don’t know what they do. You can use Get-Help *something* to find them and Get-Help afterward for more information on those results. That or using Google for more information… In this blog post, I will show you a way to create a report with all that information in one overview 🙂

What does the script do?

The script searches all your PowerShell modules, extracts the synopsis (Brief description of what the cmdlet or Function does), and tries finding the URL with more information from within the module. (Sadly, that information is not always available, URLs are not always there, and sometimes there’s no clear synopsis)

When done, it exports it to a CSV of XLSX file (Whatever your preference is). You can keep that file to browse and search it, and I use it to scroll through the new Microsoft Graph cmdlets 🙂 (And those are a lot)

Running the script

After starting the script, it will prompt for an output file. (The filename has to end with .csv or .xlsx) You can use the -Output parameter to specify it, like in the example below:

.\Get-CmdletsAndFunctions.ps1 -Output c:\temp\cmdlets.xlsx

And then… You will have to wait… It took about an hour on my machine for a long time 🙂 (Depending on the number of modules you have) I think it took about an hour on my machine… The output on your screen will show the current module being processed (In green) and the cmdlets/functions found in it (In grey). It will also tell the amount it has processed to give you an idea of how many are left…

When it’s done, the Excel output will look like this:

Note: My Excel sheet had 12493 rows for the 282 modules that it found

The script

Below are the contents of the Get-CmdletsAndFunctions.ps1 script. Save it somewhere locally and run it to get your overview of cmdlets and functions which you can use on your system.

param(
    [parameter(Mandatory = $true)][string]$Output
)
#Exit if incorrect extension was used
if (($Output.EndsWith('.csv') -ne $true) -and ($Output.EndsWith('.xlsx') -ne $true)) {
    Write-Warning ("Specified file {0} does not have the .csv or .xlsx extension. Exiting..." -f $Output)
    return
}

#Create list of available modules, loop through them and get the cmdlets and functions
$modules = Get-Module -ListAvailable | Select-Object -Unique | Sort-Object Name
if ($modules.count -gt 0) {
    $modulecounter = 1
    $total = foreach ($module in $modules) {
        Write-Host ("[{0}/{1}] Processing module {2}" -f $modulecounter, $modules.count, $module.name) -ForegroundColor Green
        $cmdlets = Get-Command -module $module.Name | Sort-Object Name
        $cmdletcounter = 1
        foreach ($cmdlet in $cmdlets) {
            Write-Host ("`t [{0}/{1}] Processing cmdlet/function {2}" -f $cmdletcounter, $cmdlets.count, $cmdlet.name)
            #Retrieve Synopsis (Remove Read-Only, Read-Wite, Nullable and Supports $expand if found) and URL for the cmdlet/function
            $help = Get-Help $cmdlet
            $synopsis = $help.Synopsis.replace('Read-only.', '').replace('Read-Write.', '').replace('Nullable.', '').replace('Supports $expand.', '').replace('Not nullable.', '').replace('\r', " ")
            $synopsis = $synopsis -replace '\n', ' ' -creplace '(?m)^\s*\r?\n', ''
            #Set variable for non matching cmdlet name and synopsis content
            $url = $help.relatedLinks.navigationLink.uri
            #Set Synopsis or URL to "Not Available" when no data is found
            if ($null -eq $synopsis -or $synopsis.Length -le 2 -or $synopsis -match $cmdlet.Name) { $synopsis = "Not available" }
            if ($null -eq $url -or -not $url.Contains('https')) { $url = "Not available" }
            [PSCustomObject]@{
                Source   = $cmdlet.Source
                Version  = $cmdlet.Version
                Cmdlet   = $cmdlet.Name
                Synopsis = $synopsis
                URL      = $url
            }
            $cmdletcounter++
        }
        $modulecounter++
    }
}
else {
    Write-Warning ("No modules found to process? Check permissions. Exiting...")
    return
}

if ($total.count -gt 0) {

    #Output to .csv or .xlsx file
    if ($Output.EndsWith('.csv')) {
        try {
            New-Item -Path $Output -ItemType File -Force:$true -Confirm:$false -ErrorAction Stop | Out-Null
            $total | Sort-Object Source, Version, Cmdlet | Export-Csv -Path $Output -Encoding UTF8 -Delimiter ';' -NoTypeInformation
            Write-Host ("`nExported results to {0}" -f $Output) -ForegroundColor Green
        }
        catch {
            Write-Warning ("`nCould not export results to {0}, check path and permissions" -f $Output)
            return
        }
    }

    if ($Output.EndsWith('.xlsx')) {
        try {
            #Test path and remove empty file afterwards because xlsx is corrupted if not
            New-Item -Path $Output -ItemType File -Force:$true -Confirm:$false -ErrorAction Stop | Out-Null
            Remove-Item -Path $Output -Force:$true -Confirm:$false | Out-Null
    
            #Install ImportExcel module if needed
            if (-not (Get-Module -Name importexcel -ListAvailable)) {
                Write-Warning ("`nImportExcel PowerShell Module was not found, installing...")
                Install-Module ImportExcel -Scope CurrentUser -Force:$true
                Import-Module ImportExcel
            }
            Import-Module ImportExcel
            $total | Sort-Object Source, Version, Cmdlet | Export-Excel -AutoSize -BoldTopRow -FreezeTopRow -AutoFilter -Path $Output
            Write-Host ("`nExported results to {0}" -f $Output) -ForegroundColor Green
        }
        catch {
            Write-Warning ("`nCould not export results to {0}, check path and permissions" -f $Output)
            return
        }
    }
}

Download the script(s) from GitHub here

2 thoughts on “Retrieve synopsis and help URLs for all PowerShell cmdlets/functions in your Modules

  1. hello harms,

    My feedback on testing your script.

    Indeed it is long to run (5616 cmdlets)
    You constructed your $Total variable as an Array. I wonder in the present case (large collection of objects) if using a [System.collection.generic.list[PsObject]] wouldn’t be faster. Additionally, you could use its .add() method. Luckily you built your Array outside the loop :-).

    Some errors encountered (always the same) Example: Processing cmdlet/function Set-RDLicenseConfiguration
    Get-Help: Type [uint8] not found.

    Note that the size of the Powershell instance did increase during and after processing, probably because of the $Total variable which was stored in memory. Perhaps feeding the .xslx file with an -Append over time would decrease this memory consumption.

    However, it is still a good big job
    Cordially

    • I think I do need to test some other options to see which is faster… And not all the cmdlets returned information 🙁 And yes, 4Gb of RAM which I could not clear with garbage collection statement (or simply by setting $total to $null)

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.