嘿,朋友!如果你现在正盯着屏幕上堆积如山的PDF、Word文档叹气,手动一个个点击“打印”,那咱们得好好聊聊了。我是 Agnes,在这个领域摸爬滚打多年,见过太多人把时间浪费在重复劳动上。今天,我不给你整那些枯燥的教科书定义,咱们直接上手,用 Windows 最强大的“隐藏技能”——批处理(Batch)和 PowerShell,把你的打印工作流自动化。

别被“代码”两个字吓跑,我保证,这里的每一个字符都有它存在的意义,而且学会了,你下午就能提前下班。

为什么你要学这个?先看看那些头疼的场景

想象一下:法务部发来一份100页的合同,你需要打印其中第10、20、35页;或者,销售团队有50份报价单分散在不同的文件夹里,明天就要开会,你却还在纠结怎么全选打印?

手动操作?太慢了,而且容易出错。

批处理的核心思想很简单:让电脑帮你跑腿,你只管喝茶。 我们利用 Windows 自带的 rundll32printui.dll 以及 PowerShell 的 COM 对象,来实现无需打开文档即可后台打印、指定范围打印、自动选择打印机等功能。

基础篇:一行命令搞定简单打印

首先,我们要打破一个误区:批处理打印,不需要你安装额外的软件,Windows 本身就有足够强大的工具。

1. 使用 rundll32 进行静默打印

这是最经典、兼容性最好的方法。rundll32.exe 是 Windows 的一个系统组件,它可以调用 DLL 中的函数。对于打印,我们利用的是 shell32.dll 中的 ShellExecuteEx 或者更直接的打印接口。

但其实,对于大多数普通文档(如 .txt, .pdf),最简单的方式是直接调用系统的关联程序,并传递 /p 参数(在 Windows 中,/p 通常代表“打印”)。

示例:打印单个 PDF 文件

假设你有一个文件 report.pdf,你想直接打印,而不打开 PDF 阅读器。

@echo off
:: 关闭回显,让屏幕清爽一点
set "FilePath=C:\Users\YourName\Documents\report.pdf"
set "PrinterName=Microsoft Print to PDF" :: 或者你的默认打印机名称

:: 方法一:使用 rundll32 调用 shell 执行打印
:: 注意:这种方法依赖于文件关联。如果 .pdf 关联的是 Adobe Reader,它会尝试打开并打印。
:: 更推荐的方法二,使用 PowerShell 调用 COM 对象,更稳定。

echo 正在打印 %FilePath% ...
start "" /wait "%FilePath%" /p

:: /p 参数的意思是“打印后退出程序”(适用于支持该参数的应用,如 Word, PowerPoint)
:: 如果应用不支持 /p,我们可以使用下面的 PowerShell 方案。

这里有个坑start /p 并不是对所有程序都有效。Adobe Acrobat 支持 /p,但很多其他软件可能不支持。所以,我们需要更“底层”且通用的方法——PowerShell

2. PowerShell:打印 PDF 的“黑科技”

PowerShell 是 Windows 1011 的标配,它可以通过 COM 对象直接控制 Adobe Acrobat 或其他 PDF 阅读器。这是目前最可靠的批量打印 PDF 的方法。

示例:使用 PowerShell 打印 PDF

# 保存为 print_pdf.ps1
param(
    [string]$FilePath = "C:\Users\YourName\Documents\report.pdf",
    [string]$PrinterName = "" # 留空则使用默认打印机
)

# 检查文件是否存在
if (-not (Test-Path $FilePath)) {
    Write-Error "文件不存在: $FilePath"
    exit 1
}

# 创建 AcroExch.App 对象(需要 Adobe Acrobat 安装)
$acroApp = New-Object -ComObject AcroExch.App
$acroDoc = $acroApp.Open($FilePath, "")

if ($null -eq $acroDoc) {
    Write-Error "无法打开文档: $FilePath"
    exit 1
}

