Save-MarkdownHelp.ps1

function Save-MarkdownHelp
{
    <#
    .Synopsis
        Saves a Module's Markdown Help
    .Description
        Get markdown help for each command in a module and saves it to the appropriate location.
    .Link
        Get-MarkdownHelp
    .Example
        Save-MarkdownHelp -Module HelpOut # Save Markdown to HelpOut/docs
    .Example
        Save-MarkdownHelp -Module HelpOut -Wiki # Save Markdown to ../HelpOut.wiki
    #>

    param(
    # The name of one or more modules.
    [Parameter(ParameterSetName='ByModule',ValueFromPipelineByPropertyName=$true)]
    [string[]]
    $Module,

    # The output path.
    # If not provided, will be assumed to be the "docs" folder of a given module (unless -Wiki is specified)
    [Parameter(ValueFromPipelineByPropertyName)]
    [string]
    $OutputPath,

    # If set, will interlink documentation as if it were a wiki. Implied when -OutputPath contains 'wiki'.
    # If provided without -OutputPath, will assume that a wiki resides in a sibling directory of the module.
    [Parameter(ValueFromPipelineByPropertyName)]
    [switch]
    $Wiki,

    # If provided, will generate documentation for any scripts found within these paths.
    # -ScriptPath can be either a file name or a full path.
    # If an exact match is not found -ScriptPath will also check to see if there is a wildcard match.
    [Parameter(ValueFromPipelineByPropertyName)]
    [string[]]
    $ScriptPath,

    # If provided, will replace parts of the names of the scripts discovered in a -ScriptDirectory beneath a module.
    [Parameter(ValueFromPipelineByPropertyName)]
    [string[]]
    $ReplaceScriptName,

    # If provided, will replace parts of the names of the scripts discovered in a -ScriptDirectory beneath a module with a given Regex replacement.
    [Parameter(ValueFromPipelineByPropertyName)]
    [string[]]
    $ReplaceScriptNameWith,

    # If set, will output changed or created files.
    [switch]
    $PassThru,

    # The order of the sections. If not provided, this will be the order they are defined in the formatter.
    [Parameter(ValueFromPipelineByPropertyName)]
    [string[]]
    $SectionOrder,

    # One or more topic files to include.
    # Topic files will be treated as markdown and directly copied inline.
    # By default ```\.help\.txt$``` and ```\.md$```
    [Parameter(ValueFromPipelineByPropertyName)]
    [string[]]
    $IncludeTopic = @('\.help\.txt$', '\.md$'),

    # If set, will not enumerate valid values and enums of parameters.
    [Parameter(ValueFromPipelineByPropertyName)]
    [switch]
    $NoValidValueEnumeration,

    # A list of command types to skip.
    # If not provided, all types of commands from the module will be saved as a markdown document.
    [Parameter(ValueFromPipelineByPropertyName)]
    [Alias('SkipCommandTypes','OmitCommandType','OmitCommandTypes')]
    [Management.Automation.CommandTypes[]]
    $SkipCommandType
    )

    begin {
        # First, let's cache a reference to Get-MarkdownHelp
        $GetMarkdownHelp = 
            if ($MyInvocation.MyCommand.ScriptBlock.Module) {
                $MyInvocation.MyCommand.ScriptBlock.Module.ExportedCommands['Get-MarkdownHelp']
            } else {
                $ExecutionContext.SessionState.InvokeCommand.GetCommand('Get-MarkdownHelp', 'Function')
            }
    }

    process {        
        $getMarkdownHelpSplatBase = @{}
        if ($SectionOrder) {
            $getMarkdownHelpSplatBase.SectionOrder =$SectionOrder
        }
        if ($NoValidValueEnumeration) {
            $getMarkdownHelpSplatBase.NoValidValueEnumeration =$true
        }
        #region Save the Markdowns
        foreach ($m in $Module) { # Walk thru the list of module names.
            if ($t -gt 1) {
                $c++
                Write-Progress 'Saving Markdown' $m -PercentComplete $p  -Id $id
            }

            $theModule = Get-Module $m # Find the module
            if (-not $theModule) { continue } # (continue if we couldn't).
            $theModuleRoot = $theModule | Split-Path # Find the module's root,
            if (-not $psBoundParameters.OutputPath) {                
                $OutputPath = 
                    if ($Wiki) {
                        Split-Path $theModuleRoot | Join-Path -ChildPath "$($theModule.Name).wiki"
                    } else {
                        Join-Path $theModuleRoot "docs"                        
                    }                
            }
            
            if (-not (Test-Path $OutputPath)) {
                $null = New-Item -ItemType Directory -Path $OutputPath
            }

            $outputPathItem = Get-Item $OutputPath
            if ($outputPathItem -isnot [IO.DirectoryInfo]) {
                Write-Error "-OutputPath '$outputPath' must point to a directory"
                return
            }

            $myHelpParams = @{}
            if ($wiki) { $myHelpParams.Wiki = $true}
            else { $myHelpParams.GitHubDocRoot = $OutputPath | Split-Path}            

            foreach ($cmd in $theModule.ExportedCommands.Values) {
                $docOutputPath = Join-Path $outputPath ($cmd.Name + '.md')
                if ($SkipCommandType -and $SkipCommandType -contains $cmd.CommandType) {
                    continue
                }
                $getMarkdownHelpSplat = @{Name="$cmd"} + $getMarkdownHelpSplatBase
                if ($Wiki) { $getMarkdownHelpSplat.Wiki = $Wiki}
                else { $getMarkdownHelpSplat.GitHubDocRoot = "$($outputPath|Split-Path -Leaf)"}
                & $GetMarkdownHelp @getMarkdownHelpSplat| Out-String -Width 1mb | Set-Content -Path $docOutputPath -Encoding utf8
                if ($PassThru) {
                    Get-Item -Path $docOutputPath -ErrorAction SilentlyContinue
                }
            }

            if ($ScriptPath) {
                $childitems = Get-ChildItem -Path $theModuleRoot -Recurse
                foreach ($sp in $ScriptPath) {
                    $childitems |
                        Where-Object { 
                                $_.Name -eq $sp -or $_.FullName -eq $sp -or $_.Name -like $sp -or $_.FullName -like $sp
                        } |
                        Get-ChildItem |
                        Where-Object Extension -eq '.ps1' |
                        ForEach-Object {
                            $ps1File = $_
                            $getMarkdownHelpSplat = @{Name="$($ps1File.FullName)"} + $getMarkdownHelpSplatBase
                            $replacedFileName = $ps1File.Name
                            @(for ($ri = 0; $ri -lt $ReplaceScriptName.Length; $ri++) {
                                if ($ReplaceScriptNameWith[$ri]) {
                                    $replacedFileName = $replacedFileName -replace $ReplaceScriptName[$ri], $ReplaceScriptNameWith[$ri]
                                } else {
                                    $replacedFileName = $replacedFileName -replace $ReplaceScriptName[$ri]
                                }
                            })
                            $docOutputPath = Join-Path $outputPath ($replacedFileName + '.md')
                            $relativePath = $ps1File.FullName.Substring("$theModuleRoot".Length).TrimStart('/\').Replace('\','/')
                            $getMarkdownHelpSplat.Rename = $relativePath
                            if ($Wiki) { $getMarkdownHelpSplat.Wiki = $Wiki}
                            else { $getMarkdownHelpSplat.GitHubDocRoot = "$($outputPath|Split-Path -Leaf)"}
                            & $GetMarkdownHelp @getMarkdownHelpSplat| Out-String -Width 1mb | Set-Content -Path $docOutputPath -Encoding utf8
                            if ($PassThru) {
                                Get-Item -Path $docOutputPath -ErrorAction SilentlyContinue
                            }
                        }

                    
                }
            }

            if ($IncludeTopic) {
                Get-ChildItem -Path $theModuleRoot -Recurse -File |
                    ForEach-Object {
                        $fileInfo = $_
                        foreach ($inc in $IncludeTopic) {
                            if ($fileInfo.Name -match $inc) {
                                $replacedName = ($fileInfo.Name -replace $inc)
                                if ($replacedName -eq "about_$module") {
                                    $replacedName = 'README'
                                }
                                $dest = Join-Path $OutputPath ($replacedName + '.md')
                                if ($fileInfo.FullName -ne "$dest") {
                                    $fileInfo | Copy-Item -Destination $dest
                                }
                            }
                        }
                    }
            }
         }

        if ($t -gt 1) {
            Write-Progress 'Saving Markdown' 'Complete' -Completed -Id $id
        }
        #endregion Save the Markdowns
    }
}