HelpOut.format.ps1xml

<?xml version="1.0" encoding="utf-16"?>
<!-- Generated with EZOut 1.9.0: Install-Module EZOut or https://github.com/StartAutomating/EZOut -->
<Configuration>
  <ViewDefinitions>
    <View>
      <Name>File.Documentation.PercentageDocumentation.Percentage</Name>
      <ViewSelectedBy>
        <TypeName>File.Documentation.Percentage</TypeName>
        <TypeName>Documentation.Percentage</TypeName>
      </ViewSelectedBy>
      <TableControl>
        <AutoSize />
        <TableHeaders>
          <TableColumnHeader>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>CommentPercent</Label>
          </TableColumnHeader>
        </TableHeaders>
        <TableRowEntries>
          <TableRowEntry>
            <TableColumnItems>
              <TableColumnItem>
                <PropertyName>Name</PropertyName>
              </TableColumnItem>
              <!-- {ConditionalColor:"
        Format-Heatmap -HeatMapMax 20 -InputObject $_.CommentPercent -HeatMapHot &quot;#11ff11&quot; -HeatMapCool &quot;#ff1111&quot;
    "}-->
              <TableColumnItem>
                <ScriptBlock>$moduleName = 'HelpOut'

            do {
                $lm = Get-Module -Name $moduleName -ErrorAction Ignore
                if (-not $lm) { continue }
                if ($lm.FormatPartsLoaded) { break }
                $wholeScript = @(foreach ($formatFilePath in $lm.exportedFormatFiles) {
                    foreach ($partNodeName in Select-Xml -LiteralPath $formatFilePath -XPath "/Configuration/Controls/Control/Name[starts-with(., '$')]") {
                        $ParentNode = $partNodeName.Node.ParentNode
                        "$($ParentNode.Name)={
            $($ParentNode.CustomControl.CustomEntries.CustomEntry.CustomItem.ExpressionBinding.ScriptBlock)}"
                    }
                }) -join [Environment]::NewLine
                New-Module -Name "${ModuleName}.format.ps1xml" -ScriptBlock ([ScriptBlock]::Create(($wholeScript + ';Export-ModuleMember -Variable *'))) |
                    Import-Module -Global
                $onRemove = [ScriptBlock]::Create("Remove-Module '${ModuleName}.format.ps1xml'")
                
                if (-not $lm.OnRemove) {
                    $lm.OnRemove = $onRemove
                } else {
                    $lm.OnRemove = [ScriptBlock]::Create($onRemove.ToString() + '' + [Environment]::NewLine + $lm.OnRemove)
                }
                $lm | Add-Member NoteProperty FormatPartsLoaded $true -Force
            
            } while ($false)
            
        

                $__ = $_
                $ci = . {
        &amp; ${HelpOut_Format-Heatmap} -HeatMapMax 20 -InputObject $_.CommentPercent -HeatMapHot "#11ff11" -HeatMapCool "#ff1111"
    }
                $_ = $__
                if ($ci -is [string]) {
                    $ci = &amp; ${HelpOut_Format-RichText} -NoClear -ForegroundColor $ci
                } else {
                    $ci = &amp; ${HelpOut_Format-RichText} -NoClear @ci
                }
                $output = . { '' + ([Math]::Round($_.CommentPercent,2)) + '%' }
                @($ci; $output; &amp; ${HelpOut_Format-RichText}) -join ""
                </ScriptBlock>
              </TableColumnItem>
            </TableColumnItems>
          </TableRowEntry>
        </TableRowEntries>
      </TableControl>
    </View>
    <View>
      <Name>PowerShell.Markdown.Help</Name>
      <ViewSelectedBy>
        <TypeName>PowerShell.Markdown.Help</TypeName>
      </ViewSelectedBy>
      <CustomControl>
        <CustomEntries>
          <CustomEntry>
            <CustomItem>
              <ExpressionBinding>
                <ScriptBlock>$moduleName = 'HelpOut'

            do {
                $lm = Get-Module -Name $moduleName -ErrorAction Ignore
                if (-not $lm) { continue }
                if ($lm.FormatPartsLoaded) { break }
                $wholeScript = @(foreach ($formatFilePath in $lm.exportedFormatFiles) {
                    foreach ($partNodeName in Select-Xml -LiteralPath $formatFilePath -XPath "/Configuration/Controls/Control/Name[starts-with(., '$')]") {
                        $ParentNode = $partNodeName.Node.ParentNode
                        "$($ParentNode.Name)={
            $($ParentNode.CustomControl.CustomEntries.CustomEntry.CustomItem.ExpressionBinding.ScriptBlock)}"
                    }
                }) -join [Environment]::NewLine
                New-Module -Name "${ModuleName}.format.ps1xml" -ScriptBlock ([ScriptBlock]::Create(($wholeScript + ';Export-ModuleMember -Variable *'))) |
                    Import-Module -Global
                $onRemove = [ScriptBlock]::Create("Remove-Module '${ModuleName}.format.ps1xml'")
                
                if (-not $lm.OnRemove) {
                    $lm.OnRemove = $onRemove
                } else {
                    $lm.OnRemove = [ScriptBlock]::Create($onRemove.ToString() + '' + [Environment]::NewLine + $lm.OnRemove)
                }
                $lm | Add-Member NoteProperty FormatPartsLoaded $true -Force
            
            } while ($false)
            
        

    $helpObject = $_
    $helpCmd = $ExecutionContext.SessionState.InvokeCommand.GetCommand($helpObject.Name, 'All')

    $MarkdownSections = [Ordered]@{
        Name = {
            if ($helpObject.Rename) {
                &amp; ${HelpOut_Format-Markdown} -Heading $helpObject.Rename
            } else {
                &amp; ${HelpOut_Format-Markdown} -Heading $helpObject.Name
            }
        }
        Synopsis = {
            &amp; ${HelpOut_Format-Markdown} -HeadingSize 3 -Heading "Synopsis"

            $helpObject.Synopsis | Out-String -Width 1mb
        }
        Description = {
            &amp; ${HelpOut_Format-Markdown} -HeadingSize 3 -Heading "Description"
            foreach ($desc in $helpObject.Description) {
                [Environment]::NewLine + $desc.text + [Environment]::NewLine
            }
        }
        RelatedLinks = {
            if ($helpObject.RelatedLinks) {
                &amp; ${HelpOut_Format-Markdown} -Heading "Related Links" -headingsize 3
    
                foreach ($nav in $helpObject.RelatedLinks.navigationLink) {
                    $linkedCmd = $ExecutionContext.SessionState.InvokeCommand.GetCommand($nav.LinkText, 'All')
                    $linkUrl =
                        if ($nav.Uri) {
                            $nav.Uri
                        }
                        elseif ($linkedCmd -and ($linkedCmd.Module -like 'microsoft.*' -or $linkedCmd.Source -like 'microsoft.*')) {
                            $linkSrc = if ($linkedCmd.Module) { $linkedCmd.Module} else { $linkedCmd.Source }
                            "https://docs.microsoft.com/powershell/module/$linkSrc/$linkedCmd"
                        } elseif ($helpObject.WikiLink) {
                            $nav.LinkText
                        } elseif ($null -ne $helpObject.DocLink) {
                            "$($nav.LinkText).md"
                        }
                        else {
                            ""
                        }

                    $linkText = if ($nav.LinkText) { $nav.linkText } else {$linkUrl}
                    
                    &amp; ${HelpOut_Format-Markdown} -Link $linkUrl -inputObject $linkText -BulletPoint
                }
            }
        }
        Examples = {
            if ($helpObject.Examples) {
                &amp; ${HelpOut_Format-Markdown} -Heading "Examples" -headingsize 3
    
                foreach ($example in $helpObject.Examples.Example) {
                    (&amp; ${HelpOut_Format-Markdown} -Heading ($example.Title -replace '^[-\s]+' -replace '[-\s]+$') -HeadingSize 4)
    
                    if ($example.Code) {
                        $example.Code | &amp; ${HelpOut_Format-Markdown} -CodeLanguage PowerShell
                    }
    
                    if ($example.Remarks) {
                        ($example.Remarks | Out-String -Width 1mb).Trim()
                    }
                }
            }
        }
        Parameters = {
            if ($helpObject.Parameters) {
                &amp; ${HelpOut_Format-Markdown} -Heading "Parameters" -HeadingSize 3
    
                $parameterTotal= @($helpObject.parameters.parameter).Length
                $parameterCounter = 0
                foreach ($parameter in $helpObject.Parameters.parameter) {
                    $parameterCounter++
                    $parameterDisplayName =
                        if ($parameter.required) {
                            "**$($parameter.Name)**"
                        } else {
                            $parameter.Name
                        }
    
                    &amp; ${HelpOut_Format-Markdown} -HeadingSize 4 -Heading $parameterDisplayName
    
                    if ($parameter.Name -in 'WhatIf', 'Confirm') {
                        "-$($parameter.Name) " +
                            'is an automatic variable that is created when a command has ```[CmdletBinding(SupportsShouldProcess)]```.'
                        if ($parameter.Name -eq 'WhatIf') {
                            "-WhatIf is used to see what would happen, or return operations without executing them"
                        }
                        if ($parameter.Name -eq 'Confirm') {
                            '-Confirm is used to -Confirm each operation.
    
If you pass ```-Confirm:$false``` you will not be prompted.
    
    
If the command sets a ```[ConfirmImpact("Medium")]``` which is lower than ```$confirmImpactPreference```, you will not be prompted unless -Confirm is passed.
'
                        }
                        continue
                    }
    
                    ($parameter.description | Out-String -Width 1mb) -split '(?&gt;\r\n|\n)' -replace '^-\s', '* ' -join [Environment]::NewLine
    
                    if (-not $helpObject.NoValidValueEnumeration -and $helpCmd -and $helpCmd.Parameters.($parameter.Name)) {
                        $parameterMetadata = $helpCmd.Parameters[$parameter.Name]
                        $validValuesList = @(
                            if ($parameterMetadata.ParameterType.IsSubclassOf([Enum])) {
                                [Enum]::GetValues($parameterMetadata.ParameterType)
                            } elseif ($parameterMetadata.Attributes.ValidValues) {
                                $parameterMetadata.Attributes.ValidValues
                            } elseif ($parameterMetadata.ParameterType.IsArray -and
                                $parameterMetadata.ParameterType.GetElementType().IsSubclassOf([Enum])) {
                                [Enum]::GetValues($parameterMetadata.ParameterType.GetElementType())
                            }
                        )
                        if ($validValuesList) {
                            "Valid Values:" + [Environment]::NewLine
                            $validValuesList | &amp; ${HelpOut_Format-Markdown} -BulletPoint
                            [Environment]::NewLine * 2
                        }
                    }

                    [Ordered]@{
                        Type = '```' + "[" + $($parameter.type.name -replace 'SwitchParameter', 'Switch') + "]" + '```'
                        Requried = $parameter.required
                        Postion = $parameter.position
                        PipelineInput = $parameter.pipelineInput
                    } | &amp; ${HelpOut_Format-Markdown}
                    if ($parameterCounter -lt $parameterTotal) { '---' }
                }
            }
        }
        Inputs = {
            if ($helpObject.inputTypes -and $helpObject.inputTypes.inputType) {
                 &amp; ${HelpOut_Format-Markdown} -Heading "Inputs" -HeadingSize 3
                foreach ($inputType in $helpObject.inputTypes.inputType) {
                    $inputType.type.name + [Environment]::NewLine
                    foreach ($desc in $inputType.Description) {
                        $desc.text + [Environment]::NewLine
                    }
                }
            }
        }
        Outputs = {
            if ($helpObject.returnValues -and $helpObject.returnValues.returnValue) {
                &amp; ${HelpOut_Format-Markdown} -Heading "Outputs" -HeadingSize 3
                foreach ($returnValue in $helpObject.returnValues.returnValue) {
                    $returnValue.Type.Name
                    [Environment]::NewLine
                }
            }
        }
        Syntax = {
            if ($helpObject.syntax.syntaxItem) {
                &amp; ${HelpOut_Format-Markdown} -Heading "Syntax" -HeadingSize 3
                if ($helpObject.Rename) {
                    ($helpObject.syntax | Out-String) -split '(?&gt;\r\n|\n)' -ne '' -replace "$($HelpObject.Name.Replace("\", "\\"))", $helpObject.Rename | &amp; ${HelpOut_Format-Markdown} -CodeLanguage PowerShell
                } else {
                    ($helpObject.syntax | Out-String) -split '(?&gt;\r\n|\n)' -ne '' | &amp; ${HelpOut_Format-Markdown} -CodeLanguage PowerShell
                }
            }
        }
        Notes = {
            if ($helpObject.alertSet) {
                &amp; ${HelpOut_Format-Markdown} -Heading "Notes" -HeadingSize 3
                foreach ($note in $helpObject.AlertSet.alert) {
                    ($note | Out-String).Trim() + [Environment]::NewLine
                }
            }
        }
    }

    @(
        $orderOfSections = @(if ($helpObject.SectionOrder) {
            $helpObject.SectionOrder
        } else {
            $MarkdownSections.Keys
        })

        $sectionCounter = 0
        foreach ($sectionName in $orderOfSections) {
            $sectionCounter++
            $sectionContent =
                if ($MarkdownSections.$sectionName -is [ScriptBlock]) {
                    &amp; $MarkdownSections.$sectionName
                } else { $null }
            if ($sectionContent) {
                $sectionContent
                if ($sectionCounter -lt $orderOfSections.Length -and $sectionContent -notmatch '---\s{0,}$') {
                    '---'
                }
            }
        }

    ) -join [Environment]::NewLine