# 指定打印机(可选)
if ($PrinterName -ne "") {
    $acroDoc.PrintPages(0, $acroDoc.GetNumPages() - 1, $true, $PrinterName)
} else {
    # 使用默认打印机打印所有页面
    $acroDoc.PrintPages(0, $acroDoc.GetNumPages() - 1, $true)
}

# 关闭文档,释放对象
$acroDoc.Close($true)
$acroApp.Exit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($acroDoc) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($acroApp) | Out-Null

Write-Host "打印任务已发送至: $PrinterName 或 默认打印机"

如何运行? 右键点击 .ps1 文件,选择“使用 PowerShell 运行”。或者在命令行中执行:

powershell -ExecutionPolicy Bypass -File print_pdf.ps1

为什么这样更好? 因为它不依赖文件关联,直接控制 Adobe 核心,稳定、快速,而且可以精确控制打印页数。

进阶篇:批量打印多个文件,并按页码范围过滤

现在,假设你有 10 个 PDF 文件,你只想打印每个文件的第 5 到 10 页,并且全部发送到同一台打印机。这用纯批处理会很复杂,但用 PowerShell 脚本结合循环,就非常简单。

场景:批量打印指定文件夹下的所有 PDF,每份只打印前 5 页

完整脚本示例:batch_print.ps1

# 定义配置
$SourceFolder = "C:\Users\YourName\Documents\Invoices"
$OutputPrinter = "HP LaserJet Pro"  # 替换为你的实际打印机名称
$PagesStart = 1
$PagesEnd = 5

# 获取所有 PDF 文件
$Files = Get-ChildItem -Path $SourceFolder -Filter "*.pdf" | Where-Object { -not $_.PSIsContainer }

if ($Files.Count -eq 0) {
    Write-Host "在 $SourceFolder 下未找到 PDF 文件。"
    exit 0
}

Write-Host "找到 $($Files.Count) 个 PDF 文件,开始批量打印..."

# 创建 Acrobat 应用对象(只创建一次,提高效率)
$acroApp = New-Object -ComObject AcroExch.App
$acroApp.Hide() # 隐藏窗口,避免屏幕闪烁

foreach ($File in $Files) {
    Write-Host "正在处理: $($File.Name)"
    
    $acroDoc = $acroApp.Open($File.FullName, "")
    
    if ($null -ne $acroDoc) {
        $totalPages = $acroDoc.GetNumPages()
        
        # 检查是否需要限制页数
        $endPage = if ($PagesEnd -gt $totalPages) { $totalPages } else { $PagesEnd }
        
        try {
            # 打印指定页码范围
            $acroDoc.PrintPages($PagesStart - 1, $endPage - 1, $true, $OutputPrinter)
            Write-Host "  -> 已发送 $($File.Name) 的第 $PagesStart 到 $endPage 页到 $OutputPrinter"
        }
        catch {
            Write-Host "  -> 打印失败: $($File.Name) - $($_.Exception.Message)"
        }
        finally {
            $acroDoc.Close($false) # 关闭文档但不保存
            [System.Runtime.Interopservices.Marshal]::ReleaseComObject($acroDoc) | Out-Null
        }
    } else {
        Write-Host "  -> 无法打开文档: $($File.Name)"
    }
}

$acroApp.Exit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($acroApp) | Out-Null
Write-Host "所有任务完成!"

这段代码的精妙之处:

  1. 对象复用AcroExch.App 只创建一次,遍历过程中复用,避免频繁启动/关闭 Adobe 进程,速度提升巨大。
  2. 错误处理try-catch-finally 确保即使某个文件打印失败,也不会中断整个流程。
  3. 进度反馈Write-Host 让你实时看到哪个文件正在处理,心里有底。

高级篇:与 Task Scheduler 结合,实现真正的自动化

学会写脚本只是第一步。真正的“自动化办公”意味着你不需要手动运行脚本。你可以让它在特定时间、或当文件放入特定文件夹时自动执行。

