Skip to content

Instantly share code, notes, and snippets.

@StartAutomating
Last active April 28, 2026 21:34
Show Gist options
  • Select an option

  • Save StartAutomating/d1d8d2e5fe835ea30bcbacb0b00308b1 to your computer and use it in GitHub Desktop.

Select an option

Save StartAutomating/d1d8d2e5fe835ea30bcbacb0b00308b1 to your computer and use it in GitHub Desktop.
Gist Convert Word Documents to Different Formats
function Convert-Word {
<#
.SYNOPSIS
Converts Word Documents
.DESCRIPTION
Converts Word Documents to a few formats:
* `docx`
* `doct`
* `html`
* `pdf`
* `rtf`
* `xml`
* `xps`
.NOTES
This uses the Word COM Object Model for conversion.
This requires Word to be installed.
Some documents may not open due to trust settings.
.EXAMPLE
Get-ChildItem ./OldWord/ -File |
Where-Object Extension -in '.rtf', '.doc' |
Convert-Word
#>
param(
# The file path containing word documents
[Parameter(Mandatory,ValueFromPipelineByPropertyName)]
[Alias('Fullname')]
[string]
$FilePath,
# The output document type.
[Alias('docx', 'doct', 'html', 'pdf', 'rtf', 'xml', 'xps')]
[string]
$To = 'docx'
)
begin {
# Try to open word
$wordApp = New-Object -ComObject Word.Application
if (-not $wordApp) { throw "Word not installed"}
# and create a queue to hold our files
$convertQueue = [Collections.Queue]::new()
}
process {
# Get all of the files
foreach ($fileInfo in Get-Item -Path $FilePath) {
# check their extension
if ($fileInfo.Extension -notin '.rtf', '.doc','.docx') {
# and warn if it's not a file we can convert.
Write-Warning "$($fileInfo.FullName) is not a word document"
continue
}
# Otherwise, add it to the queue.
$convertQueue.Enqueue($fileInfo)
}
}
end {
# Turn our queue into an array
$queue = $convertQueue.ToArray()
# and prepare our progress bars
$progress = @{id=Get-Random;Activity='Converting Word'}
# Go over each document
for ($docNumber = 0 ; $docNumber -lt $queue.Count; $docNumber++) {
# get the file
$fileInfo = $queue[$docNumber]
# adjust our progress bar
$progress.PercentComplete = $docNumber / $queue.Count * 100
$progress.Status = $fileInfo.Fullname
# and write progress.
Write-Progress @progress
# Figure out where the file is going to go.
$destination =
$fileInfo.FullName.Substring(
0, $fileInfo.FullName.Length - $fileInfo.Extension.Length
) + ".$($to.ToLower())"
# Warn if the files are the same
if ($destination -eq $fileInfo.FullName) {
Write-Warning "Will not overwrite $($fileInfo.Fullname)"
continue
}
try {
# Try to open the file
$openedFile = $wordApp.Documents.Open($fileInfo.FullName)
} catch {
# and error out and continue if we cannot
Write-Error "Could not open '$($fileInfo.Fullname)': $_"
continue
}
# We have to use an old enum to convert to different file formats
# [See This Reference](https://learn.microsoft.com/en-us/office/vba/api/word.wdsaveformat)
# Currently not allowing anywhere near the whole list, for the sake of sanity and security.
switch ($to) {
docx { $openedFile.SaveAs($destination,[ref]16) }
doct { $openedFile.SaveAs($destination,[ref]14) }
html { $openedFile.SaveAs($destination,[ref]8) }
pdf { $openedFile.SaveAs($destination,[ref]17) }
rtf { $openedFile.SaveAs($destination,[ref]6) }
txt { $openedFile.SaveAs($destination,[ref]5) }
xml { $openedFile.SaveAs($destination,[ref]11) }
xps { $openedFile.SaveAs($destination,[ref]18) }
}
# Close the file we've opened.
$openedFile.Close()
# and output the file we've exported.
Get-Item -LiteralPath $destination
}
# Make sure we complete our progress bar so it doesn't leave something on the screen
$progress.Remove('PercentComplete')
$progress.Completed = $true
Write-Progress @progress
# and quit word, so we don't have an open `winword.exe` hanging around.
$wordApp.Quit()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment