读书笔记 · 约 15,257 字 · 预计推送 2 部分

Windows 个人服务运维:服务管理器、计划任务、自动恢复、日志轮转与更新 —— 主题精读 未开始

目录

题记与说明


一、来源清单(7 个,全部精读)

#来源类型链接读到的核心内容
S1ServerFault: How can I automatically restart a Windows service if it crashes? (2009, 248k views)社区问答https://serverfault.com/questions/48600/how-can-i-automatically-restart-a-windows-service-if-it-crashesSCM Recovery 标签页 + sc failure 命令行 + 兜底 watchdog + PowerShell 恢复脚本
S2Microsoft Learn(存档): Sc failure 命令参考官方文档https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/cc742019(v=ws.11)sc failure 完整语法、参数语义、三级动作上限
S3NSSM 官方 usage 文档工具文档https://nssm.cc/usage把任意程序包成服务;内置日志轮转 AppRotate*;指数退避重启
S4ServerFault: Windows Service vs. Task Scheduler with startup trigger (2018)社区问答https://serverfault.com/questions/901388/windows-service-vs-task-scheduler-with-startup-trigger服务 vs 计划任务作常驻进程的真实取舍
S5CloudBees KB: Log file rotation on Windows厂商知识库https://docs.cloudbees.com/docs/cloudbees-ci-kb/latest/client-and-managed-controllers/log-file-rotation"Windows 无原生日志轮转"及两条出路
S6Microsoft Learn: winget upgrade 命令(2026-07 更新)官方文档https://learn.microsoft.com/en-us/windows/package-manager/winget/upgradewinget upgrade --all 全量选项与坑
S7Meziantou: Keeping your software up to date using winget and PowerShell (2023)技术博客https://www.meziantou.net/keeping-your-software-up-to-date-using-winget-and-powershell.htm每天 04:00 的 winget 更新计划任务完整参数
说明:StackOverflow 原站(S-O 390307)被反爬拦截(WebFetch 三次 403、webReader 两次只返回元数据),其结论由 S4(ServerFault 同主题问答)替代覆盖;archived 版 sc failure 文档(S2)因现行版 URL 404 而改用官方存档版。

二、七维提取

1. 核心问题

个人在 Windows 上把若干程序变成"常年自愈、无人值守的后台服务",要同时回答四个子问题:

2. 主要主张

  1. 载体二分原则:24/7 常驻、需要内存态/事件监听的进程用 Windows 服务(SCM 提供 Recovery + 依赖管理 + 优雅停止);周期性作业用计划任务(更简单,自带"错过后补跑"等设置)。计划任务加 startup 触发器可以当常驻用(S4 结论:"Yes, in your use case it is"),但要接受三个限制:默认强制结束选项、无任务间依赖、结束=杀进程。
  2. 自动恢复要三层兜底:
    • 第一层:SCM Recovery(services.msc → Recovery 标签 / sc failure),三级动作 restart→restart→run(脚本/邮件),配 reset= 让失败计数定期归零;
    • 第二层:计划任务自己的 Restart / StartWhenAvailable 设置;
    • 第三层:watchdog——每 5 分钟跑一次 net start MyServiceName,"started 就无副作用"。
    • 已知坑:服务优雅退出(exit code 0)不触发 SCM 恢复(S1 答 MSS)。
  3. 日志轮转 Windows 无原生方案(S5 原话:"Windows does not offer a native solution for log rotation"),四条路径按集成度排序:服务包装器自带(NSSM AppRotate*)→ logrotate 移植(Log-Rotate PS 模块 / LogRotateWin)→ DIY PowerShell 脚本 + 计划任务 → 应用内 rolling logger(NLog/Serilog 等,最可靠,因为由写日志的进程自己切文件)。
  4. 更新策略:winget upgrade --all --silent --accept-package-agreements --accept-source-agreements 挂每日计划任务(凌晨 4 点)是个人可用的最低成本方案,但必须配:排除清单(例如 $_.Id -notlike "TechSmith.*")、预览习惯(先裸跑 winget upgrade 看清单)、以及对"无版本号应用"与"pinned 应用"的显式开关(--include-unknown / --include-pinned)。服务类软件升级要走 stop → 换二进制 → start,winget 升级会覆盖安装,装完要用第一层 Recovery 把服务拉起来。