</ScriptBlock>
              </ExpressionBinding>
            </CustomItem>
          </CustomEntry>
        </CustomEntries>
      </CustomControl>
    </View>
  </ViewDefinitions>
  <Controls>
    <Control>
      <Name>${HelpOut_Format-Heatmap}</Name>
      <CustomControl>
        <CustomEntries>
          <CustomEntry>
            <CustomItem>
              <ExpressionBinding>
                <ScriptBlock>
    &lt;#
    .SYNOPSIS
        Formats a value as a heatmap
    .DESCRIPTION
        Returns the color used to generate a heatmap for a given value.
    #&gt;
    [Management.Automation.Cmdlet("Format", "Object")]
    [ValidateScript({return $true})]
    param(
    # The value that will be heatmapped.
    [Parameter(ValueFromPipeline)]
    $InputObject,
    
    # The Heatmap maximum, by default 1gb
    [Parameter(Mandatory)]
    $HeatMapMax = 1gb,
    
    # The Heatmap middle value, by default 512mb
    $HeatMapMiddle = 512mb,
    
    # The Heatmap minimum value, by default 0
    $HeatMapMin = 0,
    
    # The color for cool.
    # To pass a Hex color as an int, simply replace # with 0x
    # (e.g. 0x00ff00 for green instead of '#00ff00')
    [int]
    $HeatMapCool =0x05dd00,
    
    # The color for hot.
    # To pass a Hex color as an int, simply replace # with 0x
    # (e.g. 0xff0000 for red instead of '#ff0000')
    [int]
    $HeatMapHot = 0xef1100
    )

    process {
        # Separate out the segments of the color,
        $coolRedPart = [byte](($HeatMapCool -band 0xff0000) -shr 16) # by bitmasking and then shifting right until it's bytes
        $coolGreenPart = [byte](($HeatMapCool -band 0x00ff00) -shr 8)
        $coolBluePart = [byte]($HeatMapCool -band 0x0000ff)

        $hotRedPart = [byte](($HeatMapHot -band 0xff0000) -shr 16)
        $hotGreenPart = [byte](($HeatMapHot -band 0x00ff00) -shr 8)
        $hotBluePart = [byte]($HeatMapHot -band 0x0000ff)

        "#{0:x2}{1:x2}{2:x2}" -f @(
        if ($InputObject -le $HeatMapMin)
        {
            $coolRedPart, $coolGreenPart, $coolBluePart
        }
        elseif ($InputObject -ge $HeatMapMax)
        {
            $hotRedPart, $hotGreenPart, $hotBluePart
        } else {
            if ($InputObject -le $HeatMapMiddle)
            {
                $d = 1 - ([double]$InputObject / ($HeatMapMiddle - $HeatMapMin))
                [Byte][Math]::Min(255, $hotRedPart * $d + $coolRedPart)
                [Byte][Math]::Min(255, $hotGreenPart * $d + $coolGreenPart)
                [Byte][Math]::Min(255, $hotBluePart * $d + $coolBluePart)
            } else
            {
                $d = 1 - ([double]$InputObject / ($HeatMapMax - $HeatMapMiddle))
                [Byte][Math]::Min(255, $coolRedPart * $d + $hotRedPart)
                [Byte][Math]::Min(255, $coolGreenPart * $d + $hotGreenPart)
                [Byte][Math]::Min(255, $coolBluePart * $d + $hotBluePart)
            }
        })
    }
