Windows 开机自启的六种方式:从启动文件夹到服务,以及怎么把它们一次看全
启动文件夹、注册表 Run 键、任务计划程序、Windows 服务、设置里的「启动应用」、UWP 的 StartupTask——六层机制各有各的时机和权限。附上工作目录、UAC、AC 电源这几个最容易踩的坑,以及用 Autoruns 一次性排查全部持久化位置的方法。
「怎么让程序开机自启」这个问题,答案不是一个,是六个。它们的区别不在于「哪个更正确」,而在于启动时机、运行权限、能不能带界面这三件事——选错了的典型症状是:程序确实自启了,但要么弹 UAC 弹到烦,要么开机后卡三十秒,要么根本读不到自己的配置文件。
先上总览,后面逐层拆。
| 机制 | 启动时机 | 权限 | 能有界面 | 适合谁 |
|---|---|---|---|---|
| 启动文件夹 | 登录后、桌面加载完 | 当前用户 | 能 | 普通桌面程序,图省事 |
| 注册表 Run 键 | 登录后、比启动文件夹稍早 | 当前用户 / 各用户 | 能 | 绝大多数软件的「勾选自启」 |
| 任务计划程序 | 可自定义(登录时、开机时、延迟…) | 可提升到最高,且不弹 UAC | 能 | 要管理员权限或要延迟的 |
| Windows 服务 | 开机即启,不用等登录 | SYSTEM 等服务账户 | 不能 | 无界面后台程序 |
| 设置 →「启动应用」 | —— | —— | —— | 不是机制,是上面几种的管理界面 |
| UWP StartupTask | 登录后 | 应用沙箱内 | 能 | 商店应用,开发者才管得着 |
一、启动文件夹——最直观的那个
两个位置,Win + R 输入这两个 shell 名就能直达:
| 作用范围 | shell 命令 | 实际路径 |
|---|---|---|
| 仅当前用户 | shell:startup | C:\Users\<用户名>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup(即 %AppData%\Microsoft\Windows\Start Menu\Programs\Startup) |
| 所有用户 | shell:common startup | C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup |
原理很朴素:登录后 Explorer 遍历这两个文件夹,把里面的东西挨个跑一遍。放快捷方式、.bat、.vbs 都行,不一定非得是 .lnk。
优点是可见——任何人打开文件夹就知道有什么,删一个文件就取消了,不需要碰注册表。缺点有两条:启动时机晚(要等桌面加载完),以及没法带管理员权限静默运行,需要提权的程序在这里要么弹 UAC 要么直接失败。
[ 顺带一提:往「所有用户」那个文件夹里丢东西需要管理员权限,但丢进去之后,它是以每个登录用户各自的权限运行的,不是以管理员运行。这两件事经常被搞混。 ]
二、注册表 Run 键——软件们真正在用的那个
| 键的完整路径 | 作用范围 / 语义 |
|---|---|
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run | 当前用户,每次登录都跑 |
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run | 所有用户,每个人登录时各跑一次 |
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce | 当前用户,跑一次后系统自动删掉这个值 |
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce | 所有用户,同上,跑完即删 |
HKEY_LOCAL_MACHINE\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Run | 64 位系统上的 32 位程序(RunOnce 同样有 WOW6432Node 版本) |
RunOnce 就是「跑一次就把自己删了」的 Run,键名和 Run 平级、只差最后一个词,常用于安装程序重启后的收尾动作(复制文件、删临时目录、注册组件)。
你在软件设置里勾的那个「开机时启动」,背后九成写的就是 HKCU 那条。值的类型是 REG_SZ(少数用 REG_EXPAND_SZ,为了能写 %windir% 这类环境变量),值的名字随便取——它只是软件用来找到自己那条记录的标识,系统不解析;值的数据才是真正要执行的命令行。

上图是向日葵远程控制写的那条:值名 SunloginClient,值数据 "E:\Tools\向日葵远程\SunloginClient\SunloginClient.exe" --cmd=autorun。注意后面那个参数——很多软件靠它区分「开机自启拉起来的」和「用户双击打开的」,前者往往直接缩到托盘、不弹主窗口。你自己写自启功能时也该学这一手。
WOW6432Node 那条容易漏:64 位系统上,32 位程序写 HKLM\Software 会被注册表重定向到 WOW6432Node 下,只看主键会漏掉一批。HKCU 没有这个问题——重定向只作用于 HKLM\Software 和 HKEY_CLASSES_ROOT。

