Last month, our HR team dumped 240 scanned policy PDFs on my desk. They needed each one as an editable Word document so they could update the 2026 wording. Opening each file by hand in Word would have eaten a full week.
I wrote a short script instead. It finished in about twenty minutes while I got coffee. That’s the moment most admins realize you can convert PDF to Word using PowerShell and never touch a manual “Save As” again.
In this guide, I’ll walk you through the exact approach I used, the COM automation behind it, how to batch a whole folder, and how to handle the errors you’ll definitely hit along the way.
How PDF to Word Conversion Actually Works in PowerShell
PowerShell has no built-in cmdlet for this. A cmdlet is a small built-in command like Get-ChildItem or Copy-Item. There’s no ConvertTo-WordDocument waiting for you.
What PowerShell can do is control other applications through COM automation. COM (Component Object Model) is an old Windows technology that lets one program drive another. Microsoft Word supports it, and Word 2013 and newer can open PDF files directly.
So the recipe is simple:
- Start a hidden Word instance through COM.
- Open the PDF file in Word.
- Save it as
.docx. - Close everything cleanly.
Word does the heavy lifting. PowerShell just orchestrates it.
You need Microsoft Word installed on the machine running the script. This works in both Windows PowerShell 5.1 and PowerShell 7, though I’ve had slightly better COM stability in 5.1. If PowerShell 7 gives you odd COM errors, run the script with powershell.exe instead of pwsh.exe.
Step 1: Convert a Single PDF to Word
Let’s start with one file. Test small before you loop over hundreds.
# Paths
$pdfPath = "C:\HR\Policies\LeavePolicy.pdf"
$wordPath = "C:\HR\Policies\LeavePolicy.docx"
# Start Word through COM
$word = New-Object -ComObject Word.Application
$word.Visible = $false
$word.DisplayAlerts = 0
# Open the PDF (Word converts it on open)
$doc = $word.Documents.Open($pdfPath, $false, $true)
# 16 = wdFormatDocumentDefault (.docx)
$doc.SaveAs([ref]$wordPath, [ref]16)
# Clean up
$doc.Close($false)
$word.Quit()Here’s what each part does.
New-Object -ComObject Word.Applicationlaunches Word in the background. You won’t see a window because$word.Visible = $false.$word.DisplayAlerts = 0turns off pop-up dialogs. Without this, Word will show a “Word will now convert your PDF” prompt and your script will hang forever waiting for a click. This one line saves the most headaches.$word.Documents.Open($pdfPath, $false, $true)opens the file. The second argument skips link updates. The third opens it read-only, so you never accidentally corrupt the source PDF.$doc.SaveAs([ref]$wordPath, [ref]16)writes the Word file. The number16is Word’s format code for.docx. Use0if you need the older.docformat.$doc.Close($false)closes the document without saving again.$word.Quit()shuts Word down.
Pro Tip: In my experience, the number one cause of “my script worked once and then stopped” is orphaned WINWORD.EXE processes. Every failed run leaves a hidden Word instance in memory. After five or six, Word starts refusing new COM connections. Always add cleanup, and check with
Get-Process WINWORDwhen things get weird.
Step 2: Release COM Objects Properly
That first script works, but it leaks memory. PowerShell’s garbage collector doesn’t clean up COM objects on its own.
Add this after $word.Quit():
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($doc) | Out-Null
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($word) | Out-Null
Remove-Variable doc, word
[GC]::Collect()
[GC]::WaitForPendingFinalizers()ReleaseComObject tells .NET to drop its reference to Word. [GC]::Collect() forces garbage collection so the process actually exits.
Skip this, and you’ll find twelve WINWORD processes running after a batch job. I learned that the hard way on a file server that ran out of RAM overnight.
Step 3: Convert PDF to Word in Bulk
Now the real value. Let’s process an entire folder of HR policy PDFs.
$sourceFolder = "C:\HR\Policies"
$outputFolder = "C:\HR\Policies\Word"
if (-not (Test-Path $outputFolder)) {
New-Item -Path $outputFolder -ItemType Directory | Out-Null
}
$word = New-Object -ComObject Word.Application
$word.Visible = $false
$word.DisplayAlerts = 0
$pdfFiles = Get-ChildItem -Path $sourceFolder -Filter *.pdf -File
foreach ($pdf in $pdfFiles) {
$target = Join-Path $outputFolder ($pdf.BaseName + ".docx")
if (Test-Path $target) {
Write-Host "Skipping $($pdf.Name) - already converted" -ForegroundColor Yellow
continue
}
try {
$doc = $word.Documents.Open($pdf.FullName, $false, $true)
$doc.SaveAs([ref]$target, [ref]16)
$doc.Close($false)
Write-Host "Converted: $($pdf.Name)" -ForegroundColor Green
}
catch {
Write-Host "Failed: $($pdf.Name) - $($_.Exception.Message)" -ForegroundColor Red
}
}
$word.Quit()
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($word) | Out-Null
[GC]::Collect()Let’s break down the important lines.
Get-ChildItem -Path $sourceFolder -Filter *.pdf -File grabs only PDF files. The -File parameter (an option you pass to a cmdlet) stops folders from sneaking into the list. If you want to include subfolders, add -Recurse.
$pdf.BaseName gives you the filename without the extension. So LeavePolicy.pdf becomes LeavePolicy, and we bolt .docx onto it.
The Test-Path check plus continue skips files you’ve already converted. That’s the same pattern behind skipping to the next item in a PowerShell ForEach loop — handy when you rerun a job after a crash.
Notice I open Word once outside the loop. Launching Word 240 times would take hours. One instance, many documents.
The Try/Catch block catches conversion failures without killing the whole run. Encrypted or corrupt PDFs will throw, and you want the other 239 files to keep going. If you’re new to this, my guide on Try/Catch in PowerShell covers the pattern in detail.
Step 4: Add Logging So You Know What Failed
Console colors disappear when the script runs as a scheduled task. Write to a log file instead.
$logFile = "C:\HR\Logs\PdfToWord_$(Get-Date -Format 'yyyy-MM-dd').log"
function Write-Log {
param([string]$Message)
$stamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Add-Content -Path $logFile -Value "$stamp - $Message"
}
Write-Log "Starting conversion of $($pdfFiles.Count) files"Then swap your Write-Host calls for Write-Log. Now you can open the log next morning and see exactly which three files choked.
I usually name logs with the date so they don’t overwrite each other. There’s more on this in my post about creating a log file with date and time in PowerShell.
Step 5: Handle Scanned PDFs
Here’s the honest limitation. Word converts text-based PDFs well. Scanned documents are just images inside a PDF wrapper, and Word will produce a Word file containing… an image.
You’ll know immediately: the output .docx is huge and you can’t select any text.
For those, you need OCR. Word has no built-in OCR path through COM. My usual workaround is to flag them and handle them separately:
$docx = Get-Item $target
if ($docx.Length -gt 5MB) {
Write-Log "WARNING: $($pdf.Name) may be a scanned image - review manually"
}It’s a rough heuristic, but it caught 31 of my 240 files correctly. Better than discovering it three weeks later.
Things to Keep in Mind
- Test on a copy first. Point your script at a folder of five sample PDFs before you unleash it on production data. Use
-WhatIfon anyRemove-ItemorMove-Itemcalls you add later. - Word must be installed and licensed. COM automation needs a real Word install. It won’t work on a bare server, and Microsoft doesn’t officially support Office automation in server-side unattended scenarios.
- Set your execution policy. If scripts won’t run, you’ll see a “running scripts is disabled” error. Check my notes on setting the execution policy in PowerShell before blaming your code.
- Watch for locked files. If a PDF is open in Acrobat, Word may fail to read it. Handle the error rather than letting the script die halfway through the batch.
- Never hardcode credentials. If your script reaches a network share, use a stored credential object instead of a plain-text password in the file.
- Expect formatting drift. Complex tables and multi-column layouts rarely survive perfectly. Always spot-check a handful of converted documents.
Frequently Asked Questions
Do I need Microsoft Word installed to convert PDF to Word with PowerShell?
Yes, for this COM-based method. PowerShell drives Word’s own conversion engine, so Word 2013 or newer must be installed locally. Without Word, you’d need a third-party library instead.
Can I run this script on a schedule?
You can, but be careful. Office COM automation is unreliable in non-interactive sessions, and Microsoft doesn’t support it. If you must, run it under a logged-in user account with the “Run only when user is logged on” option.
Why does my script hang and never finish?
Almost always a hidden dialog box. Set $word.DisplayAlerts = 0 before opening any file. Also kill leftover WINWORD processes with Get-Process WINWORD | Stop-Process before rerunning.
Will the formatting stay exactly the same?
No. Word reconstructs the layout, so simple text documents convert cleanly, but complex tables, footnotes, and columns often shift. Always review important documents by hand.
How do I convert only PDFs modified in the last week?
Pipe Get-ChildItem through Where-Object and compare LastWriteTime against a date. For example, filter on $_.LastWriteTime -gt (Get-Date).AddDays(-7).
Can I convert PDFs stored in SharePoint?
Not directly. Download them to a local folder first with PnP PowerShell, convert them, then upload the Word files back to the library.
You now have a working PowerShell script that converts one PDF or an entire folder of them into editable Word documents, complete with error handling and logging. Start with a few test files, confirm the output looks right, then scale up to the full batch once you trust it. I hope you found this article helpful.
You may also like the following tutorials:
- How to convert HTML to PDF in PowerShell
- How to convert JPG to PDF using PowerShell
- How to use Get-ChildItem in PowerShell
- How to log error messages to a file using PowerShell Try/Catch
- How to list scheduled tasks with PowerShell
Bijay Kumar is an esteemed author and the mind behind PowerShellFAQs.com, where he shares his extensive knowledge and expertise in PowerShell, with a particular focus on SharePoint projects. Recognized for his contributions to the tech community, Bijay has been honored with the prestigious Microsoft MVP award. With over 15 years of experience in the software industry, he has a rich professional background, having worked with industry giants such as HP and TCS. His insights and guidance have made him a respected figure in the world of software development and administration. Read more.