Basic Powershell - пакетное преобразование Word Docx в PDF
Я пытаюсь использовать PowerShell для пакетного преобразования Word Docx в PDF - используя script, найденный на этом сайте:
http://blogs.technet.com/b/heyscriptingguy/archive/2013/03/24/weekend-scripter-convert-word-documents-to-pdf-files-with-powershell.aspx
# Acquire a list of DOCX files in a folder
$Files=GET-CHILDITEM "C:\docx2pdf\*.DOCX"
$Word=NEW-OBJECT –COMOBJECT WORD.APPLICATION
Foreach ($File in $Files) {
# open a Word document, filename from the directory
$Doc=$Word.Documents.Open($File.fullname)
# Swap out DOCX with PDF in the Filename
$Name=($Doc.Fullname).replace("docx","pdf")
# Save this File as a PDF in Word 2010/2013
$Doc.saveas([ref] $Name, [ref] 17)
$Doc.close()
}
И я продолжаю получать эту ошибку и не могу понять, почему:
PS C:\docx2pdf> .\docx2pdf.ps1
Exception calling "SaveAs" with "16" argument(s): "Command failed"
At C:\docx2pdf\docx2pdf.ps1:13 char:13
+ $Doc.saveas <<<< ([ref] $Name, [ref] 17)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
Любые идеи?
Также - как мне нужно будет изменить его, чтобы также конвертировать файлы doc (not docX), а также использовать локальные файлы (файлы в том же месте, что и расположение script)?
Извините - никогда не выполнялся сценарий PowerShell...
Ответы
Ответ 1
Это будет работать как с документами, так и с документами docx.
$documents_path = 'c:\doc2pdf'
$word_app = New-Object -ComObject Word.Application
# This filter will find .doc as well as .docx documents
Get-ChildItem -Path $documents_path -Filter *.doc? | ForEach-Object {
$document = $word_app.Documents.Open($_.FullName)
$pdf_filename = "$($_.DirectoryName)\$($_.BaseName).pdf"
$document.SaveAs([ref] $pdf_filename, [ref] 17)
$document.Close()
}
$word_app.Quit()
Ответ 2
Это работает для меня (Word 2007):
$wdFormatPDF = 17
$word = New-Object -ComObject Word.Application
$word.visible = $false
$folderpath = Split-Path -parent $MyInvocation.MyCommand.Path
Get-ChildItem -path $folderpath -recurse -include "*.doc" | % {
$path = ($_.fullname).substring(0,($_.FullName).lastindexOf("."))
$doc = $word.documents.open($_.fullname)
$doc.saveas($path, $wdFormatPDF)
$doc.close()
}
$word.Quit()
Ответ 3
Ни одно из решений, размещенных здесь, не работало для меня в Windows 8.1 (кстати, я использую Office 365). Мой PowerShell каким-то образом не нравится аргументы [ref] (я не знаю, почему, я использую PowerShell очень редко).
Это решение, которое сработало для меня:
$Files=Get-ChildItem 'C:\path\to\files\*.docx'
$Word = New-Object -ComObject Word.Application
Foreach ($File in $Files) {
$Doc = $Word.Documents.Open($File.FullName)
$Name=($Doc.FullName).replace('docx', 'pdf')
$Doc.SaveAs($Name, 17)
$Doc.Close()
}
Ответ 4
Вышеупомянутые ответы все мне не подходят, так как я делал пакетную работу, конвертируя около 70 000 текстовых документов таким образом. Как оказалось, повторение этого в конечном итоге приводит к сбою Word, по-видимому, из-за проблем с памятью (ошибка была каким-то COMException, что я не знал, как разбираться). Итак, мой взлом, чтобы заставить его продолжить, было убить и перезапустить слово каждые 100 документов (произвольно выбранный номер).
Кроме того, когда он иногда рушился, появлялись искаженные pdf файлы, каждый из которых обычно составлял 1-2 kb. Таким образом, при пропуске уже созданных PDF файлов я уверен, что они имеют размер не менее 3 КБ. Если вы не хотите пропускать уже сгенерированные PDF файлы, вы можете удалить этот оператор if.
Извините, если мой код выглядит не очень хорошо, я обычно не использую Windows, и это был разовый взлом. Итак, вот получившийся код:
$Files=Get-ChildItem -path '.\path\to\docs' -recurse -include "*.doc*"
$counter = 0
$filesProcessed = 0
$Word = New-Object -ComObject Word.Application
Foreach ($File in $Files) {
$Name="$(($File.FullName).substring(0, $File.FullName.lastIndexOf("."))).pdf"
if ((Test-Path $Name) -And (Get-Item $Name).length -gt 3kb) {
echo "skipping $($Name), already exists"
continue
}
echo "$($filesProcessed): processing $($File.FullName)"
$Doc = $Word.Documents.Open($File.FullName)
$Doc.SaveAs($Name, 17)
$Doc.Close()
if ($counter -gt 100) {
$counter = 0
$Word.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Word)
$Word = New-Object -ComObject Word.Application
}
$counter = $counter + 1
$filesProcessed = $filesProcessed + 1
}