我自己机器上这个键里躺着四条:一个游戏启动器、两条 Teams 的卸载残留、VMware 的托盘程序——全是 32 位程序,在主键里一条都看不到。
RunOnce 有两个前缀约定,装机脚本会用到——前缀加在值名上,不是加在命令上:
1、值名以 ! 开头(如 !MyCleanup)—— 命令执行成功之前不删除这个值,也就是失败了下次开机还会再试。
2、值名以 * 开头(如 *MyCleanup)—— 安全模式下也运行(正常情况下 RunOnce 在安全模式是不跑的)。
命令行加一条的写法:
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v MyApp /t REG_SZ /d "\"D:\Tools\myapp.exe\" --silent" /f注意那圈转义引号:路径带空格时,外面这层引号该加。
不加会怎样?回头看上面那张 WOW6432Node 的图——里面 E:\Delta Force\launcher\startup_runner.exe 就是不带引号的,而它照样能自启。原因是 CreateProcess 在没有引号时会从左往右逐段试:先试 E:\Delta.exe,不存在,再试 E:\Delta Force\launcher\startup_runner.exe,命中。
所以真正的问题不是「跑不起来」,而是两件事:
1、命令行还带参数时会歧义——路径和参数的边界靠空格切,猜错了程序就收不到自己要的参数。
2、这是一个提权后门。只要有人能在 E:\ 根目录放一个 Delta.exe,下次开机 Windows 就会先找到它并执行。这就是常说的 unquoted service path 漏洞,Run 键和服务的 binPath 都吃这一套。
写引号的成本是零,别省。

上图是 HKLM\...\Run 下的另一条(火绒安全的托盘进程):路径本身并不含空格,照样整个包了引号——你不知道用户会把软件装到哪个带空格的目录里。同一张列表里 SecurityHealth 那条用的是 REG_EXPAND_SZ、数据写成 %windir%\system32\SecurityHealthSystray.exe,正是前面说的「要用环境变量就换这个类型」。
三、任务计划程序——进阶推荐
Win + R → taskschd.msc,创建任务,触发器选「登录时」。启动文件夹和 Run 键做不到的事,它都能做:
1、延迟启动。触发器里勾「延迟任务时间:30 秒」,避开开机那阵最挤的 IO,桌面能早点能用。
2、以最高权限运行,且不弹 UAC。这是让需要管理员权限的程序自启的标准解法,没有之一——常规选项卡里勾「使用最高权限运行」,UAC 提示就被绕过了。
3、附加条件:仅在接通电源时、仅在网络可用时、空闲时才跑,等等。