3. 方法

4. 数据与证据

5. 结论

个人 Windows 服务运维的最小可行栈(按成本从低到高):

  1. 能是计划任务的就用计划任务:周期作业 + Restart 设置 + StartWhenAvailable(错过后补跑)+ -MultipleInstances IgnoreNew(防重叠)。
  2. 必须常驻的用"NSSM 包服务 + SCM Recovery":
   nssm install <name> <exe路径>          # nssm.exe 本体安装后不可移动/删除
   nssm set <name> AppStdout D:\logs\app.log
   nssm set <name> AppRotateFiles 1
   nssm set <name> AppRotateOnline 1
   nssm set <name> AppRotateBytes 10485760   # 10MB 轮转
   sc failure <name> reset= 86400 actions= restart/60000/restart/60000/run/60000
  1. watchdog 兜底:计划任务每 5 分钟 net start <name>(对运行中服务无副作用),覆盖"优雅退出 0 不触发恢复"的盲区。
  2. 日志轮转二选一:优先应用内 rolling logger;无此能力时用 PowerShell 脚本(压缩 N 天前日志、删除超期文件)挂每日计划任务,或直接用 NSSM 的 AppRotate*。
  3. 更新走 winget 每日任务:04:00、--silent、两个 --accept-*-agreements、显式排除清单;先用裸 winget upgrade 预览,服务程序升级后确认 Recovery 已把它拉起。

6. 局限

7. 对我的启发


三、四条子问题的机制细读

3.1 服务管理器与 sc.exe

sc failure 官方语法(S2 存档版全文):