1. 创建 Windows 任务计划

假设你希望每天早上 9 点,自动打印 C:\Inbox\Pending 文件夹下所有的新 PDF 文件。

步骤:

  1. 打开“任务计划程序”(Taskschd.msc)。
  2. 点击“创建基本任务”。
  3. 名称:AutoPrintPDF,触发器:每天 9:00。
  4. 操作:启动程序,程序脚本填 powershell.exe,添加参数填:
    
    -ExecutionPolicy Bypass -File "C:\Scripts\batch_print.ps1"
    
  5. 完成。

这样,你每天早上 9 点都不用碰电脑,打印机就会自动开始工作。

2. 使用 Folder Redirection 或 PowerShell 监视文件夹

更高级的做法是:当有新文件放入文件夹时,立即触发打印。这需要用到 PowerShell 的 FileSystemWatcher

示例:实时监视文件夹并打印

$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "C:\Inbox\Pending"
$watcher.Filter = "*.pdf"
$watcher.IncludeSubdirectories = $false
$watcher.EnableRaisingEvents = $true

$action = {
    $file = $event.SourceEventArgs.FullPath
    Write-Host "$(Get-Date): 检测到新文件 $file,开始打印..."
    
    # 调用上面的打印逻辑
    $acroApp = New-Object -ComObject AcroExch.App
    $acroDoc = $acroApp.Open($file, "")
    if ($null -ne $acroDoc) {
        $acroDoc.PrintPages(0, $acroDoc.GetNumPages() - 1, $true, "HP LaserJet Pro")
        $acroDoc.Close($false)
    }
    $acroApp.Exit()
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($acroDoc) | Out-Null
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($acroApp) | Out-Null
}

Register-ObjectEvent $watcher "Created" -Action $action
Write-Host "正在监视文件夹: C:\Inbox\Pending,按 Ctrl+C 退出..."
while ($true) { Start-Sleep -Seconds 1 }

把这个脚本做成一个 Windows 服务,或者用 schtasks 设置它开机自启,你就拥有了一个“永不停歇的打印机器人”。

常见陷阱与解决方案

1. 打印机名称不对

问题:脚本报错“打印机未找到”。 解决:在命令行运行 wmic printer get name 查看准确的打印机名称,注意空格和大小写。

2. Adobe Acrobat 未安装或版本不兼容

问题AcroExch.App 对象创建失败。 解决:确保安装了 Adobe Acrobat(不仅是 Reader,最好是完整版 Acrobat,因为 COM 接口在 Reader 中可能受限)。如果必须用 Adobe Reader,可以尝试调用 ShellExecute 并传入“print”操作,但稳定性不如 COM 对象。

3. 64位 vs 32位进程

问题:脚本在 64 位 PowerShell 中运行,但 Adobe 是 32 位的,导致 COM 对象无法创建。 解决:使用 32 位 PowerShell 运行脚本:

%WINDIR%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -File your_script.ps1

4. 打印顺序混乱

问题:多个文件同时打印,顺序错乱。 解决:在脚本中加入 Start-Sleep,每个文件打印后等待几秒,给打印机缓冲时间。

总结:从“打工”到“管理”

朋友,今天咱们聊的不仅是打印,更是一种思维:如何让机器服务于你,而不是你服务于机器。

批处理和 PowerShell 不是程序员专属,它们是现代办公者的“超能力”。当你能够用几行代码解决重复一天的工作,你就把时间还给了自己——去读书、去陪伴家人、去提升核心技能。

下一步行动建议:

  1. 先别急着写复杂脚本,先从最简单的 powershell -Command "Start-Process -FilePath 'report.pdf' -Verb Print" 开始体验。
  2. 逐步替换你日常重复的打印任务。
  3. 把常用脚本保存在固定位置,配上快捷键,形成你的“自动化工作流”。

记住,自动化不是为了偷懒,而是为了更高效地创造价值。祝你打印自由,下班快乐!