Generator PDF w Powershell za pomocą Office Word Automation
09.09.2011 | aktual.: 04.02.2012 17:59
Mam tę przyjemność pracować dla ludzi, którzy często operują dużymi plikami biurowymi (doc, pdf, xls). Praca na nich jest w miarę przyjemna, o ile oczywiście mamy wystarczającą ilość pamięci. Gorzej wygląda praca na wielu malutkich plikach
Przyszła dzisiaj do mnie pewna pani i powiedziała, że ma do wydrukowania 717 plików wordowych. Każdy z nich był jednostronicowy. Opcje jakie miała: 1. Po kolei otwierać plik i drukować => Kuuuuupa roboty 2. Wszystkie naraz zaznaczyć i drukować => nie bardzo chciała pamięć współpracować (Partiami tak by długo zeszło) 3. Wykorzystać metodę "Wstaw -> Plik" w Wordzie => niestety się trochę rozjeżdżało i naraz łykało ok. 40 plików.
No więc spiąłem poślady, zakasałem rękawy, chwyciłem za klawirkę i tak oto powstał skrypt w Powershell'u, który zamienia pliki wordowe na PDF.
Po co?
Ano wymyśliłem sobie, że przekształcę wszystkie pliki do PDFa a potem scale je w jeden, ponieważ mam świetne narzędzie do tego. Nazywa się PDFSaM (Split&Merge). Potrafi dzielić i scalać pliki PDF. No i jest do tego darmowy. Większość źródeł WWW odnosi się do wyżej opisanej metody nr 3, która niestety nie zdawała egzaminu.
Mój skrypt działa bardzo prosto. Otwieram plik w Wordzie, zapisuję jako PDF i zamykam plik.
Function PrintTo-PDF { <# .SYNOPSIS Save file as PDF .DESCRIPTION File must be compatible with Microsoft Office Word and Word must be available on the computer .PARAMETER File Instance of System.IO.FileInfo File to be saved as PDF. Must be Word compatible. .EXAMPLE PS C:\> get-childitem | select -last 4 | PrintTo-PDF .EXAMPLE PS C:\> get-item file.doc | PrintTo-PDF -Verbose .INPUTS System.IO.FileInfo .OUTPUTS None .NOTES Author: BlinDRooD #> [CmdletBinding()] Param( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [System.IO.FileInfo]$File ) Begin{ Write-Verbose "Importing libraries" [Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Interop.Word") | Out-Null Write-Verbose "Starting Word application" $Word = New-Object -ComObject Word.Application $PDF = [Microsoft.Office.Interop.Word.WdSaveFormat]::wdFormatPDF $Close = [Microsoft.Office.Interop.Word.WdSaveOptions]::wdDoNotSaveChanges } Process{ Write-Verbose "Openning File $($file.Name)." $Word.Documents.Open($File.FullName) | Out-Null $Newpath = Join-Path -Path $File.DirectoryName -ChildPath ($File.BaseName + ".pdf") Write-Verbose "Saving File $(Split-Path $newpath -Leaf)." $Word.ActiveDocument.SaveAs([ref]$Newpath,[ref]$PDF) | Out-Null Write-Verbose "Closing File $($file.Name)." $Word.ActiveDocument.Close([ref]$Close) | Out-Null } End{ Write-Verbose "Quitting Word application." $word.Quit() } }
Skrypt nie sprawdza, czy pliki są "otwieralne" w Wordzie. Wydajnością też nie powala. 700 plików mielił ok 3‑4 minuty. Przykład użycia
Get-ChildItem | Where { $_.Extension -eq ".doc" } | PrintTo-PDF Get-Item file.doc | PrintTo-PDF -Verbose
Następnie wystarczy pliki scalić do jednego PDFa i mamy kilka godzin pracy z głowy. Skrypt można rozbudować, żeby zmieniał pliki na inne formaty przebierając w dostępnych formatach w WdSaveFormat. Można je wylistować używając poniższego polecenia:
[Microsoft.Office.Interop.Word.WdSaveFormat] | Get-Member –Static –Membertype Property | Select-Object -Property Name
Proste prawda?