sc [<ServerName>] failure [<ServiceName>] [reset= <ErrorFreePeriod>] [reboot= <BroadcastMessage>]
    [command= <CommandLine>] [actions= {"" | {[run/<MS>] | [restart/<MS>] | [reboot/<MS>]}[/...]]

四条官方 Remarks(原文见第四节):

  1. 不是所有服务都允许改失败选项(服务集成员除外);
  2. command= 必须用全限定路径(cmd.exe /c D:\xxx.bat 或 cscript D:\xxx.vbs);
  3. actions= 最多三个动作,对应第 1、2、3 次失败;
  4. = 是选项名的一部分,选项与值之间必须有一个空格(actions= restart,漏空格直接失败)。

本机 sc qfailure Spooler 实测显示系统服务出厂即有:1 小时无错误重置计数 + 前两次失败各延迟 5 秒重启。

3.2 计划任务(Task Scheduler / schtasks)

3.3 自动恢复的完整决策树

进程死了怎么被拉起?
├─ 是 Windows 服务?
│   ├─ 崩溃退出(非0)→ SCM Recovery: sc failure 三级动作 + reset= 计数重置
│   │                     第3级挂脚本/邮件(command=,需全路径)
│   └─ 优雅退出(0)  → SCM 不管 → watchdog: 计划任务每5分钟 net start <name>
│                        (对运行中服务是 no-op,见 S1 答 Anderson)
├─ 是 NSSM 包装的服务?
│   └─ NSSM 自己监控子进程并重启(AppExit=Restart 默认);
│      AppThrottle 1500ms 起指数退避至 ~256s,防 crash-loop;
│      SCM Recovery 仍然可用(nssm.exe 本身就是服务程序)
└─ 是计划任务?
    └─ 任务设置: Restart on failure + StartWhenAvailable + IgnoreNew
       (S4: "Both have options for recovery/restart after failure")

3.4 日志轮转四方案对比

方案原理优点缺点适用
应用内 rolling logger进程自己按大小/日期切文件零竞态、最可靠要求程序支持自写服务首选
NSSM AppRotate*服务重启时轮转(AppRotateFiles=1);在线轮转靠管道拦截输出(AppRotateOnline=1)零脚本,随服务走在线轮转官方自标 "Danger, moving parts!" 可能丢输出;按字节不按天跑不动的第三方程序
logrotate 移植Log-Rotate (PowerShell Gallery) / LogRotateWin,兼容 logrotate.conf 语法配置熟悉、功能全多装一个依赖已熟悉 logrotate 的用户
DIY PowerShell + 计划任务脚本压缩/删除 N 天前日志,每日跑完全可控、无依赖自己处理竞态与保留策略任何场景的兜底

S5(CloudBees)的判断是后两者的组合:PowerShell 脚本挂计划任务,或 LogRotateWin("a Windows port of the logrotate utility available for Linux"),并强调这些"not officially supported"。

3.5 更新管线


四、重要原文引述(含中文译)

S1 — Christopher_G_Lewis(98 票,最佳答案):

"View the recovery tab - there are all sorts of options - I'd set First & Second Failure to Restart the Service, Third to run a batch program that BLAT's out an email with the third failure notification. You should also set the Reset Fail Count to 1 to reset the fail count daily."

(看 Recovery 标签页,选项很多——我会把第一、二次失败设为重启服务,第三次设为运行批处理发邮件告警。同时把失败计数重置设为 1 天。)

配命令:

SC failure w3svc reset= 432000  actions= restart/30000/restart/60000/run/60000
SC failure w3svc command= "MyBatchFile.cmd"

S1 — MSS(重要坑):

"It seems when service exit gracefully with exit code of 0 windows don't try to recover it."

(服务以退出码 0 优雅退出时,Windows 似乎不会尝试恢复它。)

S1 — Anderson(watchdog 模式):

"execute the below command in windows task scheduler every 5 minutes: net start MyServiceName. This command will basically start the service (if stopped) and has no effect if the service is already running."

(每 5 分钟在计划任务里跑 net start:停了就启动,在跑就无副作用。)

S1 — Nick(Recovery 标签跑 PowerShell 的坑):

"Program: Powershell.exe Not C:\Windows\System32\WindowsPowerShell\v1.0\Powershell.exe"

(Program 字段只填 Powershell.exe,完整路径会导致参数拆分错位。)

S2 — Microsoft Learn 存档(语法与限制):

"You can specify up to three separate actions with the actions= parameter, to be used the first, second, and third times that a service fails."

"For each command-line option (parameter), the equal sign is part of the option name. A space is required between an option and its value (for example, actions= restart). If the space is omitted, the operation will fail."

"Not all services allow changes to their failure options. Some run as part of a service set."

(动作最多三个,对应第 1/2/3 次失败;等号属于选项名,选项与值之间必须有空格,漏了就失败;并非所有服务允许改失败选项。)

S3 — NSSM usage:

"you must not move or delete nssm.exe after installing a service."

(安装服务后不得移动或删除 nssm.exe——nssm 本体被注册为服务程序。)
"AppRotateOnline 1 — rotate files that exceed the size limit while the service runs (nssm intercepts output via a pipe; the docs warn of 'Danger, moving parts!' and possible output loss on failure)"
"AppThrottle (default 1500 ms) — if the app exits sooner than this threshold, nssm pauses before restarting, 'doubling the pause time for each subsequent failure' up to roughly four minutes (256000 ms)"

S4 — apocalysque(受赏 +50 票答案):

"Yes, in your use case it is, however my understanding is that generally the task scheduler expects the task to end at some point (and in fact has a default option to force the task to end if it doesn't end by itself)"

"One area where it's not equivalent is service dependencies. There's no built-in way to make a scheduled task depend on another to run, whereas you can with services."

"Both have options for recovery/restart after failure."

(你的场景可行;但任务调度器预期任务终会结束,且有默认强制结束选项;任务没有服务那种依赖机制;两者其实都有失败恢复选项。)

S4 — Nacht(评论区):

"ending the task in Task Scheduler simply kills the process. If you want built-in stopping functionality, services seem to win here."

(结束计划任务就是直接杀进程;要内置的优雅停止,服务胜出。)

S5 — CloudBees KB:

"Windows does not offer a native solution for log rotation."

"you can use PowerShell to create a logger and run this as a scheduled task within Windows." / "LogRotateWin … a Windows port of the logrotate utility available for Linux."

"The solutions or workarounds described here are not officially supported by CloudBees."

S6 — Microsoft Learn winget upgrade(语义坑):

"Some applications do not provide a version. They are always latest. Because the Windows Package Manager cannot identify if there is a newer version of the app, an upgrade will not be possible unless the -u, --unknown, --include-unknown option is specified."

(无版本号应用在 --all 下默认不升,需要显式 --include-unknown。)

S7 — Meziantou(排除清单与任务参数):

"Where-Object { $_.Id -notlike "TechSmith.*" }"(按包 ID 排除不想自动更新的软件)

任务设置:04:00 每日、-RunLevel Highest、-MultipleInstances IgnoreNew、-RunOnlyIfNetworkAvailable:$true、-StartWhenAvailable:$true、-WakeToRun:$false。

五、本机实测记录(2026-11-04,主机 MAGE,Windows 11 build 26200)

$ sc qfailure Spooler
[SC] QueryServiceConfig2 成功
SERVICE_NAME: Spooler
        RESET_PERIOD (以秒计)        : 3600
        FAILURE_ACTIONS              : 重启动 -- 延迟 = 5000 微秒。
                                       重启动 -- 延迟 = 5000 微秒。

(真实系统服务出厂即配好 1 小时计数重置 + 两次重启动作;"微秒"为本地化错误,官方文档为毫秒。)

$ sc qc Spooler
        TYPE               : 110  WIN32_OWN_PROCESS (interactive)
        START_TYPE         : 2   AUTO_START
        BINARY_PATH_NAME   : C:\WINDOWS\System32\spoolsv.exe
        DEPENDENCIES       : RPCSS / http
        SERVICE_START_NAME : LocalSystem
$ sc failure
选项:
        reset=   <重置失败计数为 0 ... 之前无错的时间长度(以秒计)> (必须与 actions= 一起使用)
        reboot=  <失败时重新启动之前的消息广播>
        command= <失败时运行的命令行>
        actions= <失败操作和其延迟时间(以微秒计),以 / (斜杠) 分隔 -- 如 run/5000/reboot/800
                  有效的操作是 <run|restart|reboot> > (必须与 reset= option 一起使用)
$ schtasks /query            # Git Bash 下报错
错误: 无效参数/选项 - 'C:/Program Files/Git/query'。   ← MSYS 路径转换吃掉了 /query
$ schtasks //query //fo CSV | wc -l → 430 个任务(需用 // 转义)

六、综合速查(个人服务运维手册)

新服务上线 checklist:

  1. 常驻?→ nssm install <name> <exe>;周期作业?→ Register-ScheduledTask。
  2. 日志:应用支持 rolling 就在应用内配;否则 nssm set <name> AppStdout AppRotateFiles 1 AppRotateOnline 1 AppRotateBytes 10485760。
  3. 恢复:sc failure <name> reset= 86400 actions= restart/60000/restart/60000/run/60000;自写服务保证崩溃用非零退出码。
  4. 兜底:计划任务每 5 分钟 net start <name>。
  5. 计划任务侧三开关:StartWhenAvailable、-MultipleInstances IgnoreNew、必要的 -RunLevel Highest。
  6. 更新:每日 04:00 winget upgrade --silent --accept-package-agreements --accept-source-agreements + 排除清单;升级前裸跑 winget upgrade 预览。
  7. 自检命令:sc qfailure <name>、sc qc <name>、schtasks //query //fo LIST //v。

*笔记生成:2026-11-04,精读员·#3。来源均于当日在线精读;本机实测在 Windows 11 26200 上完成。*

← 资料库今日播报 →