</ScriptBlock>
              </ExpressionBinding>
            </CustomItem>
          </CustomEntry>
        </CustomEntries>
      </CustomControl>
    </Control>
    <Control>
      <Name>${HelpOut_Format-RichText}</Name>
      <CustomControl>
        <CustomEntries>
          <CustomEntry>
            <CustomItem>
              <ExpressionBinding>
                <ScriptBlock>
    &lt;#
    .Synopsis
        Formats the text color of output
    .Description
        Formats the text color of output

        * ForegroundColor
        * BackgroundColor
        * Bold
        * Underline
    .Notes
        Stylized Output works in two contexts at present:
        * Rich consoles (Windows Terminal, PowerShell.exe, Pwsh.exe) (when $host.UI.SupportsVirtualTerminal)
        * Web pages (Based off the presence of a $Request variable, or when $host.UI.SupportsHTML (you must add this property to $host.UI))
    #&gt;
    [Management.Automation.Cmdlet("Format","Object")]
    [ValidateScript({
        $canUseANSI = $host.UI.SupportsVirtualTerminal
        $canUseHTML = $Request -or $host.UI.SupportsHTML -or $OutputMode -eq 'HTML'
        if (-not ($canUseANSI -or $canUseHTML)) { return $false}
        return $true
    })]
    param(
    # The input object
    [Parameter(ValueFromPipeline)]
    [PSObject]
    $InputObject,
    # The foreground color
    [string]$ForegroundColor,
    # The background color
    [string]$BackgroundColor,
    # If set, will render as bold
    [switch]$Bold,
    # If set, will render as blinking (not supported in all terminals or HTML)
    [switch]$Blink,
    # If set, will render as strikethru
    [switch]$Strikethru,
    # If set, will underline text
    [switch]$Underline,
    # If set, will invert text
    [switch]$Invert,
    # If set, will not clear formatting
    [switch]$NoClear
    )

    begin {
        $canUseANSI = $host.UI.SupportsVirtualTerminal
        $canUseHTML = $Request -or $host.UI.SupportsHTML -or $OutputMode -eq 'HTML'
        $knownStreams = @{
            Output='';Error='BrightRed';Warning='BrightYellow';
            Verbose='BrightCyan';Debug='Yellow';Progress='Cyan';
            Success='BrightGreen';Failure='Red';Default=''}
        $standardColors = 'Black', 'Red', 'Green', 'Yellow', 'Blue','Magenta', 'Cyan', 'White'
        $brightColors = 'BrightBlack', 'BrightRed', 'BrightGreen', 'BrightYellow', 'BrightBlue','BrightMagenta', 'BrightCyan', 'BrightWhite'

        $n =0
        $cssClasses = @()
        $styleAttributes =
            @(:nextColor foreach ($hc in $ForegroundColor,$BackgroundColor) {
                $n++
                if (-not $hc) { continue }
                if ($hc[0] -eq [char]0x1b) {
                    if ($canUseANSI) {
                        $hc; continue
                    }
                }
        
                $ansiStartPoint = if ($n -eq 1) { 30 } else { 40 }
                if ($knownStreams.ContainsKey($hc)) {
                    $i = $brightColors.IndexOf($knownStreams[$hc])
                    if ($canUseHTML) {
                        $cssClasses += $hc
                    } else {
                        if ($i -ge 0 -and $canUseANSI) {
                            '' + [char]0x1b + "[1;$($ansiStartPoint + $i)m"
                        } else {
                            $i = $standardColors.IndexOf($knownStreams[$hc])
                            if ($i -ge 0 -and $canUseANSI) {
                                '' + [char]0x1b + "[1;$($ansiStartPoint + $i)m"
                            } elseif ($i -le 0 -and $canUseANSI) {
                                '' + [char]0x1b + "[$($ansistartpoint + 8):5m"
                            }
                        }
                    }
                    continue nextColor
                }
                elseif ($standardColors -contains $hc) {
                    for ($i = 0; $i -lt $standardColors.Count;$i++) {
                        if ($standardColors[$i] -eq $hc) {
                            if ($canUseANSI -and -not $canUseHTML) {
                                '' + [char]0x1b + "[$($ansiStartPoint + $i)m"
                            } else {
                                $cssClasses += $standardColors[$i]
                            }
                            continue nextColor
                        }
                    }
                } elseif ($brightColors -contains $hc) {
                    for ($i = 0; $i -lt $brightColors.Count;$i++) {
                        if ($brightColors[$i] -eq $hc) {
                            if ($canUseANSI -and -not $canUseHTML) {
                                '' + [char]0x1b + "[1;$($ansiStartPoint + $i)m"
                            } else {
                                $cssClasses += $standardColors[$i]
                            }
                            continue nextColor
                        }
                    }
                }
                elseif ($psStyle -and $psStyle.Formatting.$hc -and
                    $psStyle.Formatting.$hc -match '^\e') {
                    if ($canUseANSI -and -not $canUseHTML) {
                        $psStyle.Formatting.$hc
                    } else {
                        $cssClasses += "formatting-$hc"
                    }
                }
                elseif (-not $n -and $psStyle -and $psStyle.Foreground.$hc -and
                    $psStyle.Foreground.$hc -match '^\e' ) {
                    if ($canUseANSI -and -not $canUseHTML) {
                        $psStyle.Foreground.$hc
                    } else {
                        $cssClasses += "foreground-$hc"
                    }
                }
                elseif ($n -and $psStyle -and $psStyle.Background.$hc -and
                    $psStyle.Background.$hc -match '^\e') {
                    if ($canUseANSI -and -not $canUseHTML) {
                        $psStyle.Background.$hc
                    } else {
                        $cssClasses += "background-$hc"
                    }
                }

        
        
                if ($hc -and $hc -notmatch '^[\#\e]') {
                    $placesToLook=
                        @(if ($hc.Contains('.')) {
                            $module, $setting = $hc -split '\.', 2
                            $theModule = Get-Module $module
                            $theModule.PrivateData.Color,
                                $theModule.PrivateData.Colors,
                                $theModule.PrivateData.Colour,
                                $theModule.PrivateData.Colours,
                                $theModule.PrivateData.EZOut,
                                $global:PSColors,
                                $global:PSColours
                        } else {
                            $setting = $hc
                            $moduleColorSetting = $theModule.PrivateData.PSColors.$setting
                        })
        
                    foreach ($place in $placesToLook) {
                        if (-not $place) { continue }
                        foreach ($propName in $setting -split '\.') {
                            $place = $place.$propName
                            if (-not $place) { break }
                        }
                        if ($place -and "$place".StartsWith('#') -and 4,7 -contains "$place".Length) {
                            $hc = $place
                            continue
                        }
                    }
                    if (-not $hc.StartsWith -or -not $hc.StartsWith('#')) {
                        continue
                    }
                }
                $r,$g,$b = if ($hc.Length -eq 7) {
                    [int]::Parse($hc[1..2]-join'', 'HexNumber')
                    [int]::Parse($hc[3..4]-join '', 'HexNumber')
                    [int]::Parse($hc[5..6] -join'', 'HexNumber')
                }elseif ($hc.Length -eq 4) {
                    [int]::Parse($hc[1], 'HexNumber') * 16
                    [int]::Parse($hc[2], 'HexNumber') * 16
                    [int]::Parse($hc[3], 'HexNumber') * 16
                }
        
                if ($canUseHTML) {
                    if ($n -eq 1) { "color:$hc" }
                    elseif ($n -eq 2) { "background-color:$hc"}
                }
                elseif ($canUseANSI) {
                    if ($n -eq 1) { [char]0x1b+"[38;2;$r;$g;${b}m" }
                    elseif ($n -eq 2) { [char]0x1b+"[48;2;$r;$g;${b}m" }
                }
                
            })
        
        
        if ($Bold) {
            $styleAttributes +=
                if ($canUseHTML) {
                    "font-weight:bold"
                }
                elseif ($canUseANSI)
                {
                    '' + [char]0x1b + "[1m"
                }
        }
        
        if ($Underline) {
            $styleAttributes +=
                if ($canUseHTML) {
                    "text-decoration:underline"
                } elseif ($canUseANSI) {
                    '' +[char]0x1b + "[4m"
                }
        }

        if ($Strikethru) {
            $styleAttributes +=
                if ($canUseHTML) {
                    "text-decoration: line-through"
                } elseif ($canUseANSI) {
                    '' +[char]0x1b + "[4m"
                }
        }

        if ($Blink) {
            $styleAttributes +=
                if ($canUseHTML) {
                    
                } elseif ($canUseANSI) {
                    '' +[char]0x1b + "[5m"
                }
        }
        
        if ($Strikethru) {
            $styleAttributes +=
                    if ($canUseHTML) {
                        "text-decoration: line-through"
                    } elseif ($canUseANSI) {
                        [char]0x1b + "[9m"
                    }
        }
        
        if ($Invert) {
            $styleAttributes +=
                if ($canUseHTML) {
                    "filter:invert(100%)"
                } elseif ($canUseANSI) {
                    [char]0x1b + "[7m"
                }
        }
        
        $header =
            if ($canUseHTML) {
                "&lt;span$(
                    if ($styleAttributes) { " style='$($styleAttributes -join ';')'"}
                )$(
                    if ($cssClasses) { " class='$($cssClasses -join ' ')'"}
                )&gt;"
            } elseif ($canUseANSI) {
                $styleAttributes -join ''
            }
    }

    process {
        if ($header) {
            "$header" + "$(if ($inputObject) { $inputObject | Out-String})".Trim()
        }
        elseif ($inputObject) {
            ($inputObject | Out-String).Trim()
        }
    }

    end {
        
        if (-not $NoClear) {
            if ($canUseHTML) {
                "&lt;/span&gt;"
            }
            elseif ($canUseANSI) {
                if ($Underline) {
                    '' + [char]0x1b + "[24m"
                }
                if ($Strikethru) {
                    '' + [char]0x1b + "[29m"
                }
                if ($Bold) {
                    '' + [char]0x1b + "[21m" + '' + [char]0x1b + "[22m"
                }
                if ($Invert) {
                    '' + [char]0x1b + '[27m'
                }
                if ($ForegroundColor) {
                    '' + [char]0x1b + '[39m'
                }
                if ($BackgroundColor) {
                    '' + [char]0x1b + '[49m'
                }
            
                if (-not ($Underline -or $Bold -or $Invert -or $ForegroundColor -or $BackgroundColor)) {
                    '' + [char]0x1b + '[0m'
                }
            }
        }
    }
