Monday, October 25, 2021

Saving PowerPoint Deck as a PDF - with PowerShell 7

 This week, I got into a twitter discussion about a presenter posting their slides for delegates. My personal preference is to always share the slides. Often, especially when I was working for an employer, I'd share a PDF of the file rather than the slides. Some decks had had a LOT of effort put in (some by inhouse graphics guys) and giving those animations away was sub-optimal for IP reasons. 

My approach was to post whatever material was appropriate to a DropBox share - and let people have that. I created a unique Bit.Ly short URL, and put that on the first few and final slides. Since the shortend URL never changed, I could put whatever content was relevant - letting attendees know this would all disappear in a few week's time.

What I used to do was to run a short little PowerShell script, during the final development of the deck. If, like SO many presenters, I made a change in the speaker's lounge just before going on - I could run the script just before unplugging and heading to the talk. I could just share https://bit.ly/TFLPresentations and manage the content.

Converting your PowerPoint deck to a PDF is straightforward - I blogged about how to convert a Powerpoint deck into a PDF using PowerShell a long time ago.  The script uses the PowerPoint objects that are part of Office and which Office setup conveniently stores in the .NET Framework's Global Assembly Cache (the GAC). 

After the Twitter conversation, I dusted off this script and to my surprise, it did not work. And the reason is that PowerShell 7 uses .NET and not The .NET Framework. The former does not make use of the GAC, so when I tried to load the appropriate assembly I got this error:

PS C:\Foo> Add-Type -AssemblyName microsoft.office.interop.powerpoint

Add-Type: Cannot find path 'C:\Foo\microsoft.office.interop.powerpoint.dll' because it does not exist.

After a few minutes contemplation I realised what the issue was. And by using Void Tools most excellent SearchEvereything product, I found the assembly at the snappy location of: C:\Windows\assembly\GAC_MSIL\Microsoft.Office.Interop.PowerPoint\15.0.0.0__71e9bce111e9429c\Microsoft.Office.Interop.PowerPoint.dll.

So now I know the location, I could do this to save a single file:

# Define the files
$PPTFile = 'C:\foo\test.pptx'
$PDFFile = 'D:\Dropbox\AAA-TFL Presententations LIVE\test.pdf'
# Add the DLL
$DLLFile = 'C:\Windows\assembly\GAC_MSIL\Microsoft.Office.Interop.PowerPoint\' +
           '15.0.0.0__71e9bce111e9429c\Microsoft.Office.Interop.PowerPoint.dll'
# Add the type
Add-Type -Path $DLLFile
# Create save as PDF option
$SaveOption = [Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType]::ppSaveAsPDF
# Open the PowerPoint Presentation
$PPT = New-Object -ComObject "PowerPoint.Application"
$Presentation = $PPT.Presentations.Open($PPTFile)
# Save it as a PDF and close the presentation
$Presentation.SaveAs($PdfFile,$SaveOption)
$Presentation.Close()
# Close PPT and kill the process to be sure
$PPT.Quit()
Get-Process 'POWERPNT' | Stop-Process

This fragment adds in the necessary DLL, opens the presentation from wherever I have it stored today, and then saves the file as PDF into the DropBox folder. 

I kind of thought that the Quit() method would kill PowerPoint but in my testing, the process hung around hence killing the process at the end of the fragment. Depending on how adventurous you wish to be, you can always wrap this code to get all the PPT files in one folder and save them away. 

No comments: