简介:一份面向Windows运维人员及受打印故障困扰用户的实用工具包,用于解决Print Spooler打印服务意外停止或未能随系统启动而导致的无法打印问题。程序会在后台监测服务状态,一旦发现异常便自动重启,确保打印队列持续可用,尤其适合企业办公、多用户共享打印等依赖稳定输出的场景。资源共10个文件,压缩包仅22KB,包含启停配置脚本(SetupServer.bat、unInstallServer.bat)、服务监控程序WSDemoByTime.exe及其配置文件、详细操作手册(docx)和安装/代码分析日志,体量精简但功能配套完整。已有4020人学习下载。使用者可参照操作手册快速部署自动守护机制,也可通过日志排查安装或运行异常,兼顾实用性与排错参考价值。
1. 打印服务 print spooler 自动启动程序:这个问题通常不是“启动一下”就能收工
打印服务 print spooler 自动启动程序,说白了就是让 Windows 的后台打印服务在开机时自己跑起来,并且服务一旦退出还能被重新拉起来。我碰到过不止一次,新装好的系统用了一个月,打印机突然打不了,打开 services.msc 一看,Print Spooler 停在“禁用”或“停止”状态,手动启动就好了,可重启电脑又犯。这个问题最坑的点在于,Print Spooler 明明是开机自动启动的默认服务,但优化软件、残留驱动、系统崩溃都可能悄悄改掉它的启动方式。这篇文章要解决的问题,就是让 Print Spooler 在任何场景下都能可靠自动启动,并给出便于批量部署的开机脚本和守护计划任务。
2. print spooler 为什么不会自动启动:启动类型、恢复选项与第三方优化软件的坑
要写自动启动程序,先得知道 Windows 是怎么决定一个服务开不开机的。Print Spooler 能否自启,只取决于两个地方:服务启动类型,和服务恢复选项。很多运维只改了启动类型,没看恢复选项,导致服务崩了不会自己起来;还有些人只写了计划任务,却没搞清为什么服务会被禁用。这一章把这两条链路上的坑逐个讲清楚,后面你才能判断该用哪种方案去守。
2.1 先看服务本身:print spooler 的启动类型和默认状态
在 Windows 的服务列表里,Print Spooler 的显示名是“Print Spooler”,服务名是Spooler。想要确认当前配置,不要只看 services.msc 的界面,那个界面刷新慢,而且“自动(延迟启动)”和“自动”长得太像。用命令更可靠。在管理员 CMD 里执行:
sc qc Spooler输出里会有一行START_TYPE: 2 AUTO_START。这个数值你需要背下来:2 是自动启动,3 是手动启动,4 是禁用。如果看到START_TYPE: 3或4,说明服务已经被改过。另一个常见状态是2 AUTO_START但同时注册表里DelayedAutoStart=1,这表示“自动(延迟启动)”。Print Spooler 这种服务,我不建议延迟启动,原因后面第 5 章会讲到。
系统默认情况下 Print Spooler 就是 2,但为什么很多人开不了机?原因多半是注册表被改或者恢复选项没有设置。查看注册表项更直观:
reg query HKLM\SYSTEM\CurrentControlSet\Services\Spooler /v StartStart的值和上面 sc 输出的数字一一对应。这个值就是 Windows 开机时服务控制管理器读取的唯一依据,读出来是 2 就自动启,读到 4 就理直气壮地不启。也可以把服务管理器里的启动类型改成自动,但 GUI 操作有个隐蔽问题:如果你在服务停止状态下把启动类型从“禁用”改成“自动”,它不会自动帮你把服务拉起来,你还得再点一次“启动”。而命令行sc config Spooler start= auto只是改配置,同样不会立即启动服务。
2.2 罪魁祸首:优化软件、注册表与组策略如何改掉启动类型
“Windows 优化大师设置了开机启动也无法开机自动启动”这种问题,我隔三差五就能在客户机器上看到。第三方优化工具很喜欢把 Print Spooler 当成“无用服务”禁用,它们背后做的事就是修改上面那个注册表Start值,把 2 改成 4。你以为在软件里点了“恢复开机启动”,但软件本身可能只负责改它自己的配置,根本没有回写 Windows 服务注册表。
遇到这种反复被改的情况,先查注册表是不是在每次开机后被某个进程重写。可以看注册表键的权限:右键HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Spooler,选择“权限”,把Users和Power Users的“完全控制”去掉,只留“读取”。这样普通优化软件以当前用户运行时,就没有权限改Start值了。如果你用的是真正的 Administrator 账户运行优化软件,那它仍然能改,所以最彻底的办法还是卸载这类带“实时监控”的优化工具。
还有一种情况是域策略。企业环境里,本地安全策略或 GPO 可以强制指定服务的启动模式。你本机用sc config改成自动,过几分钟组策略刷新,又被拉回禁用。判断方法是在命令行执行gpresult /r,看有没有应用“系统服务”相关的策略。如果有,需要联系域管理员在 GPO 里调整,本地怎么折腾都是白搭。我在一个教育机构的机房踩过这个坑,打印机一直不工作,最后发现是域策略统一禁用了 Spooler,理由是“减少攻击面”。
2.3 服务恢复选项:崩溃后只会傻站着的默认设置
启动类型负责“开机启不启”,服务恢复选项负责“运行中崩了之后怎么办”。很多老机器上 Print Spooler 的恢复选项是默认的“不操作”,这意味着服务意外停止后,系统不会自动把它拉起来,你的打印机就一直卡着。查看当前恢复配置:
sc qfailure Spooler如果结果里RESET_AT_SYSTEM_START后面跟着不操作,那就说明崩了只能靠人肉。把恢复选项改成自动重启服务:
sc failure Spooler reset= 86400 actions= restart/restart/restart这个命令的意思是:系统启动后 86400 秒(1 天)内,如果服务连续崩溃三次,每次都尝试重新启动服务;超过 1 天没有崩溃,失败计数重置。actions=后面必须写三个操作,不能只写一个restart,否则命令不生效。我第一次写这个命令的时候,把restart/restart/restart写成了restart/ restart,中间带了空格,sc 不报错,但实际恢复策略没有变。这也是为什么命令写完一定要再sc qfailure Spooler确认一次。
恢复选项是“崩溃后兜底”,自动启动是“开机时拉起”,两者不能互相替代。后面要写的自动启动程序里,我会把这两件事都做掉。下一章先给你四种从轻到重的做法,按需选择。
3. 把 print spooler 做成开机必启的四种做法:从服务命令到守护计划任务
方案按“稳、简、活、锁”四个层次来选:单机排查用服务管理器和 sc 命令最快;批量装机用 PowerShell 批量推送;想要服务崩了也能自愈,要靠计划任务做守护;想防止别人再改,就去注册表加权限。下面这四个做法我基本都在生产环境里用过,不追求复杂,关键是每一步可复现、可验证。
3.1 最标准:在服务管理器和 sc 命令里确认启动类型
先做最基础的一件事:把启动类型改成自动。图形界面操作是 Win+R 打开services.msc,找到“Print Spooler”,双击,把启动类型改成“自动”,如果服务处于停止状态,还要点“启动”。这个流程适合单机临时解决,但我不建议在批量环境里用,因为图形界面没法直观看到注册表里的实际值。
命令行版本更明确:
sc config Spooler start= auto注意start=后面的空格不能省。sc 命令有个迷惑点:常规写法是start=auto,但 sc 要求等号后面必须要一个空格,否则会提示“参数错误”。这是一个合规但极容易被忽略的语法。改完之后用sc qc Spooler验证输出里的START_TYPE是否为2 AUTO_START。
这里还要提一个坑:sc config只是改启动配置,不会立刻把服务拉起来。如果你当前服务是停止的,还需要再执行:
net start Spooler如果服务当前是禁用状态,net start会报错“服务名无效或被禁用”。所以稳妥的顺序永远是先 config 改自动,再 net start。
3.2 批量部署的正规姿势:sc 脚本与 PowerShell Set-Service
几十台电脑挨个sc config太原始,我一般用 PowerShell 的Set-Service加远程执行。Set-Service 比起 sc 的好处是同时支持批量、异常处理和返回结果。先看单机用法:
Set-Service -Name Spooler -StartupType Automatic Start-Service -Name Spooler注意Set-Service -StartupType在 Windows PowerShell 5.1 里已经可用,如果你的机器还在用旧版本,就退回 sc 命令。批量操作时,把机器名放在一个数组里,用Invoke-Command远程执行:
$machines = @("PC01", "PC02", "PC03") foreach ($m in $machines) { Invoke-Command -ComputerName $m -ScriptBlock { Set-Service -Name Spooler -StartupType Automatic Start-Service -Name Spooler } }这个方案的先决条件是目标机器已开启 WinRM,并且当前账户有远程管理权限。在很多域环境里,这是现成的;如果是在对等的工作组里,就需要先配置 WinRM,否则会连不上。还有一点:Start-Service在服务本来就在运行时会提示“服务已经运行”,但不会返回错误,所以不用额外判断状态。
3.3 做守护者:用计划任务在服务停止时自动拉起来
服务启动类型设置为自动,只解决开机问题。如果 Spooler 在运行中崩溃,自动启动类型不会帮你恢复,恢复选项又可能被系统策略覆盖。这时候最可靠的做法是加一个计划任务当作“守护程序”,定时检查服务状态,发现停了就拉起来。
我常用的计划任务是每 5 分钟执行一次 PowerShell 检查脚本。在管理员 CMD 里创建:
schtasks /Create /TN "SpoolerGuard" /TR "powershell.exe -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File \"C:\Scripts\SpoolerAutoStart.ps1\"" /SC MINUTE /MO 5 /RU SYSTEM /RL HIGHEST /F这里/RU SYSTEM让任务以系统账户运行,等价于最高权限,不需要输入密码;/RL HIGHEST保证脚本能改服务状态。/SC MINUTE /MO 5是每 5 分钟触发一次。注意File参数的路径或文件名带有空格时,需要用\"把内部引号转义,我之前在这个地方漏了转义,导致计划任务创建成功,但运行时报“无法找到文件名”。
创建后验证任务状态:
schtasks /Query /TN SpoolerGuard /V看“上次运行时间”和“上次结果”,如果“上次结果”是 0,说明脚本执行成功。计划任务的缺点是它只是轮询,服务停止后最多有 5 分钟空窗期。对打印服务这种不是特别实时敏感的服务来说,5 分钟足够,但如果你的应用对打印延迟要求很高,就需要事件触发,这个留在最后一章讲。
3.4 用注册表锁死启动类型:reg 命令与权限保护
前面几种做法都在“改设置”,但如果罪魁祸首是优化软件或用户误操作,过两天可能又被改回去。想要长期锁死启动类型,最底层的手段是直接修改注册表并回收权限。
先把 Start 值写死为自动:
reg add HKLM\SYSTEM\CurrentControlSet\Services\Spooler /v Start /t REG_DWORD /d 2 /f然后打开regedit,定位到HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Spooler,右键“权限”,在弹窗里点“高级”,把Users的权限修改为“读取”,并且勾选“应用到 只有这个键”。这样普通用户或运行为普通用户的优化程序,就再也没有权限把Start改成 4 了。
要注意的是,如果优化软件以管理员权限运行,仍然可以通过提权获得写入权限。所以注册表权限只能防普通用户,不能作为安全边界。更关键的是,这个注册表路径在 64 位系统上有键重定向的概念,如果你用 32 位工具去读取,会看到完全不同的视图。我的血泪经验是:不要在 32 位 PowerShell 里改这个键,否则服务管理器看到的还是旧值。统一用 64 位 PowerShell 或reg.exe操作就不会踩这个坑。
4. print spooler 自动启动程序落地:一个自带日志的 PowerShell 脚本
前面已经把原理和单个命令讲完了,这一章整合成一个真正可以扔到生产环境跑的脚本。脚本的设计目标是:开机时运行,如果 Spooler 是禁用状态就改成自动;如果是停止状态就启动;如果已经在运行就跳过;任何情况都写日志,方便事后排查。它同时可以被计划任务、开机脚本、登录脚本调用,退出码有明确含义。
4.1 脚本逻辑:先检查、再修正、最后拉起
把下面这段保存为SpoolerAutoStart.ps1:
#Requires -RunAsAdministrator param( [string]$ServiceName = "Spooler", [int]$TimeoutSeconds = 30, [string]$LogFile = "$env:ProgramData\PrintSpoolerAutoStart\SpoolerStart.log" ) $logDir = Split-Path -Parent $LogFile if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null } function Write-Log { param([string]$Message) $time = Get-Date -Format "yyyy-MM-dd HH:mm:ss" "$time [$env:COMPUTERNAME] $Message" | Out-File -FilePath $LogFile -Append -Encoding UTF8 } try { $svc = Get-Service -Name $ServiceName -ErrorAction Stop Set-Service -Name $ServiceName -StartupType Automatic -ErrorAction Stop Write-Log "已设置 $ServiceName 启动类型为 Automatic" if ($svc.Status -ne "Running") { Write-Log "服务状态: $($svc.Status),尝试启动..." Start-Service -Name $ServiceName -ErrorAction Stop $deadline = (Get-Date).AddSeconds($TimeoutSeconds) do { Start-Sleep -Seconds 1 $svc.Refresh() } while ($svc.Status -ne "Running" -and (Get-Date) -lt $deadline) if ($svc.Status -eq "Running") { Write-Log "服务启动成功,当前状态: Running" } else { Write-Log "服务启动超时,当前状态: $($svc.Status)" exit 1 } } else { Write-Log "服务已在运行,无需启动" } } catch { Write-Log "异常: $($_.Exception.Message)" exit 2 } exit 0代码里的核心点有三个。第一,Set-Service -StartupType Automatic会在服务是禁用状态时可以正常修改,不需要先手动解禁。第二,Get-Service返回的对象在你调用Start-Service之后不会自动刷新,所以 while 循环里每轮都要执行$svc.Refresh(),否则你可能在一个永远不变的旧状态里死循环。第三,#Requires -RunAsAdministrator放在脚本第一行,如果用户没有用管理员身份运行,PowerShell 会直接拒绝执行,而不是等跑到Set-Service才报错。
4.2 脚本参数怎么调:超时、日志路径和退出码
脚本通过param暴露了三个参数,生产环境里一般不需要改:
| 参数 | 默认值 | 作用 |
|---|---|---|
| ServiceName | Spooler | 要守护的服务名,如果你想把思路复用到别的服务,改成对应服务名即可 |
| TimeoutSeconds | 30 | 等待服务进入 Running 的最大秒数,驱动加载慢的机器建议调到 60 |
| LogFile | C:\ProgramData\PrintSpoolerAutoStart\SpoolerStart.log | 日志输出路径,目录不存在会自动创建 |
退出码设计为:0 表示脚本完成且服务处于 Running;1 表示服务启动超时,需要人工看日志;2 表示脚本执行过程出现异常,比如服务不存在或权限不足。在计划任务里可以把退出码作为判断条件,例如相邻任务看到退出码 1 就发告警。常规的轮询守护任务不需要这么敏感,但如果你把脚本放在开机脚本里,退出码能帮你快速定位“是没执行还是执行了没起来”。
4.3 部署方式:开机脚本、计划任务和登录时运行
脚本写好后,有三种部署方式。第一种是组策略开机脚本:把脚本放到C:\Windows\System32\GroupPolicy\Machine\Scripts\Startup\,然后在gpedit.msc里的“计算机配置 -> Windows 设置 -> 脚本(启动/关机)”中添加。开机脚本在系统启动时执行一次,适合新装机第一次配置,但它没法在服务崩溃后继续守护。
第二种也是我最推荐的方式:计划任务。创建命令和上一章相似,但这一次直接执行脚本文件,不再内联 PowerShell 代码:
schtasks /Create /TN "SpoolerAutoStart" /TR "powershell.exe -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File \"C:\Scripts\SpoolerAutoStart.ps1\"" /SC MINUTE /MO 5 /RU SYSTEM /RL HIGHEST /F为什么用计划任务而不是开机脚本?因为计划任务可以设置“重复周期”,每 5 分钟跑一次,服务崩了会自动拉回来。开机脚本只在开机瞬间执行,如果那个时刻 Spooler 还没准备好或者服务被依赖项卡住,脚本退出后就没有第二次机会。
第三种是登录时运行:把脚本快捷方式放在shell:startup文件夹。这个方式只对当前用户生效,而且普通用户运行会触发#Requires拒绝,所以我不推荐给系统级服务用。如果你管理的环境是多用户共用机器,还是老老实实用计划任务加系统账户。
5. print spooler 自动启动避坑指南:5 个常见现象、原因与修复
脚本跑起来不代表万事大吉。我遇到过好几次“计划任务每 5 分钟跑一次,但服务还是起不来”的情况,查到最后发现不是脚本问题,而是系统层面有更深的原因。这一章把最常翻车的五个现象列出来,每条都按照“现象、原因、解决”的顺序写,方便你遇到问题时直接对照。
5.1 现象:手动能启动,重启后又变成“已禁用”
现象:在服务管理器里,Print Spooler 显示“已禁用”。你手动改成自动并启动后,打印机恢复正常,但重启电脑再打开服务管理器,它又变成“已禁用”。
原因:Windows 优化大师或同类清理工具在后台有实时“服务管理”功能。它每隔一段时间会按自己的白名单把服务重置。另一种常见场景是域策略在每次网卡上线时强制应用服务设置,导致你本机的修改被覆盖。
解决:先用sc config Spooler start= auto改回来,再用reg query HKLM\SYSTEM\CurrentControlSet\Services\Spooler /v Start确认注册表值为 2。如果重启后再次变回 4,执行gpresult /r查看有没有“系统服务”策略。如果确认是优化软件,卸载它或关闭“开机优化”功能,不要只改软件里的开关,那通常没用。
5.2 现象:启动时报错 1058 或 1068,服务起不来
现象:手动启动 Print Spooler 时弹出“错误 1058:无法启动服务,原因可能是已被禁用或没有启用。”或者“错误 1068:无法启动服务,依赖服务或组无法启动。”
原因:1058 基本上可以断定注册表Start=4,服务被禁用;1068 则说明 Spooler 依赖的服务没有在运行。Print Spooler 的依赖项里通常包含 Remote Procedure Call 和 HTTP Service,如果 HTTP Service 被单独禁用,Spooler 就会报 1068。
解决:先看sc qc Spooler的依赖列表,再用sc qc HTTP检查 HTTP Service 的启动类型。反过来,如果 HTTP Service 本身也无法启动,尝试以管理员运行net stop http再net start http,必要时清理C:\Windows\System32\drivers\etc\services这个文件。注意不要轻易动 RPC,很多系统服务都依赖它,RPC 挂了往往不是重启一个服务能解决的。
5.3 现象:设置“自动(延迟启动)”后,打印机驱动托盘在开机后不加载
现象:服务启动类型是“自动(延迟启动)”时,用户已经看到桌面,但打印机图标迟迟不出现,打印作业发出去也是挂起状态。把启动类型改成普通“自动”后,问题立刻消失。
原因:延迟启动会让服务在系统完成启动后再过一段时间才运行。打印驱动和厂商托盘程序通常在登录时就开始加载,它们依赖 Spooler 服务就绪,服务未就绪,驱动组件的加载窗口就错过了。
解决:把启动类型改回普通“自动”,并且关闭注册表里的延迟标记。命令行一条搞定:
sc config Spooler start= auto如果注册表里已经有DelayedAutoStart这个值,把它设为 0:
reg add HKLM\SYSTEM\CurrentControlSet\Services\Spooler /v DelayedAutoStart /t REG_DWORD /d 0 /f不要为了追求“开机更快”把打印服务延迟启动,省出来的零点几秒远不够你后面排查打印机问题的时间。
5.4 现象:服务启动后立刻停止,或者反复重启
现象:Spooler 服务能启动,但几秒后自动停止,事件查看器里出现“服务控制管理器”事件 ID 7031,描述为“Print Spooler 服务意外终止”。服务恢复选项被设置成自动重启时,就会反复进入“启动-崩溃-重启”循环。
原因:最常见的三大根源:打印队列文件损坏、第三方打印驱动冲突、系统补丁与老驱动不兼容。队列文件路径是C:\Windows\System32\spool\PRINTERS,里面残留的.spl/.shd文件可能是上次异常中断时留下的,服务启动时读取这些坏文件直接崩溃。
解决:先把服务停掉,再清空目录里的文件,最后启动服务:
net stop Spooler del /q C:\Windows\System32\spool\PRINTERS\*.* net start Spooler清队列是网上各种 “fix print spooler” 方案里最有效的一招。如果清了还是崩,用pnputil /enum-drivers找到近期安装的打印驱动,禁用掉再试。另外要留意系统补丁与厂商驱动的兼容性,尤其是涉及打印后后台服务安全补丁的更新,建议优先升级厂商驱动而不是回滚系统补丁。
5.5 现象:自动启动脚本没生效,计划任务没有跑
现象:计划任务创建了,服务还是停着。打开任务计划程序,发现任务显示“已禁用”,或者“上次运行结果”不是 0。
原因:通常有三个。第一,计划任务的触发条件设置了“只在用户登录时运行”,但执行账户是 SYSTEM,登录状态对不上。第二,脚本路径或文件名带空格,而操作参数里的引号写错。第三,任务创建后默认没有勾选“使用最高权限运行”,脚本执行到Set-Service时弹出拒绝访问,但计划任务界面看不到这个弹窗。
解决:用命令查询任务状态:
schtasks /Query /TN SpoolerAutoStart /V看“计划任务状态”和“上次运行时间”。如果确认任务没执行,用任务计划程序 GUI 打开任务,在“常规”选项卡勾选“不管用户是否登录都要运行”,并勾选“使用最高权限运行”。如果“上次结果”是 2,说明脚本抛了异常,手动以管理员身份执行一次脚本看具体报错。最后检查命令里的File参数,路径有空格时务必写成\"C:\Scripts\SpoolerAutoStart.ps1\",这个转义我至少写错过三次。
6. 进阶:让自动启动程序带上“事件触发”模式,服务一停就拉起来
前面用的是轮询,每 5 分钟检查一次。如果打印服务被频繁或突然停止,5 分钟的空窗期还是有点长。Windows 系统实际上把服务启停都记录在事件日志里,Print Spooler 状态变化时会生成“服务控制管理器”事件,事件 ID 是 7036。利用这个事件触发计划任务,可以让自动启动程序几乎实时地拉起 Spooler。
基于事件触发的方式是创建计划任务,触发器选“发生事件”而不是“按计划”。事件日志选择“系统”,来源选择“Service Control Manager”,事件 ID 填 7036。如果你用命令行创建,需要写一段 XPath 过滤器,比较复杂,我建议在任务计划程序图形界面里操作:
右键 -> 创建任务 -> 触发器 -> 新建 -> 开始任务选“发生事件”。在“日志”下拉选“系统”,来源选“Service Control Manager”,事件 ID 填 7036。然后切到“操作”,启动程序填powershell.exe,参数填-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "C:\Scripts\SpoolerAutoStart.ps1"。这样每次 Spooler 服务状态变化,包括进入运行、停止、暂停,任务都会触发一次脚本,脚本会判断当前状态,如果没在运行就拉起来。
不过 7036 事件不只代表服务停止,它还包含服务“正在运行”和“已经停止”两种切换。所以任务会被多触发几次,但脚本内部有状态判断,服务在运行时会直接写日志退出,不会有副作用。如果你对触发条件很敏感,可以在触发器里用“自定义事件”加 XML 过滤,只匹配文本包含“停止”的事件。我记得有一次我在客户机配事件触发,XPath 写错导致任务根本不触发,后来老老实实退回图形界面选条件,反而更稳。
现在的做法是:开机脚本加轮询计划任务保底,事件触发任务提升响应速度。打印服务这个领域没有太多玄学,核心无非是把服务状态看得死死的,日志写清楚。我自己的习惯是就算脚本跑通了,也会保留日志文件,等出问题时先看最后几条记录——是“服务已在运行”还是“启动超时”,一眼就能判断是脚本问题还是系统问题。希望这些踩坑经验能帮到你。
本文还有配套的精品资源,点击获取