A desktop publishing application from Microsoft that focuses on page layout and graphic design.
Hi @SaschaMac
Based on my research and testing, I updated the script referenced in the following article: Microsoft Publisher will no longer be supported after October 2026 | Microsoft Support
The updated version converts Publisher files to PowerPoint (.pptx) format instead of PDF.
Here is the full PowerShell script that you can save as a .ps1 file:
param
(
[ValidateNotNullOrEmpty()]
[string]
$Filter,
[switch]
$Recurse
)
if (-not $PSBoundParameters.ContainsKey('Filter')) {
Write-Error "The -Filter parameter is required."
exit 1
}
if (-not ($Filter -like "*.pub")) {
Write-Error "The filter must specify .pub files (e.g., '*.pub' or 'file.pub').";
exit 1;
}
# Clean out any completely dead or frozen background instances before launching the engine
Get-Process -Name "powerpnt" -ErrorAction SilentlyContinue | Stop-Process -Force
Start-Sleep -Seconds 1
try {
$files = Get-ChildItem $Filter -File -Recurse:$Recurse;
if (-not $files) {
Write-Error "No Publisher files found for the filter: $Filter";
exit 1;
}
Write-Output "Running vector element extraction..."
# Add Office and application Interop assemblies
Add-type -AssemblyName Office;
Add-type -AssemblyName Microsoft.Office.Interop.Publisher;
try {
$app = New-Object -ComObject Publisher.Application;
# Capture a snapshot of running instances before starting
$existingPids = (Get-Process -Name "powerpnt" -ErrorAction SilentlyContinue).Id
# Spin up PowerPoint and ensure window references attach cleanly
$pptApp = New-Object -ComObject PowerPoint.Application;
$pptApp.Visible = [Microsoft.Office.Core.MsoTriState]::msoTrue
# Isolate the exact PID of the COM instance we just created
Start-Sleep -Milliseconds 500
$currentPids = (Get-Process -Name "powerpnt" -ErrorAction SilentlyContinue).Id
$pptPid = $currentPids | Where-Object { $_ -notin $existingPids } | Select-Object -First 1
# If it's a single global instance fallback, grab the active running PID safely
if (-not $pptPid) {
$pptPid = (Get-Process -Name "powerpnt" | Sort-Object StartTime -Descending | Select-Object -First 1).Id
}
} catch {
Write-Error "Microsoft Publisher or PowerPoint is not installed or accessible."
exit 1;
}
$successCount = 0;
$failCount = 0;
foreach ($file in $files) {
if ($file.Extension -eq ".pub") {
$fileFullName = $file.FullName;
$pptxFilePath = [System.IO.Path]::ChangeExtension($fileFullName, '.pptx')
if (Test-Path $pptxFilePath) {
Write-Output "Existing PowerPoint file found. Removing: $pptxFilePath"
Remove-Item $pptxFilePath -Force -ErrorAction SilentlyContinue
}
try {
$doc = $app.Open($fileFullName);
} catch {
$failCount++;
Write-Error "Error opening file: $fileFullName $_";
Continue;
}
if (-not($doc)) {
$failCount++;
Write-Error "Failed to open file: $fileFullName";
Continue;
}
try {
$presentation = $pptApp.Presentations.Add([Microsoft.Office.Core.MsoTriState]::msoTrue);
$pageSetup = $doc.PageSetup;
if ($null -ne $pageSetup) {
try {
$presentation.PageSetup.SlideWidth = $pageSetup.PageWidth;
$presentation.PageSetup.SlideHeight = $pageSetup.PageHeight;
} catch {
$presentation.PageSetup.SlideWidth = 960;
$presentation.PageSetup.SlideHeight = 540;
}
} else {
$presentation.PageSetup.SlideWidth = 960;
$presentation.PageSetup.SlideHeight = 540;
}
foreach ($pubPage in $doc.Pages) {
$slide = $presentation.Slides.Add($presentation.Slides.Count + 1, [Microsoft.Office.Interop.PowerPoint.PpSlideLayout]::ppLayoutBlank);
if ($pubPage.Shapes.Count -gt 0) {
try {
$tempMetaPath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), "pub_vector_$($pubPage.PageNumber)_$([Guid]::NewGuid().ToString().Substring(0,8)).emf")
$pubPage.SaveAsPicture($tempMetaPath, [Microsoft.Office.Interop.Publisher.PbPictureResolution]::pbPictureResolutionCommercialPrint_300DPI)
if (Test-Path $tempMetaPath) {
$vectorShape = $slide.Shapes.AddPicture($tempMetaPath, [Microsoft.Office.Core.MsoTriState]::msoFalse, [Microsoft.Office.Core.MsoTriState]::msoTrue, 0, 0, $presentation.PageSetup.SlideWidth, $presentation.PageSetup.SlideHeight)
try {
$ungroupedShapes = $vectorShape.Ungroup()
if ($null -ne $ungroupedShapes) {
foreach ($sh in $ungroupedShapes) {
if ($sh.Type -eq [Microsoft.Office.Core.MsoShapeType]::msoGroup) {
try { $sh.Ungroup() | Out-Null } catch {}
}
}
}
} catch {}
Remove-Item $tempMetaPath -Force -ErrorAction SilentlyContinue
}
} catch {
Write-Error "Error converting layout on page $($pubPage.PageNumber): $_"
}
}
}
if ($presentation.Slides.Count -gt 1 -and $presentation.Slides.Item(1).Shapes.Count -eq 0) {
$presentation.Slides.Item(1).Delete()
}
$presentation.SaveAs($pptxFilePath, [Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType]::ppSaveAsOpenXMLPresentation);
if (Test-Path $pptxFilePath) {
Write-Output "Exported safely to $pptxFilePath.";
$successCount++;
} else {
$failCount++;
Write-Error "Failed to export file: $fileFullName";
}
$presentation.Close();
} catch {
$failCount++;
Write-Error "Error during PowerPoint structure migration: $_";
if ($presentation) {
try { $presentation.Close(); } catch {}
}
}
try { $doc.Close(); } catch {}
}
}
Write-Output "Converted $successCount files with $failCount errors.";
} catch {
Write-Error $_;
} finally {
# Standard programmatic close call
try { if ($doc) { $doc.Close(); } } catch {}
try { if ($presentation) { $presentation.Close(); } } catch {}
try { if ($app) { $app.Quit(); } } catch {}
try { if ($pptApp) { $pptApp.Quit(); } } catch {}
# Break COM object plumbing links in the environment
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($app) | Out-Null
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($pptApp) | Out-Null
[GC]::Collect()
[GC]::WaitForPendingFinalizers()
Start-Sleep -Seconds 1
# Target and force kill the specific tracked process ID
if ($pptPid) {
Write-Output "Targeting specific PowerPoint process handle (PID: $pptPid) for closure..."
Get-Process -Id $pptPid -ErrorAction SilentlyContinue | Stop-Process -Force
Write-Output "PowerPoint window and process successfully closed."
}
}
Throughout my testing, I was able to convert the sample .pub file to a .pptx file, and it remained editable after the conversion.
You can run the script by following these steps:
Step 1: Open PowerShell with administrator permissions.
Step 2: Navigate to the folder containing the PowerShell script.
For example:
cd "C:\Users\Documents"
Step 3: Convert a specific Publisher file to .pptx using a command similar to the example below:
.\<NameofScript>.ps1 -Filter "C:\Users\Documents\MyFile.pub"
Step 4: Wait for the script to complete, then review the resulting PowerPoint file to determine whether it meets your editing requirements.
If the results meet your expectations, you can also process all Publisher files within a directory using:
.\<NameofScript>.ps1 -Filter "C:\Users\Documents\*.pub"
I hope this provides some additional insight.
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.