【问题标题】:Using Powershell to Print a Folder of Text files to PDF (Retaining the Original Base name)使用 Powershell 将文本文件的文件夹打印为 PDF(保留原始基本名称)
【发布时间】:2023-08-11 10:41:01
【问题描述】:

第一次发帖 - 但我认为这是一个很好的帖子,因为我花了 2 天时间研究,与当地专家交谈,但仍然没有完成。

必须在大量文件(.txt 文件)上定期启动单独的打印作业,并且必须通过打印作业将其转换为保留原始基础的本地文件(即通过 PDF 打印机)每个文件的名称。此外,脚本必须是高度可移植的。

如果文件只是简单地转换(而不是打印)、不保留原始基本文件名或打印过程需要在每次打印时进行手动交互,则目标将无法实现。

经过我的研究,这是目前 PowerShell 中的情况:

问题:该脚本执行所有操作,但实际上打印文件的内容。 它遍历文件,并“打印”一个 .pdf,同时保留原始文件名库;但是 .pdf 是空的。

我知道我遗漏了一些关键的东西(即,可能是流使用?);但是经过搜索和搜索一直无法找到它。非常感谢任何帮助。

代码中提到,打印函数的核心是gathered from this post

# The heart of this script (ConvertTo-PDF) is largley taken and slightly modified from https://social.technet.microsoft.com/Forums/ie/en-US/04ddfe8c-a07f-4d9b-afd6-04b147f59e28/automating-printing-to-pdf?forum=winserverpowershell
# The $OutputFolder variable can be disregarded at the moment. It is an added bonus, and a work in progress, but not cirital to the objective.
function ConvertTo-PDF {
    param(
        $TextDocumentPath, $OutputFolder
    )

      Write-Host "TextDocumentPath = $TextDocumentPath"
      Write-Host "OutputFolder = $OutputFolder"
    Add-Type -AssemblyName System.Drawing
    $doc = New-Object System.Drawing.Printing.PrintDocument
    $doc.DocumentName = $TextDocumentPath
    $doc.PrinterSettings = new-Object System.Drawing.Printing.PrinterSettings
    $doc.PrinterSettings.PrinterName = 'Microsoft Print to PDF'
    $doc.PrinterSettings.PrintToFile = $true
    $file=[io.fileinfo]$TextDocumentPath
      Write-Host "file = $file"
    $pdf= [io.path]::Combine($file.DirectoryName, $file.BaseName) + '.pdf'
      Write-Host "pdf = $pdf"
    $doc.PrinterSettings.PrintFileName = $pdf
    $doc.Print()
      Write-Host "Attempted Print: $pdf" 
    $doc.Dispose()
}

# get the relative path of the TestFiles and OutpufFolder folders.

$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
  Write-Host "scriptPath = $scriptPath"
$TestFileFolder = "$scriptPath\TestFiles\"
  Write-Host "TestFileFolder = $TestFileFolder"
$OutputFolder = "$scriptPath\OutputFolder\"
  Write-Host "OutputFolder = $OutputFolder"

# initialize the files variable with content of the TestFiles folder (relative to the script location).

$files = Get-ChildItem -Path $TestFileFolder


# Send each test file to the print job
foreach ($testFile in $files)
{
            $testFile = "$TestFileFolder$testFile"
              Write-Host "Attempting Print from: $testFile" 
              Write-Host "Attemtping Print to  : $OutputFolder"
            ConvertTo-PDF $testFile $OutputFolder
}

【问题讨论】:

    标签: powershell pdf printing automation portability


    【解决方案1】:

    您缺少读取文本文件并将文本传递给打印机的处理程序。它被定义为这样的脚本块:

    $PrintPageHandler =
    {
        param([object]$sender, [System.Drawing.Printing.PrintPageEventArgs]$ev)
    
        # More code here - see below for details
    }
    

    并像这样添加到PrintDocument 对象中:

    $doc.add_PrintPage($PrintPageHandler)
    

    您需要的完整代码如下:

    $PrintPageHandler =
    {
        param([object]$sender, [System.Drawing.Printing.PrintPageEventArgs]$ev)
    
        $linesPerPage = 0
        $yPos = 0
        $count = 0
        $leftMargin = $ev.MarginBounds.Left
        $topMargin = $ev.MarginBounds.Top
        $line = $null
    
        $printFont = New-Object System.Drawing.Font "Arial", 10
    
        # Calculate the number of lines per page.
        $linesPerPage = $ev.MarginBounds.Height / $printFont.GetHeight($ev.Graphics)
    
        # Print each line of the file.
        while ($count -lt $linesPerPage -and (($line = $streamToPrint.ReadLine()) -ne $null))
        {
            $yPos = $topMargin + ($count * $printFont.GetHeight($ev.Graphics))
            $ev.Graphics.DrawString($line, $printFont, [System.Drawing.Brushes]::Black, $leftMargin, $yPos, (New-Object System.Drawing.StringFormat))
            $count++
        }
    
        # If more lines exist, print another page.
        if ($line -ne $null) 
        {
            $ev.HasMorePages = $true
        }
        else
        {
            $ev.HasMorePages = $false
        }
    }
    
    function Out-Pdf
    {
        param($InputDocument, $OutputFolder)
    
        Add-Type -AssemblyName System.Drawing
    
        $doc = New-Object System.Drawing.Printing.PrintDocument
        $doc.DocumentName = $InputDocument.FullName
        $doc.PrinterSettings = New-Object System.Drawing.Printing.PrinterSettings
        $doc.PrinterSettings.PrinterName = 'Microsoft Print to PDF'
        $doc.PrinterSettings.PrintToFile = $true
    
        $streamToPrint = New-Object System.IO.StreamReader $InputDocument.FullName
    
        $doc.add_PrintPage($PrintPageHandler)
    
        $doc.PrinterSettings.PrintFileName = "$($InputDocument.DirectoryName)\$($InputDocument.BaseName).pdf"
        $doc.Print()
    
        $streamToPrint.Close()
    }
    
    Get-Childitem -Path "$PSScriptRoot\TextFiles" -File -Filter "*.txt" |
        ForEach-Object { Out-Pdf $_ $_.Directory }
    

    顺便说一句,这是基于此处的官方 Microsoft C# 示例:

    PrintDocumentClass

    【讨论】:

    • 非常有用,非常感谢。