Mess With Markdown
Converts from the lightweight markup format Markdown into HTML

function ConvertFrom-Markdown {             
            
    <#
    .Synopsis
        Converts from markdown to HTML format
    .Description
        Converts from the lightweight markup format Markdown into HTML
    .Link
        http://daringfireball.net/projects/markdown/
    .Link
        http://en.wikipedia.org/wiki/Markdown
    .Example
        ConvertFrom-MarkDown '
# Heading #
## Subheading
### Another Subheading ###

Header 1 
=========

Header 2
--------

***

---
*italics*
* * *
**bold**
- - -
_moreitalics_
- - -
__morebold__
******
Some text with `some code` inline 

    some code
    plain old indented code


! [Show Logo](http://show-logo.com/?Show-Logo_Text=Show-Logo&Show-Logo_RandomFont=true)
! [Show Logo][2]

[wikipedia](http://wikipedia.org)

[start-automating][1]
[start-automating][]
--------

[1]: http://start-automating.com/
[2]: http://show-logo.com/?Show-Logo_Text=Show-Logo&Show-Logo_RandomFont=true
[start-automating]: http://start-automating.com/

'    

    #>            
    [OutputType([string])]            
    param(            
    # The Markdown text that will be converted into HTML            
    #|LinesForInput 20            
    [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0)]            
    [Alias('Md')]            
    [String]$Markdown,            
                
    [Parameter(Position=1)]            
    # If set, will convert links to Write-Link.            
    # This will automatically embed richer content            
    #|Float            
    [Switch]$ConvertLink,            
                
    [Parameter(Position=3)]            
    # If set, will convert PRE tag content into colorized PowerShell            
    [Switch]$ScriptAsPowerShell,            
                
    [Parameter(Position=2)]            
    # If set, will recognize @{} as an embedded object, and will show the data in that object with Out-HTML.            
    #|Float            
    [Switch]$ShowData,            
            
    # If set, will splat embedded data to run commands            
    [Switch]$Splat            
    )            
                
    process {            
                    
                    
        if ($ShowData) {            
            $markdown  = [Regex]::Replace($markdown,             
                "\`$(\w{1,})",             
                {            
            
                                    
                    $text = $args[0].Groups[1].ToString()            
                    if ($text -ieq 'pipeworksmanifest') {            
                        return ('$' + $args[0].Groups[1])            
                                    
                    }            
            
                    # If it's castable to a double, it's probably a currency, not a variable            
                    if ($text -as [Double]) {            
                        return ('$' + $text)            
                    }            
            
                    if ($text -ieq 'true') {            
                        return ('$' + $true)            
                    }            
            
                    if ($text -ieq 'false') {            
                        return ('$' + $false)            
                    }            
            
                    if ($text -like "*username*" -or             
                        $text -like "*password*" -or             
                        $text -like "*secret*" -or             
                        $Text -like "*key*" -or             
                        $text -eq "home") {            
                        return ('$' +$args[0].Groups[1])                                    
                    }            
            
                    $v = $ExecutionContext.SessionState.PSVariable.Get($text)            
                                
                    if ($v) {            
                        if ($v.Value -is [string] -or             
                            $v.Value -is [int] -or             
                            $v.Value -is [float]) {            
                            $scriptHtml = $v.Value            
                        } else {            
                            $scriptHtml = $v.Value | Out-HTML            
                        }            
                    } else {            
                        $scriptHtml =""            
                    }            
            
            
                    if ($scriptHtml) {            
                        $scriptHtml            
                    } else {            
                        if ($debugPreference -ne 'SilentlyContinue') {            
                            return ('$' + $args[0].Groups[1])            
                        } else {            
                            return ' '             
                        }            
                    }            
                },             
                "Multiline,IgnoreCase")            
            $markdown = [Regex]::Replace($markdown,             
                "\$\@\{([.\s\W\w\S]{1,})\}",             
                {            
                    $a = $args             
                    $text = $a[0].Groups[1].ToString()            
                    $text = $text.Replace("<pre>", "").Replace("</pre>", "")                                
                    $dataChunk = "@{$text}"            
            
                    $theData = Import-PSData -DataString $dataChunk             
            
            
                    $scriptHtml = $theData | Out-HTML            
                                
                    if ($scriptHtml) {            
                        $scriptHtml            
                    } else {            
                        ("@{" + $args[0].Groups[1] + "}")            
                    }            
                },             
                "Multiline,IgnoreCase")            
                              
            
                        
        }            
        $markDown = $markdown -ireplace "$([Environment]::NewLine)", " $([Environment]::NewLine)"             
        #region Multiline Regex Replacement            
        $replacements = @{            
            Find = '^#{6}([^#].+)#{6}', '^#{6}([^#].+)'            
            Replace = '<h6>$1</h6>
'            
        }, @{            
            Find = '^#{5}([^#].+)#{5}', '^#{5}([^#].+)'            
            Replace = '<h5>$1</h5>
'            
        }, @{            
            Find = '^#{4}([^#].+)#{4}', '^#{4}([^#].+)'            
            Replace = '<h4>$1</h4>
'            
        }, @{            
            Find = '^#{3}([^#].+)#{3}', '^#{3}([^#].+)'            
            Replace = '<h3>$1</h3>
'            
        }, @{            
            Find = '^#{2}([^#].+)#{2}', '^#{2}([^#].+)'            
            Replace = '<h2>$1</h2>
'            
        }, @{            
            Find = '^#{1}([^#].+)#{1}', '^#{1}([^#].+)'            
            Replace = '<h1>$1</h1>
'            
        }, @{            
            # Horizontal rules            
            Find = '^\* \* \*', '^- - -'            
            Replace = "$([Environment]::NewLine)<HR/>$([Environment]::NewLine)"            
        }, @{            
            Find = '^(.+)\s={3,}'            
            Replace = '<h1>$1</h1>'            
        }, @{            
            Find = '^(.+)\s-{3,}'            
            Replace = '<h2>$1</h2>'            
        }             
                                 
        $Markdown = $Markdown.Trim()            
        foreach ($r in $replacements) {            
            foreach ($f in $r.find) {            
                $regex =New-Object Regex $f, "Multiline, IgnoreCase"            
                $Markdown  = $regex.Replace($markdown, $r.Replace)            
            }                        
        }            
        #endregion Multiline Regex Replacement            
                    
        #region Singleline Regex Replacement            
        $markdown = $markdown -ireplace             
            "$([Environment]::NewLine) $([Environment]::NewLine) $([Environment]::NewLine)", "$([Environment]::NewLine)<BR/><BR/>$([Environment]::NewLine)" -ireplace                        
            '-{3,}', "$([Environment]::NewLine)<HR/>$([Environment]::NewLine)" -ireplace            
            '\*{3,}', "$([Environment]::NewLine)<HR/>$([Environment]::NewLine)" -ireplace            
            '\*\*(.+?)\*\*', '<b>$1</b>' -ireplace             
            '__(.+?)__', '<b>$1</b>' -ireplace             
            '\*(.+?)\*', '<i>$1</i>' -ireplace             
            '\s_(.+?)_\s', '<i>$1</i>' -ireplace             
            '`(.+)` ', '<span style="font-family:Consolas, Courier New, monospace">$1</span> '                      
        #endregion Singleline Regex Replacement            
                    
        # build link dictionary            
        $linkrefs = @{}            
        $re_linkrefs = [regex]"\[(?<ref>[0-9]+)\]\:\s*(?<url>https?[^\s]+)"            
        $markdown = $re_linkrefs.Replace($Markdown, {            
            param($linkref)            
            $linkrefs[$linkref.groups["ref"].value] = $linkref.groups["url"].value                        
        })            
                    
        # handle links, images - embedded or referenced            
        $re_links = [regex]"(?<image>!\s?)?\[(?<text>[^\]]+)](?:\((?<url>[^)]+)\)|\[(?<ref>\d+)])"            
        $markdown = $re_links.Replace($markdown, {            
            param($link);            
            $url = $link.groups["url"].value            
            if (-not $url) {            
                # url did not match, so grab from dictionary            
                $url = $linkrefs[$link.groups["ref"].value]            
            }            
            $text = $link.groups["text"].value            
            
            if ($link.groups["image"].success) {            
                # image            
                $format = '<img src="{0}" alt="{1}" />'            
                $format -f $url, $text            
            } else {            
                # href            
                $format = '<a href="{0}">{1}</a>'            
                if (-not $ConvertLink) {            
                    $format -f "$url".Replace(" ", "%20"), $text            
                } else {            
                    Write-Link -Url $url -Caption $text -Button -Style @{            
                        "font-size" = "small"            
                    }            
                }            
            
            }            
                                    
        })            
            
        $replacements = @(@{            
            Find = '^>(.+)<BR/>'            
            Replace = '<blockquote>$1</blockquote><br/>'            
        })            
                    
                    
        foreach ($r in $replacements) {            
            foreach ($f in $r.find) {            
                $regex =New-Object Regex $f, "Multiline, IgnoreCase"            
                $Markdown  = $regex.Replace($markdown, $r.Replace)            
            }                        
        }            
                    
        $lines = @($Markdown -split ("[$([Environment]::NewLine)]") -ne "")            
        $toReplace = @{}            
        $inBlockQuote = $false            
        $inNumberedList = $false            
        $inList = $false            
        $inInnerHTML = $false            
        #region Fix Links and Code Sections            
        $lines = @(foreach ($l in $lines) {            
                        
            if ($l -notlike "*#LinkTo*") {            
                if ($l -match "^\d{1,}\.") {            
                    if (-not $inNumberedList) {            
                        "<ol>"            
                    }  else {            
                        "</li>"            
                    }            
                    $numberedListItemOpen = $true            
                    "<li>" + $l.Substring($l.IndexOf(".") + 1)             
                    $inNumberedList = $true            
                    continue            
                } else {            
                    if ($numberedListItemOpen) {            
                        "</li></ol>"            
                        $inList = $false            
                        $numberedListItemOpen = $false            
                    }            
                }            
                            
                if ($l -match "^\s{0,3}\*{1}") {            
                    if (-not $inList) {            
                        "<ul>"            
                    } else {            
                        "</li>"            
                    }            
                    $listItemOpen = $true            
                    "<li>" + $l.Substring($l.IndexOf("*") + 1)            
                    $inList = $true            
                    continue            
                } else {            
                    if ($listItemOpen) {            
                        "</li></ul>"            
                        $inList = $false            
                        $listItemOpen = $false            
                    }            
                }                           
                if ($l.StartsWith(">")) {            
                    if (-not $inBlockQuote) {            
                        "<blockquote>" + $l.TrimStart(">")                                    
                    } else {            
                        $l.TrimStart(">")            
                    }            
                    $inBlockQuote = $true            
                    continue            
                }            
            
                            
                if ((-not $inInnerHtml) -and $l.StartsWith("<")) {            
                    $inInnerHTML = $true            
                } elseif ($inInnerHtml -and $l.StartsWith("</")) {            
                    $inInnerHTML = $false            
                }            
            
            
                                             
                if ($inBlockquote) {            
                    if ($l -like "*<br/>*") {            
                        $l -ireplace "<br/>", "</blockquote><br/>"            
                        $inBlockQuote = $false            
                    } else {            
                        $l            
                    }            
                } elseif ($inNumberedList) {            
                    if ($l -notlike "    *") {            
                        if ($l -ne '<BR/>') {            
                            "$l</ol>"               
                            $inNumberedList = $false            
                        }            
                    } else {            
                        $l            
                    }            
                } elseif ($inList) {            
                    if ($l -and $l -notlike "    *") {            
                        if ($l -ne '<BR/>') {            
                            "$l</ul>"             
                            $inList = $false            
                        }                                      
                    } else {            
                        $l            
                    }            
                } else {            
                    if (($l.StartsWith("    ") -and $l.Trim() -and $l -notlike "*<*")) {            
                        if (-not $inCodeChunk) {            
                            "<pre>"            
                        }            
                        $l.TrimStart("    ")            
                        $inCodeChunk = $true            
                        continue            
                    } elseif ($InCodeChunk) {            
                        $inCodeChunk = $false            
                        "</pre>"            
                    }            
                                
                    if ($inCodeChunk) {            
                        $inCodeChunk = $false            
                        "</pre>"            
                    }            
                    $l                            
                }            
                            
            } else {            
                $first, $rest = $l -split ":"               
                $first = $first.Replace("#LinkTo", "").Trim()                         
                $toReplace."@LinkTo${first}" = "$(($rest -join ':').Trim())"            
            }            
                        
                        
        }            
                    
        if ($numberedListItemOpen) {            
            "</li></ol>"            
            $inList = $false            
            $numberedListItemOpen= $false            
        }            
        if ($listItemOpen) {                        
            "</li></ul>"            
            $inList = $false            
            $listItemOpen = $false                        
        })            
                    
        if ($inCodeChunk) {            
            $inCodeChunk = $false            
            $lines += "</pre>"            
        }            
                    
                    
                    
        $markdown = $lines -join ([Environment]::NewLine)            
                    
        foreach ($tr in $toReplace.Getenumerator()) {            
            if (-not $tr) {continue }            
            $markDown = $markDown -ireplace "$($tr.Key)", $tr.Value            
        }            
        #endregion Fix Links and Code Sections            
            
            
                    
        if ($scriptAsPowershell) {            
            $markdown = [Regex]::Replace($markdown,             
                "<pre[^>]*>([.\s\W\w\S]+)</pre>",             
                {            
                    $scriptHtml = Write-ScriptHTML -Script $args[0].Groups[1] -ErrorAction SilentlyContinue            
                    if ($scriptHtml) {            
                        $scriptHtml            
                    } else {            
                        $args[0].Groups[1]            
                    }            
                },             
                "Multiline,IgnoreCase")            
            
        }            
                    
                    
        if ($Splat) {            
            $markdown = [Regex]::Replace($markdown,             
                "\@([\w-]{1,})(\@\{([.\s\W\w\S]+)\}){0,}",             
                {            
                    $a = $args            
                    $commandName = $args[0].Groups[1].ToString()            
                    $splatIt = $args[0].Groups[2].ToString()            
                    $commandName.Replace("<pre>", "").Replace("</pre>", "")                                
                    $splatIt = "$splatIt".Replace("<pre>", "").Replace("</pre>", "")                                
                    #$dataChunk = "@{$text}"            
            
                    $command = Get-Command -Name $commandName -ErrorAction SilentlyContinue            
            
                    $invokeWebCommandParams = @{}            
                    if ($pipeworksManifest -and $pipeworksManifest.WebCommand.$commandName) {            
                        $invokeWebCommandParams = $pipeworksManifest.WebCommand.$commandName            
            
                    } else {            
                        $invokeWebCommandParams = @{ShowHelp=$true}            
                    }            
            
            
                    if ($splatIt) {            
                        $theParams= & ([ScriptBlock]::Create("data { $dataChunk }"))                                                                                                                
                        $null = $invokeWebCommandParams.Remove("RunWithoutInput")            
                        $defaults = @{} +$theParams             
                        if ($invokeWebCommandParams.ParameterDefaultValue) {            
                            foreach ($kv in $invokeWebCommandParams.ParameterDefaultValue.GetEnumerator()) {            
                                if (-not $defaults[$kv.Key]) {            
                                    $defaults[$kv.Key] = $kv.Value            
                                }            
                            }            
                        }            
            
                        if ($invokeWebCommandParams.DefaultValue) {            
                            foreach ($kv in $invokeWebCommandParams.DefaultValue.GetEnumerator()) {            
                                if (-not $defaults[$kv.Key]) {            
                                    $defaults[$kv.Key] = $kv.Value            
                                }            
                            }            
                        }            
                        $scriptHtml = Invoke-WebCommand -Command $command -ParameterDefaultValue $defaults -RunWithoutInput @invokeWebCommandParams            
                    } else {                                    
                        $scriptHtml = Invoke-WebCommand -Command $command @invokeWebCommandParams            
                    }            
                                
            
                                
                                
                    if ($scriptHtml) {            
                        $scriptHtml            
                    } else {            
                        $args[0].Groups[1]            
                    }            
                },             
                "Multiline,IgnoreCase")            
                              
        }            
              
            
                    
        $markdown                    
                          
                                            
                           
    }            
            
}