一、引子
每天下班前,我都有一个“强迫症”习惯:把电脑上所有打开的程序都关掉,再执行关机。
这不仅是为了让第二天开机时系统清爽、启动迅速,更是为了避免:
- 浏览器恢复几十个标签页,拖慢系统;
- 微信/QQ 留在后台偷偷上传日志或接收消息;
- 某些编辑器(如 Typora、Notion)因未保存而丢失草稿;
- 文件资源管理器窗口残留,占用内存;
- 最讨厌的是——有些软件关闭时还会弹出“是否保存?”“是否退出后台?”的二次确认对话框……
手动一个个点?效率太低,还容易遗漏托盘里的程序。
直接强制关机?又总觉得“不干净”,心理上过不去。
于是,我开始思考:有没有一种方法,能一键、安全、彻底地关闭当前用户启动的所有非系统应用程序?
答案是肯定的。
二、核心需求与设计目标
在动手写代码前,必须明确我们到底要什么:
| 需求 | 说明 |
|---|---|
| ✅ 关闭所有用户启动的应用 | 包括前台窗口、后台运行、最小化到托盘的程序 |
| ✅ 安全关闭文件资源管理器窗口 | 不能杀explorer.exe,否则桌面消失 |
| ✅ 不影响系统关键进程 | 如dwm.exe、sihost.exe、任务栏、开始菜单等 |
| ✅ 提供图形化确认 | 防止误操作导致数据丢失 |
| ✅ 脚本自身不被关闭 | 避免“自杀式”执行 |
| ✅ 兼容中文路径与无窗口程序 | 确保在各种环境下稳定运行 |
| ✅ 操作完成后有反馈 | 告知用户关闭了多少程序 |
三、技术方案
3.1 为什么传统方法行不通?
很多网上教程推荐用:
Get-Process|Where MainWindowTitle|Stop-Process但这种方法存在致命缺陷:
- 托盘程序无窗口→
MainWindowTitle为空 → 被跳过; - 资源管理器窗口无法关闭→ 因为
explorer.exe是外壳进程,通常被排除; - 无法区分“你的程序”和“系统程序”→ 可能误杀。
因此,我们必须放弃“窗口依赖”,转向更底层的进程归属判断。
3.2 关键技术点
(1)通过 SID 识别用户进程
每个 Windows 进程都有一个所有者(Owner),其唯一标识是安全标识符(SID)。
我们可以:
- 获取当前登录用户的 SID;
- 遍历所有进程,筛选出属于该 SID 的进程。
$currentUserSid=([System.Security.Principal.WindowsIdentity]::GetCurrent()).User.Value$ownerSid=$proc.GetOwnerSid().Sidif($ownerSid-eq$currentUserSid){/*是用户程序*/}(2)安全关闭资源管理器窗口
使用Shell.ApplicationCOM 对象,仅关闭窗口而不终止进程:
$shell=New-Object-ComObject Shell.Applicationforeach($windowin$shell.Windows()){if($window.FullName-like"*explorer.exe"){$window.Quit()}}(3)图形化确认对话框
调用 .NET 的PresentationFramework,弹出标准 Windows 消息框:
Add-Type-AssemblyName PresentationFramework[System.Windows.MessageBox]::Show("确认关闭?","警告",'YesNo','Warning')四、完整脚本:CloseAllUserApps.ps1
✅ 支持中文系统
✅ 兼容 PowerShell 5.1 及 PowerShell 7+
✅ 无需管理员权限
✅ 自动排除脚本自身
# ==============================================================================# CloseAllUserApps.ps1# 功能:一键关闭当前用户启动的所有非系统应用程序(含托盘程序)# 特性:# - 弹出标准 Windows 图形确认对话框# - 安全关闭所有文件资源管理器窗口(不终止 explorer.exe)# - 基于 SID 精准识别用户进程# - 多重防护:排除系统关键进程 + 系统目录程序 + 脚本自身# - 执行后弹出结果提示## 作者:xiaoli# 日期:2025-12-20# 许可:MIT(可自由使用、修改、分发,保留作者信息即可)# ==============================================================================# 加载 WPF 组件以支持图形消息框Add-Type-AssemblyName PresentationFramework# -----------------------------# 第一步:图形化确认# -----------------------------$caption="确认关闭所有应用程序?"$message= @" ⚠️ 此操作将强制关闭您当前登录用户启动的所有应用程序, 包括最小化到系统托盘的程序(如微信、QQ、网易云音乐、Steam 等), 并关闭所有文件资源管理器窗口。 ❗ 未保存的工作(文档、聊天记录、草稿等)将会永久丢失! 是否继续? "@$result=[System.Windows.MessageBox]::Show($message,$caption,'YesNo','Warning')if($result-ne'Yes'){[System.Windows.MessageBox]::Show('操作已取消。','已取消','OK','Information')exit}Write-Host"`n✅ 用户确认执行,开始清理..."-ForegroundColor Green# -----------------------------# 第二步:安全关闭资源管理器窗口# -----------------------------try{$shell=New-Object-ComObject Shell.Application$windows=$shell.Windows()if($windows-and$windows.Count-gt0){Write-Host"正在关闭$($windows.Count)个文件资源管理器窗口..."-ForegroundColor Cyan# 从后往前遍历,避免索引变化问题for($i=$windows.Count-1;$i-ge0;$i--){$window=$windows.Item($i)if($window.FullName-like"*explorer.exe"){try{$window.Quit()}catch{}}}}}catch{Write-Host"⚠️ 跳过资源管理器窗口关闭(COM 对象不可用)"-ForegroundColor Yellow}# -----------------------------# 第三步:获取当前用户 SID# -----------------------------try{$currentUserSid=([System.Security.Principal.WindowsIdentity]::GetCurrent()).User.Value}catch{[System.Windows.MessageBox]::Show("无法获取当前用户身份,请重试。","错误","OK","Error")exit}# -----------------------------# 第四步:定义排除列表(关键系统进程)# -----------------------------$excludedNames= @('explorer.exe',# 桌面外壳(窗口已单独处理)'dwm.exe',# 桌面窗口管理器(关了会黑屏)'sihost.exe',# Shell 基础服务'taskhostw.exe','RuntimeBroker.exe','ShellExperienceHost.exe','StartMenuExperienceHost.exe','SearchApp.exe','TextInputHost.exe','SecurityHealthSystray.exe','conhost.exe',# 控制台宿主'powershell.exe',# 当前脚本进程(防止自杀)'pwsh.exe','WindowsTerminal.exe','ApplicationFrameHost.exe','dllhost.exe','fontdrvhost.exe','WUDFHost.exe')# -----------------------------# 第五步:筛选并终止用户应用程序# -----------------------------try{$allProcesses=Get-WmiObject-ClassWin32_Process-ErrorAction Stop}catch{[System.Windows.MessageBox]::Show("无法访问进程列表,请以普通用户身份运行此脚本。","权限错误","OK","Error")exit}$userAppProcesses=foreach($procin$allProcesses){# 跳过无效或系统保留 PIDif(-not$proc.ProcessId-or$proc.ProcessId-lt4){continue}# 获取进程所有者 SIDtry{$ownerSid=$proc.GetOwnerSid().Sid}catch{continue# 无权限或内核进程}# 仅处理当前用户的进程if($ownerSid-ne$currentUserSid){continue}# 排除关键进程名if($proc.Name-in$excludedNames){continue}# 排除位于系统目录(%windir%)下的程序(增强安全性)if($proc.ExecutablePath-and$proc.ExecutablePath.StartsWith("$env:windir\")){continue}# 输出符合条件的进程$proc}# -----------------------------# 第六步:执行终止并反馈结果# -----------------------------if($userAppProcesses){$count=($userAppProcesses|Measure-Object).CountWrite-Host"正在终止$count个用户应用程序..."-ForegroundColor Yellowforeach($procin$userAppProcesses){try{Stop-Process-Id$proc.ProcessId-Force-ErrorAction SilentlyContinue}catch{# 忽略已退出或受保护的进程}}[System.Windows.MessageBox]::Show("✅ 成功关闭$count个应用程序。","完成","OK","Information")}else{[System.Windows.MessageBox]::Show("未找到可关闭的用户应用程序。","提示","OK","Information")}五、使用指南
步骤 1:保存脚本文件
- 复制上方完整脚本;
- 打开记事本(Notepad);
- 粘贴内容;
- 点击文件 → 另存为;
- 文件名输入:
CloseAllUserApps.ps1
注意:务必选择“所有文件”类型,编码建议选UTF-8; - 保存到例如:
C:\Scripts\或桌面。
步骤 2:设置 PowerShell 执行策略(首次使用)
Windows 默认禁止运行.ps1脚本。需临时允许本地脚本:
- 按
Win + R,输入powershell,回车(不要用“以管理员身份运行”); - 执行命令:
Set-ExecutionPolicy-ExecutionPolicy RemoteSigned-Scope CurrentUser - 输入
Y并回车。
🔒 说明:
RemoteSigned策略允许本地脚本运行,远程脚本需数字签名,兼顾安全与便利。
步骤 3:运行脚本
- 推荐方式:右键
CloseAllUserApps.ps1→“使用 PowerShell 运行”; - 或在 PowerShell 中执行:
.\CloseAllUserApps.ps1
步骤 4:创建桌面快捷方式(可选但推荐)
- 右键桌面 → 新建 → 快捷方式;
- 在“位置”栏输入:
powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -File "C:\Scripts\CloseAllUserApps.ps1"-WindowStyle Hidden可隐藏控制台窗口,仅显示图形对话框。 - 点击“下一步”,命名为 “一键清理应用”;
- 完成后,可右键快捷方式 → 属性 → 更换图标(建议使用红色 × 或垃圾桶图标)。
现在,双击该快捷方式即可一键清理!
六、注意事项
⚠️ 重要警告
- 所有未保存的数据将永久丢失!请确保已保存工作。
- 某些程序(如 OneDrive、Teams、钉钉)设计为“常驻后台”,关闭后可能自动重启,属正常行为。
- 切勿以管理员身份运行此脚本,以免误杀系统服务。
- 脚本不会关闭
explorer.exe进程,因此桌面、任务栏、开始菜单始终可用。
七、常见问题解答(FAQ)
Q1:为什么资源管理器窗口关了,但桌面还在?
A:因为我们只调用了window.Quit()关闭窗口,没有终止explorer.exe进程。桌面由同一进程托管,不受影响。
Q2:脚本会关闭浏览器吗?
A:会。Chrome、Edge、Firefox 等均会被关闭。下次启动时可通过“恢复上次会话”找回标签页(需浏览器开启此功能)。
Q3:能否保留某个程序(如网易云音乐)?
A:可以!在脚本的$excludedNames数组中添加进程名,例如'cloudmusic.exe'。
Q4:脚本在 PowerShell 7 中能用吗?
A:可以。已兼容 PowerShell 5.1(Windows 自带)和 PowerShell 7+。
Q5:能否做成计划任务自动运行?
A:可以,但强烈不建议自动执行(因无用户确认)。仅建议手动触发。
附:脚本维护建议
- 定期检查
$excludedNames列表,根据新安装的软件调整; - 如遇异常,可临时移除
-WindowStyle Hidden查看控制台输出;