Category Archives: PowerShell

How to convert a Markdown file to Word document with PowerShell: A One-Line Solution

Overview

Need to convert Markdown files to Word documents quickly and efficiently? 

This one line PowerShell leverages the Word COM object to transform your .md files into professionally formatted .docx documents – no external tools or dependencies required.

The Solution

This script provides a complete Markdown-to-Word converter that handles all common formatting elements. Simply update the file path, paste into PowerShell, and execute.

$mdPath = "C:\Users\Documents\report.md"; if (-not (Test-Path $mdPath)) { Write-Error "❌ Markdown file not found at: $mdPath"; return }; $docPath = [System.IO.Path]::ChangeExtension($mdPath, ".docx"); function Process-InlineFormatting { param($range, $text); $position = 0; $segments = @(); while ($position -lt $text.Length) { if ($text.Substring($position) -match '^\*\*\*(.+?)\*\*\*') { $segments += @{Text = $matches[1]; Bold = $true; Italic = $true}; $position += $matches[0].Length } elseif ($text.Substring($position) -match '^\*\*(.+?)\*\*') { $segments += @{Text = $matches[1]; Bold = $true; Italic = $false}; $position += $matches[0].Length } elseif ($text.Substring($position) -match '^\*(.+?)\*') { $segments += @{Text = $matches[1]; Bold = $false; Italic = $true}; $position += $matches[0].Length } else { $nextAsterisk = $text.IndexOf('*', $position); if ($nextAsterisk -eq -1) { $segments += @{Text = $text.Substring($position); Bold = $false; Italic = $false}; break } else { $segments += @{Text = $text.Substring($position, $nextAsterisk - $position); Bold = $false; Italic = $false}; $position = $nextAsterisk } } }; foreach ($segment in $segments) { if ($segment.Text) { $range.Text = $segment.Text; $range.Font.Bold = $segment.Bold; $range.Font.Italic = $segment.Italic; $range.Collapse(0) } } }; try { $word = New-Object -ComObject Word.Application; $word.Visible = $false; $doc = $word.Documents.Add(); $lines = Get-Content $mdPath -Encoding UTF8; $wdCollapseEnd = 0; $wdBorderBottom = 4; $wdLineStyleSingle = 1; $wdColorBlack = 0; $wdLineWidth150pt = 6; foreach ($line in $lines) { $range = $doc.Content; $range.Collapse($wdCollapseEnd); if ($line -match '^\s*$') { $range.Text = "`r"; $range.Style = "Normal"; continue }; if ($line -match '^\s*[-]{3,}\s*$') { $range.Text = "`r"; $range.Style = "Normal"; $range.ParagraphFormat.Borders.Item($wdBorderBottom).LineStyle = $wdLineStyleSingle; $range.ParagraphFormat.Borders.Item($wdBorderBottom).Color = $wdColorBlack; $range.ParagraphFormat.Borders.Item($wdBorderBottom).LineWidth = $wdLineWidth150pt } elseif ($line -match '^(#{1,6})\s+(.+)') { $headerLevel = $matches[1].Length; $headerText = $matches[2]; Process-InlineFormatting -range $range -text $headerText; $range.Style = "Heading $headerLevel"; $range.Collapse($wdCollapseEnd); $range.Text = "`r" } elseif ($line -match '^\s*[-*+]\s+(.+)') { $listText = $matches[1]; Process-InlineFormatting -range $range -text $listText; $range.Style = "List Bullet"; $range.Collapse($wdCollapseEnd); $range.Text = "`r" } elseif ($line -match '^\s*\d+\.\s+(.+)') { $listText = $matches[1]; Process-InlineFormatting -range $range -text $listText; $range.Style = "List Number"; $range.Collapse($wdCollapseEnd); $range.Text = "`r" } else { Process-InlineFormatting -range $range -text $line; $range.Style = "Normal"; $range.Collapse($wdCollapseEnd); $range.Text = "`r" } }; $doc.SaveAs([ref] $docPath); $doc.Close(); $word.Quit(); [System.Runtime.Interopservices.Marshal]::ReleaseComObject($word) | Out-Null; [System.GC]::Collect(); [System.GC]::WaitForPendingFinalizers(); Write-Host "✅ Markdown converted to Word document at $docPath" } catch { Write-Error "❌ An error occurred: $_"; if ($doc) { $doc.Close($false) }; if ($word) { $word.Quit(); [System.Runtime.Interopservices.Marshal]::ReleaseComObject($word) | Out-Null } }