上图是一个真实例子:TrafficMonitor(那个显示网速的小工具)在任务计划程序库里建了个自己的文件夹 TrafficMonitor,里面一个名为 Autorun for <用户名> 的任务,触发器写着「登录 <计算机名>\<用户名> 时」,操作选项卡里是「启动程序 → E:\Static\...\TrafficMonitor.exe」。它之所以不用注册表,正是因为要读网卡流量得有管理员权限——走 Run 键就得每次开机弹 UAC,走计划任务勾上「使用最高权限运行」就一声不响。
这也顺带说明了排查时的一个现实:这台机器的注册表 Run 键里根本找不到 TrafficMonitor,只看注册表会以为它没自启。
命令行版本:
schtasks /create /tn "MyApp" /tr "\"D:\Tools\myapp.exe\"" /sc onlogon /rl highest /delay 0000:30这里有两个默认值会咬人:
[ 坑一:条件选项卡里「只有在计算机使用交流电源时才启动此任务」默认是勾上的。笔记本拔了电源,任务就不跑了,而且没有任何提示。 ]
[ 坑二:设置选项卡里「如果任务运行时间超过下列时间,停止任务」默认勾着,值是 3 天。常驻后台的程序会在开机第三天被计划程序悄悄杀掉。 ]
正经软件(某些驱动更新器、云盘客户端)和流氓软件都爱用这里,所以排查自启动时千万别漏了计划任务——它比注册表隐蔽得多,普通人不会想到来这看。
四、Windows 服务——开机就启,不等登录
services.msc 里那一屏。它和上面所有机制的根本区别是:服务在用户登录之前就已经跑起来了。数据库、同步工具、SSH 隧道、反代这类东西,不应该等到有人坐下来登录才启动。
另一个好处是崩溃自动重启:服务属性的「恢复」选项卡里可以配「第一次失败:重新启动服务」,相当于自带一个 supervisor。
普通 exe 不能直接注册成服务——服务要实现 Service Control Manager 的那套控制接口(响应启动/停止/暂停消息),普通程序没有,硬注册进去会在启动时超时报 1053 错误。所以需要包一层:
| 工具 | 从哪来 | 说明 |
|---|---|---|
sc create | 系统自带 | 只适合本来就实现了服务接口的程序 |
| NSSM(Non-Sucking Service Manager) | nssm.cc | 最省事,nssm install MyService 弹图形界面填路径,能管标准输出重定向、崩溃自动重启 |
| WinSW(Windows Service Wrapper) | GitHub winsw/winsw | 单个 exe + 一个同名 XML 配置,适合跟着项目一起版本控制、随代码分发 |
sc create 的经典坑:等号后面必须有一个空格。
sc create MyService binPath= "D:\Tools\svc.exe" start= auto写成 binPath="D:\..."(等号后无空格)会直接失败,这是 sc 那套老掉牙的参数解析留下的。
还有一条硬限制:服务不能显示界面。Vista 之后有 Session 0 隔离,服务跑在 session 0,用户桌面在 session 1+,服务弹出来的窗口你根本看不见,只会表现为「程序卡在那儿不动」。要有托盘图标的程序就别做成服务,或者做成「服务 + 一个用户态的托盘客户端」两件套。
五、设置里的「启动应用」——它不是一种机制
设置 → 应用 → 启动,或者任务管理器的「启动应用」标签页。
这里不是第五种自启动方式,而是前面几种的汇总管理界面。很多人以为它是个独立开关,其实它列出来的每一项,来源都是启动文件夹、注册表 Run 键或者 UWP 的 StartupTask。
值得知道的是「关闭」按钮干了什么:它不会删除原来的注册表值或快捷方式,而是在另一个地方记一笔「这项被禁用了」。完整的三对键(我在自己机器上逐个确认过都存在):
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\StartupFolder
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run32
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\StartupFolder(Run32 对应的就是前面说的 32 位程序那套 WOW6432Node\...\Run。)
里面的值名和 Run 键里的值名一一对应,值是一段 12 字节的 REG_BINARY:首字节 02/06 表示启用,03 表示禁用,后 8 字节是被禁用那一刻的时间戳(FILETIME)。
所以会出现这种情况:注册表 Run 键里明明有值,程序就是不启动——去 StartupApproved 对应的那条看看首字节,多半是被这里关掉了。反过来,你用脚本往 Run 键写了一条,用户在界面上禁用后,你的脚本重写多少次都没用。
那个「启动影响:高/中/低」的评级也来自这套机制,是系统统计的实际耗时,可以当作优化时的参考。
六、UWP / 商店应用的 StartupTask
微软商店装的应用不走注册表,而是在 Package.appxmanifest 里声明一个 StartupTask 扩展(windows.startupTask,指定 TaskId 和 Executable),由系统统一调度。用户侧只能在「设置 → 应用 → 启动」那个界面里开关它,注册表 Run 键和启动文件夹里都看不到。
普通用户基本碰不到,但排查时要知道「有些自启项不在传统位置」这回事。
排查:一个 Autoruns 就够
上面列的还只是常见位置。完整的持久化点位远不止六个:Winlogon 的 Userinit / Shell 值、AppInit_DLLs、映像劫持(IFEO 的 Debugger 项)、Active Setup、组策略的登录脚本、WMI 事件订阅、浏览器扩展、驱动、Codec……手工挨个翻不现实。
微软官方 Sysinternals 的 Autoruns 一个工具全覆盖,它就是干这个的:把所有已知的自启动位置一次列全,按类别分标签页。免费、免安装,解压就能跑(建议右键以管理员身份运行,否则看不全 HKLM 那半边):
https://download.sysinternals.com/files/Autoruns.zip

最后:怎么选
普通桌面程序 → 启动文件夹(可见、好删)
要延迟、要管理员权限、要附加条件 → 任务计划程序
无界面、不该等登录、崩了要自动拉起 → Windows 服务(NSSM / WinSW 包一层)
软件自己要实现「勾选自启」这个功能 → HKCU 的 Run 键(不需要管理员权限就能写)
写代码实现自启功能时特别提醒一句:写 HKCU 而不是 HKLM。前者当前用户就能写,后者需要管理员权限,为了一个自启选项去要提权,是很糟糕的产品决策。
评论
评论加载中……