Document Tricks with Pandoc and PowerShell
Today's content is a little different. I'm not going to focus on a specific PowerShell topic, but rather something I think of as "PowerShell adjacent." You have probably written Markdown documents for your PowerShell projects, such as modules. You most likely have a README
file in your repository. Hopefully, you are using the PlatyPS module to create documentation. This too will generate Markdown files. Or maybe you simply like writing in Markdown.
Since you've created this content once, you might want to re-purpose it into different formats. Maybe you want a set of HTML documents you can post to a documentation website. Or maybe you need a set of PDF files? What about a Word document?
Fortunately, there is a single tool you can use for all of these tasks. And because it is a command-line tool, that means you can incorporate it into PowerShell and automate the process. I want to give you a brief introduction to Pandoc and demonstrate how it can be used with PowerShell.
Installing Pandoc
To get started, you will need the latest version of Pandoc installed on your desktop. You can find installation instructions here. You could also install it from GitHub.
I'll install using Winget.
winget install --id JohnMacFarlane.Pandoc
The installation will update your PATH environment variable so you can run Pandoc from any command prompt. However, you will need to restart your PowerShell session to pick up the change.
PS C:\> $env:path -split ";" | where {$_ -Match "pandoc"}
C:\Users\Jeff\AppData\Local\Pandoc\
PS C:\> $env:path -split ";" | where {$_ -Match "pandoc"} | Set-Location
PS C:\Users\Jeff\AppData\Local\Pandoc> dir
Directory: C:\Users\Jeff\AppData\Local\Pandoc
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 7/28/2024 9:41 PM 20519 COPYING.rtf
-a--- 7/28/2024 9:20 PM 8489 COPYRIGHT.txt
-a--- 7/28/2024 9:41 PM 390601 Pandoc User's Guide.html
-a--- 7/28/2024 9:41 PM 216364032 pandoc.exe
Getting Help
I'll guide you through some Pandoc basics, but you should take a quick look at the HTML user guide.
PS C:\Users\Jeff\AppData\Local\Pandoc> Invoke-Item '.\Pandoc User''s Guide.html'
You can also get help from the command line.
pandoc --help
The help is extensive, but you can narrow it down using Select-String
.
PS C:\> pandoc --help | Select-String list
--list-tables[=true|false]
--listings[=true|false]
--list-input-formats
--list-output-formats
--list-extensions[=FORMAT]
--list-highlight-languages
--list-highlight-styles
The basic syntax for Pandoc is pandoc --output
. The input file can be a single Markdown file or a collection of files. The output file can be a single file or a directory. Pandoc will convert the input file(s) to the desired format.
Creating Fragments
You will probably always want to specify the output file. Here is a sample markdown file.
# Sample Document
This is a sample markdown document.
## Section 1
I'll put first-level content here.
```powershell
Get-CimInstance Win32_OperatingSystem |
Select-Object RegisteredUser,InstallDate,
@{Name="OS";Expression = {$_.Caption}},
@{Name="Computername";Expression={$_.CSName}}
```
### Subsection 1
Here is a subsection.
## Summary
You can find me online [here](https://jdhitsolutions.github.io).
I want to convert this to an HTML fragment.
pandoc -o c:\temp\sample.html c:\work\sample.md
> Be careful. The Pandoc parameters are case-sensitive. And don't forget to watch the number of dashes.
The output looks like an HTML document.

But if you look at the source, you'll see this is an HTML fragment.

This could be useful if you are assembling a larger document from multiple fragments. But let's set that idea aside for now.
Creating Standalone Documents
More than likely you will want to create a complete, stand-alone document.
PS C:\work> pandoc -s -o c:\temp\sample.html c:\work\sample.md
[WARNING] This document format requires a nonempty <title> element.
Defaulting to 'sample' as the title.
To specify a title, use 'title' in metadata or --metadata title="...".
If you want to suppress the warnings, add the --quiet
parameter.
pandoc -s -o c:\temp\sample.html c:\work\sample.md --quiet
If you look at the HTML code, you'll now see a complete HTML document with metadata, style, and more.

Metadata
If you want to specify metadata, you can do it like this.
pandoc -s -o c:\temp\sample.html c:\work\sample.md --quiet --metadata title="Sample Doc" --metadata author="Jeff Hicks"
The potential downside is that this gets added to the HTML document.

If you want the metadata, you can set it via variables.
pandoc -s -o c:\temp\sample.html c:\work\sample.md --quiet --variable title-meta="Sample Doc" --variable author-meta="Jeff Hicks" --variable date-meta=$(Get-Date -Format u) --title "Sample Markdown Doc"
You will also want to set the title. As an alternative, you can store metadata in a JSON
or YAML
file.
{
"title": "My Sample Doc",
"author": "Jeff Hicks",
"keywords": [
"markdown",
"pandoc"
]
}
Then you can reference the file in your command.
pandoc -s -o c:\temp\sample.html c:\work\sample.md --quiet --metadata-file=".\metadata.json" -V date-meta=$(Get-Date -Format u)
I could never get the date to set using the JSON file so I added it as a variable.

Although, this process will insert the metadata into the HTML document, which you may or may not like.
Syntax Highlighting
Another feature you might want to take advantage of is syntax highlighting. You can specify a supported Pandoc style
PS C:\> pandoc --list-highlight-styles
pygments
tango
espresso
zenburn
kate
monochrome
breezedark
haddock
I'll let you experiment with these. Here is an example.
pandoc -s -o c:\temp\sample.html c:\work\sample.md --quiet --variable title-meta="Sample Doc" --variable author-meta="Jeff Hicks" --variable date-meta=$(Get-Date -Format u) --title "Sample Markdown Doc" --highlight-style='espresso'

Other Style Options
If you read through the HTML help file, you'll discover you can set other HTML options through variables.
pandoc -s -o c:\temp\sample.html c:\work\sample.md --quiet --variable title-meta="Sample Doc" --variable author-meta="Jeff Hicks" --variable date-meta=$(Get-Date -Format u) --title "Sample Markdown Doc" --highlight-style='tango' --variable linkcolor="#337DFF" --variable mainfont="Tahoma" --variable backgroundcolor="#E0E6F1"

Converting at Scale
If I can do something for one file, I can just easily do it for many files. I want to take the Markdown files from a module and create HTML versions.
Get-ChildItem -Path C:\scripts\PSProjectStatus\docs\*.md |
Foreach-Object {
$target = Join-Path -path c:\temp\html -ChildPath "$($_.Name.Replace(".md",".html"))"
$title = $_.BaseName
Write-Host "Exporting $($_.FullName) to $target" -ForegroundColor Cyan
pandoc --standalone --output $target $_.FullName--quiet --variable author-meta="Jeff Hicks" --variable title-meta=$title --variable date-meta=$(Get-Date -Format u) --highlight-style='kate' --variable linkcolor="#337DFF" --variable mainfont="Tahoma" --variable backgroundcolor="#E0E6F1"
Get-Item -path $target
}

If I decide to change the style, I can easily revise the command and recreate the HTML files.
Summary
I am having a lot of fun with this and there's much more that I want to show you. For now, I hope you'll install pandoc and give some of my demonstrations a try. Next time, we'll explore other export options I think you'll find useful.