How to Use

Step 1: Update the file path at the beginning of the script

$mdPath = "C:\Users\Documents\report.md"

Step 2: Copy the entire one-line script above

Step 3: Paste into PowerShell and press Enter

Step 4: Your Word document will be created in the same directory with a .docx extension

Supported Markdown Features

The script converts the following Markdown elements to their Word equivalents:

Headers

markdownDownloadCopy code# Heading 1
## Heading 2
### Heading 3

Converts to Word’s built-in Heading 1, 2, 3 styles (up to Heading 6)

Text Formatting

  • Bold: **text** → text
  • Italic: *text* → text
  • Bold + Italic: ***text*** → text

Lists

Bullet Lists:

markdownDownloadCopy code- Item one
* Item two
+ Item three

Numbered Lists:

markdownDownloadCopy code1. First item
2. Second item
3. Third item

Horizontal Rules

markdownDownloadCopy code---

Creates a horizontal line with bottom border formatting

Special Characters

UTF-8 encoding support ensures proper handling of international characters, accents, and special symbols.

How It Works

Inline Formatting Parser

The script includes a custom function that processes inline formatting by:

  1. Parsing text character-by-character
  2. Identifying markdown formatting markers (******)
  3. Extracting the text within markers
  4. Applying appropriate Word formatting (Bold, Italic, or both)
  5. Removing the markdown syntax

Document Processing

The script:

  • Reads the markdown file with UTF-8 encoding
  • Processes each line sequentially
  • Applies regex pattern matching to identify markdown elements
  • Uses Word COM object methods to apply appropriate styles
  • Handles blank lines to preserve document spacing
  • Properly manages Word styles to prevent formatting conflicts

COM Object Management

The script properly initializes and cleans up Word COM objects to prevent memory leaks and ensure smooth execution.

Key Features

✅ No External Dependencies – Uses built-in PowerShell and Word COM automation
✅ UTF-8 Support – Handles international characters correctly
✅ Inline Formatting – Processes bold and italic within any text element
✅ Professional Output – Uses Word’s native styles for consistent formatting
✅ One-Line Execution – Paste and run without saving to a file
✅ Error Handling – Includes try-catch blocks for robust execution
✅ Memory Management – Properly releases COM objects after execution

Use Cases

This script is perfect for:

  • Documentation Automation – Convert markdown documentation to Word format for distribution
  • Report Generation – Transform markdown reports into professional Word documents
  • Content Migration – Batch convert markdown files to Word format
  • Workflow Integration – Incorporate into larger PowerShell automation scripts
  • Quick Conversions – Ad-hoc conversion without installing additional tools

Customization Options

Change Output Location

Modify the $docPath variable to specify a different output location:

$docPath = "C:\Output\CustomName.docx"

Make Word Visible

Set $word.Visible = $true to watch the conversion process in real-time

Adjust Border Styling

Modify the Word constants to customize horizontal rule appearance:

$wdLineWidth150pt = 6  # Change border thickness
$wdColorBlack = 0 # Change border color

Requirements

  • Windows operating system
  • Microsoft Word installed
  • PowerShell 5.1 or later
  • Appropriate permissions to create COM objects

Technical Details

Word COM Constants Used:

  • wdCollapseEnd = 0 – Collapse range to end position
  • wdBorderBottom = 4 – Bottom border identifier
  • wdLineStyleSingle = 1 – Single line style
  • wdColorBlack = 0 – Black color value
  • wdLineWidth150pt = 6 – Border width (1.5pt)