</ScriptBlock>
              </ExpressionBinding>
            </CustomItem>
          </CustomEntry>
        </CustomEntries>
      </CustomControl>
    </Control>
    <Control>
      <Name>${HelpOut_Format-Markdown}</Name>
      <CustomControl>
        <CustomEntries>
          <CustomEntry>
            <CustomItem>
              <ExpressionBinding>
                <ScriptBlock>
    &lt;#
    .SYNOPSIS
        Formats an object as Markdown
    .DESCRIPTION
        Formats an object as Markdown, with many options to work with
    .EXAMPLE
        Format-Markdown -ScriptBlock {
            Get-Process
        }
    .EXAMPLE
         1..6 | Format-Markdown -HeadingSize { $_ }
    #&gt;
    [Management.Automation.Cmdlet("Format","Object")]
    [ValidateScript({return $true})]
    param(
    [Parameter(ValueFromPipeline,ValueFromPipelineByPropertyName)]
    [PSObject]
    $InputObject,
    
    # If set, will treat the -InputObject as a paragraph.
    # This is the default for strings, booleans, numbers, and other primitive types.
    [Parameter(ValueFromPipelineByPropertyName)]
    [switch]
    $MarkdownParagraph,

    # If set, will generate a markdown table.
    [Parameter(ValueFromPipelineByPropertyName)]
    [switch]
    $MarkdownTable,

    # If provided, will align columnns in a markdown table.
    [Parameter(ValueFromPipelineByPropertyName)]
    [ValidateSet("Left","Right","Center", "")]
    [string[]]
    $MarkdownTableAlignment,

    # An array of properties. Providing this implies -MarkdownTable
    [Parameter(ValueFromPipelineByPropertyName)]
    [PSObject[]]
    $Property,

    # A heading.
    # If provided without -HeadingSize, -HeadingSize will default to 2.
    # If provided with -InputObject, -Heading will take priority.
    [Parameter(ValueFromPipelineByPropertyName)]
    [string]
    $Heading,

    # The heading size (1-6)
    # If provided without -Heading, the -InputObject will be considered to be a heading.
    [Parameter(ValueFromPipelineByPropertyName)]
    [ValidateRange(1,6)]
    [int]
    $HeadingSize,

    # If set, will create a link. The -InputObject will be used as the link content
    [Parameter(ValueFromPipelineByPropertyName)]
    [string]
    $Link,

    # If set, will create an image link. The -Inputobject will be used as the link content.
    [Parameter(ValueFromPipelineByPropertyName)]
    [string]
    $ImageLink,

    # If set, will generate a bullet point list.
    [Parameter(ValueFromPipelineByPropertyName)]
    [Alias('BulletpointList')]
    [switch]
    $BulletPoint,
    
    # If set, bullet or numbered list items will have a checkbox.
    # Each piped -InputObject will be an additional list item.
    [Parameter(ValueFromPipelineByPropertyName)]
    [switch]
    $Checkbox,

    # If set, bullet or numbered list items will be checked.
    [Parameter(ValueFromPipelineByPropertyName)]
    [switch]
    $Checked,

    # If set, will generate a numbered list.
    # Each piped -InputObject will be an additional list item.
    [Parameter(ValueFromPipelineByPropertyName)]
    [switch]
    $NumberedList,

    # If set, will generate a block quote.
    # Each line of the -InputObject will be block quoted.
    [Parameter(ValueFromPipelineByPropertyName)]
    [switch]
    $BlockQuote,

    # If set, will generate a block quote of a particular depth.
    # Each line of the -InputObject will be block quoted.
    [Parameter(ValueFromPipelineByPropertyName)]
    [ValidateRange(1,3)]
    [int]
    $BlockQuoteDepth,
        
    # If provided, will create a markdown numbered list with this particular item as the number.
    [Parameter(ValueFromPipelineByPropertyName)]
    [int]
    $Number,

    # If set, will generate a horizontal rule.
    # If other parameters are provided, the horiztonal rule will be placed after.
    [Parameter(ValueFromPipelineByPropertyName)]
    [switch]
    $HorizontalRule,

    # If set, will output the -InputObject as a Markdown code block
    [Parameter(ValueFromPipelineByPropertyName)]
    [switch]
    $Code,

    # If set, will output the -InputObject as a Markdown code block, with a given language
    # If the -InputObject is a ScriptBlock, -CodeLanguage will be set to PowerShell.
    [Parameter(ValueFromPipelineByPropertyName)]
    [string]
    $CodeLanguage,

    # If provided, will output a script block as a Markdown code block.
    [Parameter(ValueFromPipelineByPropertyName)]
    [ScriptBlock]
    $ScriptBlock
    )

    begin {
        $numberedListCounter = 0
        $IsFirst = $true
        filter LinkInput {
            $in = $_
            if ($ImageLink) {
                "![$in]($imageLink)"
            } elseif ($link) {
                "[$in]($link)"
            } else {
                "$in"
            }
        }

        $markdownLines = @()
    }

    process {
        
        if ($ScriptBlock -or $inputObject -is [scriptblock]) { # If a -ScriptBlock was provided
            $CodeLanguage = 'PowerShell' # use PowerShell as a Code Language.
        }

        # If a -HeadingSize or a -Heading were provided, render a heading.
        if ($HeadingSize -or $Heading)
        {
            if (-not $HeadingSize) { $HeadingSize = 2} # If the -HeadingSize was not set, set it to 2.
            $headingContent = "$(if ($Heading) { $Heading} else { $inputObject | LinkInput})"
            $markdownLines +=
                if ($HeadingSize -eq 1) {
                    $headingContent
                    '=' * [Math]::Max($headingContent.Length, 3)
                }
                elseif ($HeadingSize -eq 2) {
                    $headingContent
                    '-' * [Math]::Max($headingContent.Length, 3)
                }
                else {
                    ("#"*$HeadingSize) + " $headingContent" # Output the -Heading or the -InputObject.
                }
        }
        # If -Code or -CodeLanguage was provided, render a Markdown code block.
        elseif ($Code -or $CodeLanguage)
        {
            # If the -InputObject was a [ScriptBlock] or there is a -ScriptBlock
            if ($InputObject -is [scriptblock] -or $ScriptBlock) {
                $CodeLanguage = 'PowerShell' # set the code language to PowerShell.
            }
            $markdownLines += (
                '```' + # Start the code fence,
                    $(if ($CodeLanguage) { $CodeLanguage}) + # add the language,
                    [Environment]::newline + # then a newline,
                    $(if ($ScriptBlock) { "$scriptBlock" } else { $inputObject | LinkInput}) + # then the -ScriptBlock or -InputObject
                    [Environment]::newline + # then a newline
                '```' # then close the code fence.
            )
        }
        # If -BulletPoint was passed, render a Bullet Point list.
        elseif ($BulletPoint)
        {
            $markdownLines += "*$(if ($Checkbox) { "[$(if ($Checked) {"x"} else {" "})]"}) $($inputObject | LinkInput)"
        }
        # If -NumberedList was passed, render a numbered list.
        elseif ($NumberedList -or $Number)
        {
            $numberedListCounter++ # Increment the counter
            $markdownLines += "$(if ($number) { $number } else {$numberedListCounter}).$(if ($Checkbox) {" [$(if ($Checked) {"x"} else {" "})]"}) $($inputObject | LinkInput)"
        }
        elseif ($BlockQuote -or $BlockQuoteDepth) {
            if (-not $BlockQuoteDepth) { $BlockQuoteDepth = 1 }
            $markdownLines += ("&gt;" * $BlockQuoteDepth) + ' ' + (
                "$inputObject" -split '(?&gt;\r\n|\n)' -join (
                    [Environment]::NewLine + ("&gt;" * $BlockQuoteDepth) + ' '
                )
            )
        }
        # Otherwise, we have to determine if -InputObject should be a -MarkdownTable or a -MarkdownParagraph.
        else
        {
            # If the input is a primitive type or a string, it should be a markdown paragraph
            if (($inputObject.GetType -and $inputObject.GetType().IsPrimitive) -or
                $inputObject -is [string]) {
                $MarkdownParagraph = $true
            }
            # If it is a dictionary, it should be a markdown table.
            elseif ($inputObject -is [Collections.IDictionary])
            {
                $MarkdownTable = $true
            }
            # If the input is an array, apply the same logic:
            elseif ($inputObject -is [Object[]] -or $InputObject -is [PSObject[]]) {
                $allPrimitives = 1
                # if the array was all primitives or strings
                foreach ($in in $InputObject) {
                    $allPrimitives = $allPrimitives -band (
                        ($in.GetType -and $in.GetType().IsPrimitive) -or $in -is [string]
                    )
                }
                if ($allPrimitives) { # output as a paragraph.
                    $MarkdownParagraph = $true
                } else {
                    $MarkdownTable = $true
                }
            }
            # If we're still not sure, output as a table.
            else {
                $MarkdownTable = $true
            }
        }

        if ($MarkdownParagraph) {
            # If we're outputting as a paragraph, add the input and link it if needed.
            $markdownLines += $inputObject | LinkInput
        } elseif ($MarkdownTable) {
            # If we're rendering a table, we need to go row-by-row.
            foreach ($in in $InputObject) {
                $propertyList = @(
                    # we first need to get a list of properties.
                    # If there was a -Property parameter provided, use it.
                    if ($Property) {
                        foreach ($prop in $Property) {
                            if ($prop -is [string]) { # Strings in -Property should be taken as property names
                                $prop
                            } elseif ($prop.Name -and $prop.Expression -and $prop.Expression -is [scriptblock]) {
                                # and anything with a name and expression script block will run the expression script block.
                                $_ = $psItem = $in
                                @{name=$prop.Name;Value = . $prop.Expression}
                            }
                        }
                    }
                    # Otherwise, if the input was a dictionary
                    elseif ($in -is [Collections.IDictionary])
                    {
                        foreach ($k in $in.Keys) { # take all keys from the dictionary
                            if ($MyInvocation.MyCommand.Parameters[$k]) { continue } # that are not parameters of this function.
                            $k
                        }
                    }
                    # Otherwise, walk over all properties on the object
                    else {
                        foreach ($psProp in $In.psobject.properties) {
                            # and skip any properties that are parameters of this function.
                            if ($psProp.Name -notin $MyInvocation.MyCommand.Parameters.Keys) {
                                $psProp
                            }
                        }
                    }
                )

                # If we're rendering the first row of a table
                if ($IsFirst) {
                    # Create the header
                    $markdownLines +=
                        '|' + (@(foreach ($prop in $propertyList) {
                            if ($prop -is [string]) {
                                $prop
                            } else {
                                $prop.Name
                            }
                        }) -replace ([Environment]::newline), '&lt;br/&gt;' -replace '\|', '`|' -join '|') + '|'
                    # Then create the alignment row.
                    $markdownLines +=
                        '|' + $(
                            $columnNumber =0
                            @(
                                foreach ($prop in $propertyList) {
                                    $colLength =
                                        if ($prop -is [string]) {
                                            $prop.Length
                                        } else {
                                            $prop.Name.Length
                                        }
                                    if ($MarkdownTableAlignment) {
                                        if ($MarkdownTableAlignment[$columnNumber] -eq 'Left') {
                                            ':' + ("-" * ([Math]::Max($colLength,2) - 1))
                                        }
                                        elseif ($MarkdownTableAlignment[$columnNumber] -eq 'Right') {
                                            ("-" * ([Math]::Max($colLength,2) - 1)) + ':'
                                        }
                                        elseif ($MarkdownTableAlignment[$columnNumber] -eq 'Center') {
                                            ':' + ("-" * ([Math]::max($colLength, 3) - 2)) + ':'
                                        } else {
                                            "-" * $colLength
                                        }
                                    } else {
                                        "-" * $colLength
                                    }
                                    
                                    $columnNumber++
                                }
                            ) -replace ([Environment]::newline), '&lt;br/&gt;' -replace '\|', '`|' -join '|') + '|'
                    $IsFirst = $false
                }
                
                # Now we create the row for this object.
                $markdownLines += '|' + (@(foreach ($prop in $propertyList) {
                    if ($prop -is [string]) {
                        $in.$prop | LinkInput
                    } else {
                        $prop.Value | LinkInput
                    }
                }) -replace ([Environment]::newline), '&lt;br/&gt;' -replace '\|', '`|' -join '|') + '|'
            }
        }

            
        if ( # There are a few combinations of parameters that make us want to write the -InputObject as a paragraph:
            ($ScriptBlock -and $inputObject) -or # * If -ScriptBlock and -InputObject were both provided.
            ($Heading -and $inputObject) # * if -Heading and -InputObject were both provided
        ) {
            $markdownLines += $InputObject | LinkInput
        }


        # If we're going to render a horizontal rule (and -MarkdownTable has not been set)
        if ($HorizontalRule -and -not $MarkdownTable) {
            # add the horizontal rule at the end.
            if ($host.UI.RawUI.BufferSize.Width) {
                $markdownLines += (([string]$HorizontalRuleCharacter) * ($Host.UI.RawUI.BufferSize.Width - 1))
            } else {
                $markdownLines += "---"
            }
        }
    }

    end {
        # Now we need to make one last pass to normalize tables
        if ($markdownLines -match '^\|') { # (that is, if we have tables to normalize).
            $maxColumnSize = @{} # To normalize the table, we need to track the maximum size per column
            foreach ($ml in $markdownLines) {
                if ($ml -match '\^|') {
                    $columnCount = 0
                    foreach ($tablePart in $ml -split '\|' -ne '') {
                        if ((-not $maxColumnSize[$columnCount]) -or $maxColumnSize[$columnCount] -lt $tablePart.Length) {
                            $maxColumnSize[$columnCount] = [Math]::Max($tablePart.Length, 2)
                        }
                        $columnCount++
                    }
                }
            }
            # One we know the maximum size per column, walk over each line
            $markdownLines = @(foreach ($ml in $markdownLines) {
                if ($ml -match '\^|') {
                    $columnCount = 0
                    # Recreate the line with the right amount of padding.
                    '|' + (@(foreach ($tablePart in $ml -split '\|' -ne '') {
                        if ($tablePart -match '^[:\-]+$') {
                            if ($tablePart -match '^\:-{0,}\:$') { # If it's an alignment column, make sure to keep the alignment.
                                if ($maxColumnSize[$columnCount] -gt 2) {
                                    ':' + ('-' * ($maxColumnSize[$columnCount] - 2)) + ':'
                                } else {
                                    '::'
                                }
                            }
                            elseif ($tablePart -match '\:$') {
                                $tablePart.PadLeft($maxColumnSize[$columnCount], '-')
                            }
                            elseif ($tablePart -match '^\:') {
                                $tablePart.PadRight($maxColumnSize[$columnCount], '-')
                            }
                            else {
                                $tablePart.PadRight($maxColumnSize[$columnCount], '-')
                            }
                        } else {
                            $tablePart.PadRight($maxColumnSize[$columnCount], ' ')
                        }
                        $columnCount++
                    }) -join '|') + '|'
                } else {
                    $ml
                }
            })
        }
        $markdownLines -join [Environment]::NewLine
    }
</ScriptBlock>
              </ExpressionBinding>
            </CustomItem>
          </CustomEntry>
        </CustomEntries>
      </CustomControl>
    </Control>
  </Controls>
</Configuration>