Regex Patterns:

  • Headers: '^(#{1,6})\s+(.+)' – Requires space after #
  • Bullet Lists: '^\s*[-*+]\s+(.+)' – Supports -, *, + markers
  • Numbered Lists: '^\s*\d+\.\s+(.+)' – Matches numbered items
  • Horizontal Rules: '^\s*[-]{3,}\s*$' – Three or more hyphens

Conclusion

This PowerShell one-liner provides a powerful, dependency-free solution for converting Markdown to Word documents. Whether you’re automating documentation workflows or need a quick conversion tool, this script delivers professional results with minimal setup.

Simply update the file path, paste the script, and let PowerShell handle the rest!

How to run a PowerShell script

So you have a PowerShell script and you just want to run it without messing around with permissions, policies, signing it or any other crap. (Yes yes I know all those things are vital for system wide security but you’re in a hurry damn it!)

Right click PowerShell and run as administrator.


When the terminal is open run the following line:


Set-ExecutionPolicy RemoteSigned


When prompted type the letter A and press Enter (if applicable).


Run the below including “&” at start of line with reference to your script, i.e.


& “C:\YourTestDirectory\YourTestFile.ps1”

How to Sort Files into Year-Month-Day Folders

Below is example PowerShell code to create a directory structure from file creation dates.

A use case for this code might be a need to organize a collection of files stored on an SFTP server or NAS. The code can be modified to loop through the files putting each one into sub directories corresponding to nested folders organized into Year\Month\Day folders.

To use the logic first create a test folder on your computer.
Then copy the logic below to a text file editor and find and replace the following with reference to your test folder location:

C:\YourTestDirectory

Then save the code below as a PowerShell file called “DirFromDate.ps1” into your test folder.

To then run the file open up PowerShell and paste the following line:

Set-ExecutionPolicy RemoteSigned

Hit return and then enter the letter A if requested.

Then enter the following replacing “YourTestDirectory” with your actual test directory location:

& “C:\YourTestDirectory\DirFromDate.ps1”

Hit return.

<#
.SYNOPSIS
   <A brief description of the script>
.DESCRIPTION
   <A detailed description of the script>
.PARAMETER <paramName>
   <Description of script parameter>
.EXAMPLE
   <An example of using the script>
#>

#FIND AND REPLACE THE FOLLOWING WITH A DIRECTORY
C:\YourTestDirectory

#How Run In Powershell
#Open Powershell terminal and run the folling line:
#Set-ExecutionPolicy RemoteSigned
#Type A and press Enter (if applicable).
#Run the below including "&" at start of line
#& "C:\YourTestDirectory\DirFromDate.ps1"

#VARIABLES
#Define folder variables
$workingFolder = "C:\YourTestDirectory\"
#Define file variable
$testFile = "\ThisIsATestFile.txt"
$testFile = $workingFolder + $testFile


###############################################
#(!!DO NOT ALTER SCRIPT PASSED THIS POINT!!)
###############################################
#Write variables to terminal
Write-Host "Filepath: $workingFolder";

#Create test File

New-Item $testFile

#Define source directory variable
$files = Get-ChildItem -Path $workingFolder 

#3 steps: move raw files to azure, zip file, move zipped file to azure
foreach ($file in $files)
{
		#FileName
		Write-Host "File: $file";
		#Get file creation date from file name
		$fileDate = $file.CreationTime.ToString("ddMMyyyy")
		#Get file creation date (last time data was written to file) from file name
		#$fileDate = $file.LastWriteTime.ToString("ddMMyyyy")
		Write-Host "Filedate: $fileDate";
		$fileDate = $fileDate.Substring($fileDate.Length - 4) + "\" + $fileDate.Substring(3, 2) + "\" + $fileDate.Substring(0, 2)
		Write-Host "Filedate: $fileDate";
		$DirectoryStructure = $workingFolder + "\" + $fileDate
		Write-Host "DirStructure: $DirectoryStructure";

}
md $DirectoryStructure

Move-Item -Path $testFile -Destination $DirectoryStructure