磁盘瘦身大师
> 管两种盘:系统盘清缓存、数据盘做体检。口径完全不同,先分流再动手。
前置条件
- 操作系统:Windows 10 / 11(只用系统自带的 robocopy、
mklink /J、PowerShell)。 - 运行时:纯 PowerShell,零第三方依赖——不用装 Python、不用装 Node、不联网也能跑。这是本技能区别于同类工具的核心卖点。
- 权限:非管理员即可完成绝大部分工作;建议提权,理由有二——非管理员读不到部分系统缓存(报告里会标 denied),迁移时遇到被占用文件也更容易搬净。没提权不影响其余功能。
- 本包是全功能版:扫描、报告、清理、迁移、月度复查全部包含,无功能阉割、无运行时授权校验,拿到即可完整执行。
何时使用
> 技能被调用即进入第 1 步(扫描是只读的)。用户不管是输入「扫描电脑 / 清理 C 盘 / 释放空间 / 把大目录迁到别的盘」,还是在聊天框里点选本技能,都不要再问一遍"要扫哪个盘"——直接开跑,用户不欠你一个触发词。默认 C 盘(系统盘爆红是绝大多数场景),跑完的 TOP LEVEL 摘要会直接告诉你该不该换个盘。
- 系统盘:用户说"C 盘满了 / 空间不足 / 帮我看看为什么满 / AppData 好大"。
- 数据盘:用户说"D/F/H 盘也快满了 / 这个盘都装了什么 / 帮我清理下这个盘"。
- 第一轮永远只读扫描,不动任何文件。
- 英文场景改用同目录下的
SKILL_en.md(流程一致,脚本与参考表通用);
报告与收尾脚本已内置中/英双语(-Lang auto|zh|en),非中文系统会自动出英文界面。
铁律
- 红区永不进报告、永不进可清理清单:
C:\Windows、Program Files、Program Files (x86)、
已安装应用的本体目录(含正在运行的版本包)一律不列出、不建议清理。
不为"覆盖率"去展示或触碰红区——报告里出现这些路径,用户会误以为删得掉。
系统盘教科书式例外只有两个:C:\Windows\SoftwareDistribution\Download(Win 更新缓存)
和C:\Windows\Temp,且一律建议走「磁盘清理 → 清理系统文件」而非手删。 - 扫描 = 只读。先出报告,再让用户确认,绝不先删。
- 删除前必须列清单 + 说明风险 + 让用户选档位/勾名单(用 AskUserQuestion)。
- 优先回收站(可回收),其次永久删除;永久删除需二次确认。
- 备份/快照类数据优先"搬到别的盘"而不是删——先
Get-PSDrive看哪个盘空间够。 - 删程序包前先确认不是运行版本:
Get-Process -Name 'X*' | Select -Expand Path。 - 不替用户杀进程(怕丢未保存工程);被占用就跳过并写进收尾脚本。
- 绝不
rm -rf/del /S /Q打个人目录;不动 Desktop / Downloads / Documents 内容。 - 数据盘(D/F/H)不做"分档删缓存":那里的文件是用户的资料,只出报告,删除必须用户逐项点名。
- 日志与产物写到用户的工作盘目录(本机为
F:\workbuddy\<会话目录>\),不要往 C 盘写。 - 超大体量(>20 GB)删除不能用回收站——超出配额不会真正释放空间,须提前说明并二次确认。
Step 0 — 环境盘点(必做)
先看各盘剩余空间,决定"该删还是该搬、搬到哪":
Get-PSDrive -PSProvider FileSystem | Where-Object {$_.Free -ne $null} | ForEach-Object {
"$($_.Name): Free $([math]::Round($_.Free/1GB,2)) GB / Total $([math]::Round(($_.Used+$_.Free)/1GB,1)) GB" }
盘位角色与选址原则见 references/other-drives.md。
Step 1 — 只读扫描(默认用一键流水线)
默认入口是一条命令跑完全流程:pipeline.ps1 一次产出「各盘概览 + 顶层占用 + AppData 大头 + HTML 报告 + 下一步建议」,
省掉"先盘点 → 再扫描 → 再定性"的多轮往返(实测 H 盘端到端 11 秒)。
$sb = [scriptblock]::Create([System.IO.File]::ReadAllText("<skill_dir>\scripts\pipeline.ps1"))
& $sb -Drive C -OutDir "<工作目录>" -SkillDir "<skill_dir>\scripts" -TopN 20
⚠️ -SkillDir 必传:scriptblock 加载时 $PSCommandPath 为空,脚本无法自行定位同级目录。
输出里的结构化字段(stdout 不回显时读 $LOG_FILE):
DRIVES(各盘余量)/ TARGET … type=SYSTEM|DATA(自动判盘型)/ TOP LEVEL / APPDATA TOP / REPORT_FILE= / NEXT。
→ 直接拿着这份摘要进 Step 3 分档,不要再扫第二遍;拿到 REPORT_FILE= 立即 present_files 呈现。
扫描慢时告诉用户:只读电表式读取(名称/大小/日期),不改动任何文件;首次文件多需要几分钟。
<details><summary>需要更细控制时用单脚本方式(点开)</summary>
本环境执行策略为 Restricted 且不允许派生 powershell.exe,powershell -File 跑不通。
→ 用内存 script block 加载技能脚本(不受执行策略约束,实测可用):
$sb = [scriptblock]::Create([System.IO.File]::ReadAllText("<skill_dir>\scripts\report_html.ps1"))
& $sb -Drive F -OutFile "<工作目录>\report.html" -TopN 20 -MinMB 300
| 场景 | 用哪个脚本 | 产出 |
|---|---|---|
| 想要可视化交付物(推荐默认) | scripts/report_html.ps1 |
自包含 HTML 报告,无外部依赖、离线可看,中英双语 |
| 系统盘纯文本排查 | scripts/scan_appdata.ps1 |
各盘概览 + AppData TopN 文本(英文标签) |
| 数据盘纯文本体检 | scripts/scan_bigfiles.ps1 |
大文件/重复/老文件清单(英文标签) |
报告加 -Lang en 强制英文、-Lang zh 强制中文,默认 auto(按系统 UI 语言判断)。
要点(必守):
- 必须加 -File(纯目录会让 Measure-Object Length 报错中断)、-Force(否则漏隐藏文件)。
- C:\Windows / Program Files 深递归极易超时,放最后或跳过——用户能清理的几乎都在 AppData。
- 本环境 PowerShell stdout 经常不回显,一律"写文件 → Read",不要指望回显。
- 系统盘加 -IncludeAppData 才能拿到软件缓存热点。
- 生成 HTML 后主动把报告呈现给用户,这是本技能最直观的价值。
</details>
Step 2 — 判性质 + 查占用
- 系统盘:对照
references/app-hotspots.md定性(纯缓存 / 数据备份 / 程序包 / 应用数据 / 个人数据)。 - 数据盘:对照
references/other-drives.md(迁移 / 归档压缩 / 用户点名删除 / 软件内改存储位置)。 - 先查目标软件是否在运行(运行中会大量跳过):
Get-Process -Name '*JianyingPro*','*Lark*','*WeChat*'。 - 剪映用户必看 references 里的改路径残留坑和草稿回收站坑:
应用内"已清空"≠ 磁盘已释放,.recycle_bin可能还压着几十 GB。
Step 3 — 分档/名单让用户选
系统盘用 AskUserQuestion,四档(实测这套话术决策最快):
1. 清纯缓存档(推荐) — 只删可自动重建的缓存/日志/下载残留/旧版本包
2. 彻底档 — 再加字体包、AI 模型等"删了要重下"的项
3. 只清最大一项 — 最保守
4. 别删,只给清单 — 用户自己处理
数据盘不设档位,改为逐项名单式确认:出报告 → 用户勾选要归档/迁移/删除的项。
备份/快照类数据单独问一次"搬走 vs 删除",并列出各盘剩余空间供选择。
Step 4 — 执行
系统盘清缓存(script block 方式加载 scripts/clean_dotnet.ps1):
- 整体删除:[System.IO.Directory]::Delete($t,$true)(首选,最快)
- 清空内容:[System.IO.File]::Delete() 逐文件 + 目录从深到删 → 5 万文件约 25 秒
- 可先加 -WhatIf 预演,只报体积不删除
搬移 A — 目录联接迁移(软件在用的目录一律走这条)
scripts/migrate_junction.ps1:把目录搬到别的盘,再在原位建 junction 联接。
软件照常读写、用户无感,以后新文件也落新盘——这是本技能的高价值能力。
多数清理工具只会"搬走",搬完软件因找不到原路径而失效,联接方案正是补上这一环。
$sb = [scriptblock]::Create([System.IO.File]::ReadAllText("<skill_dir>\scripts\migrate_junction.ps1"))
& $sb -Src "$env:USERPROFILE\Documents\WeChat Files" -Dst "H:\Moved\WeChat Files" -WhatIf # 先预演
& $sb -Src "$env:USERPROFILE\Documents\WeChat Files" -Dst "H:\Moved\WeChat Files" # 再执行
mklink /J不需要管理员权限(symlink/D才需要提权);管理员只在"文件被占用"时有帮助。- 内置四道拦截,全部不删源:同盘(同卷)迁移 / 源已是 junction / 目标盘余量不足 / 源目录因占用没搬干净。
- 源没搬干净时提示"关掉软件后重跑同一条命令续传",目标副本保留,不会丢数据。
- junction 建不出来会自动 robocopy 搬回源目录回滚,并输出搬回后的体积供核对。
- ⚠️ 交付时必须告知用户:通过联接删文件 = 真删;将来要还原,删的是联接本身,不要删目标目录。
搬移 B — 纯归档搬移(软件无关的数据)
scripts/move_robocopy.ps1:备份快照、自己拷贝的资料,搬完不需要保留原路径时用这个。
robocopy "<src>" "<dst>" /E /MOVE /R:1 /W:1 /MT:16
不用 Move-Item:>260 字符路径会整体中止并留下半搬状态;先跑 -NoMove 可空跑校验。
目标盘余量校验(≥ 源体积 ×1.05)已内置,不足会直接 ABORT。
怎么选:动的是「软件正在读写的目录」(微信/QQ/游戏/剪映素材/飞书)→ A 建联接;
动的是「备份/归档/用户自己放的东西」→ B 直接搬。拿不准就用 A,它是可逆的。
详细限制对照、退出码、超时与日志策略见 references/sandbox-deletion.md。
Step 5 — 复测 + 交付(必做,别漏)
- 复测:重跑 Step 1 扫描 +
Get-PSDrive,给 before → after 对比表。 - 收尾脚本:把"本次被占用没删成的项"写进回收站脚本交给用户本机跑:
- 复制scripts/recycle_template.ps1到工作目录,改顶部目标列表
- 配一键清理.bat(ASCII 内容):chcp 65001+powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0xxx.ps1"
-.ps1必须存为 UTF-8 with BOM,否则 PowerShell 5.1 中文乱码 - 应用内清理 / 改存储位置指南(最安全、常能各自腾几 GB):见 references 路径表。
- 治本建议:库文件夹右键属性→位置→迁到数据盘;磁盘清理(清理系统文件);存储感知;
powercfg -h off。
Step 6 — 提议每月复查(差异化价值,别漏)
清理是一次性收益、磁盘是持续消耗。交付成果时主动问用户要不要建月度体检自动化:
只读、不删任何东西,每月出一份 HTML 报告 + 空间趋势对比,爆红前一个月预警。
配置模板、rrule、prompt 模板、复查时的增量判断方法见 references/automation-setup.md。
多语言 / 英文系统(非中文环境必读)
- 报告与收尾脚本已内置中英双语,
-Lang auto按InstalledUICulture自动切换,HTMLlang属性同步。 - 英文系统用户可直接用
-Lang en;中文软件目录(剪映/飞书/WPS)在英文系统上仍是中文名,报告里要给"这是什么"的判定,别指望用户自己看懂。 - 实测澄清(别再重复排查):区域设置不会把
24.9变成24,9,Get-Date -Format分隔符也不变,系统目录物理名在所有语言版本一致(只有显示名本地化)。真正会出问题的只有六个点,见references/i18n-and-localization.md。 - 交付给英文用户时:报告用英文、
.bat保留chcp 65001、.ps1必须 UTF-8 with BOM、路径一律走$env:LOCALAPPDATA等环境变量(别硬编码含中文用户名的路径)。
授权与免责(商用分发版必读)
- 本技能供已获得副本的用户自由使用(个人自用不限),但属专有授权作品:禁止未经授权的复制分发、二次销售、公开发布或翻写后上架;详见根目录
LICENSE.md。 - 每个
.ps1顶部的版权声明不得删除或篡改。 - 涉及永久删除时,回复里必须出现一行不可恢复提示,并给出"先搬移 / 先备份"的备选路径——不要直接替用户做决定。
- 交付的 HTML 报告与整理清单是给用户看的结果物,不要往里面注入免责声明 banner(用户会自行处理)。
输出格式
先给结论(为什么满、根因一句话),再给表格(项目 / 大小 / 性质 / 处置),最后给分档或名单选项。
收尾必须给一张 before → after 释放量表(用户只看这个数字判断有没有用)。
常见问题(用户问到就直接答,别重复排查)
| 现象 | 原因与处理 |
|---|---|
| 可清理的绿区很小 | 多半是非管理员运行,系统级缓存读不到。用管理员身份重开后再跑一次,常能多出几 GB。 |
| 清理后还剩一堆删不掉 | 文件被运行中的程序占用。关掉对应软件(剪映/飞书/微信)重跑同一条命令即可续传;删不掉的会写进收尾脚本,重启后清。 |
| 某个脚本跑不动 | 先确认文件存在(本包含全部 8 个脚本,无阉割)。若被执行策略拦,跑一次 Set-ExecutionPolicy -Scope CurrentUser RemoteSigned。 |
| 迁移失败 / 权限不足 | mklink /J 建联接本身不需要提权,失败多因目标文件被软件占用。退出该软件后重试,不要在软件运行时搬它自己的目录。 |
| 报告乱码 | 报告是 UTF-8 自包含单文件,用 present_files 展示路径即可。乱码是浏览器误判成 GBK,手动选 UTF-8 编码。 |
| 迁移后能撤销吗 | 能,junction 是可逆的:删掉联接(不要删目标目录),再把目标搬回原盘即可恢复原状。 |
| 会不会删掉我的文档和照片 | 不会。桌面 / 文档 / 图片 / 视频 / 音乐里的个人文件既不自动删、也不进可清理清单,只有用户逐项点名才会处理。 |
| 红区那么大为什么不算 | 系统核心与应用本体不在可清理范围,也不为了"覆盖率"去展示——列出来只会让人误以为删得掉。 |
分发形态说明
本包为 tier 2 全量版,8 个脚本与全部 references 齐备,所有能力直接可用,无需任何授权或联网校验。
若将来要拆成多个 SKU 分级分发,正确做法是按交付文件集合分级(免费版里不放清理脚本,自然无从启用),
而不是做联网 License 校验——联网、签名校验、反调试都会被安全审计判 P1/P0 高危;且对纯文本技能而言删掉那几行就能绕过,防不住还赔上分发资格。
| 等级 | 能力 | 交付内容 |
|---|---|---|
| tier 0 | 扫描 + HTML 报告 + 建议清单 | pipeline.ps1、scan_*.ps1、report_html.ps1、references 全部 |
| tier 1 | +绿区清理 | 追加 clean_dotnet.ps1、recycle_template.ps1 |
| tier 2(本包) | +目录联接迁移 +月度复查 | 追加 migrate_junction.ps1、automation-setup.md 配置、遗失时段增量判断 |
> 价值锚点建议放在案例库(每月新增真实排查)与售后答疑上,而不是"藏起来的代码"。
文件结构
SKILL.md 本文件:流程与铁律(中文主入口)
SKILL_en.md 英文版主流程(国际化用)
LICENSE.md 商业授权协议 + 免责声明(© 黄小豪 huangxiaohao)
icon.svg 上架图标(SkillHub 只收纯 SVG,位图会被拒)
references/app-hotspots.md 系统盘大头皮性质表 + 剪映专章(C 盘残留 + F 盘草稿回收站)
references/other-drives.md 数据盘口径:体检流程 / 允许动作 / 盘位角色
references/sandbox-deletion.md 删除方式对照 + scriptblock 加载法 + .NET/robocopy 代码 + 环境坑
references/automation-setup.md 每月复查自动化的 rrule、prompt 模板与增量判断
references/i18n-and-localization.md 多语言 / 英文系统:实测结论 + 六个真实坑 + 交付检查清单
scripts/pipeline.ps1 ★ 一键流水线:各盘概览+顶层占用+扫码报告+下一步建议(默认入口)
scripts/scan_appdata.ps1 系统盘只读扫描(-Drive)
scripts/scan_bigfiles.ps1 数据盘只读体检(-Drive -MinMB -OlderThanDays)
scripts/report_html.ps1 自包含 HTML 报告(-Drive -Lang auto|zh|en -IncludeAppData)
scripts/clean_dotnet.ps1 高速删除(-WhatIf 预演、自动推断盘符)
scripts/migrate_junction.ps1 ★ 目录联接迁移(搬走后软件照常用,四道拦截+自动回滚)
scripts/move_robocopy.ps1 纯归档跨盘搬移(-NoMove 试跑、目标盘余量校验,/UNILOG 保中文路径)
scripts/recycle_template.ps1 交付给用户的回收站版本清理脚本模板(中英双语)
assets/sample_report_zh.html 中文报告样例
assets/sample_report_en.html 英文报告样例
安全模型(向买家说明时的三句话)
- 扫描全在本地:只读文件名、大小、日期做统计,不读取文件内容,不上传任何数据。
- 绿区是纯缓存:列入清理的只有删了能自动重建的缓存/日志/临时文件,不含任何用户资料;个人目录(桌面/文档/图片/视频)永不自动删。
- 红区不碰:系统核心与已安装应用本体不进报告、不进可清理清单;迁移只搬不删,且可用联接保证软件继续正常工作。
编写脚本时的环境坑(改脚本必看)
- 自定义函数名避开内置别名:
H=Get-History,定义成函数后调用会被别名吞掉、输出全空,
排查成本极高。用W或多字母命名。 [System.Web.HttpUtility]未必可用,HTML 转义手写Replace('&','&amp;')更稳。- 交付给用户的
.ps1一律存为 UTF-8 with BOM。 [math]::Round(2.5)返回 2(银行家舍入):必须显式[MidpointRounding]::AwayFromZero。- 别用
exit:scriptblock 加载时exit会杀掉整个宿主会话,参数校验失败一律return。 - Int + String 会强转报错:
$count + " copies"会把右侧转 Int 后炸掉,用"$($count) copies"。 - robocopy 用
/UNILOG:不用/LOG::后者按 ANSI 写盘,中文路径全变问号。 - 变量紧跟冒号会被当成作用域变量:
"$Drive:\"/"$srcDrive:)"会报
变量引用无效。':' 后面的变量名称字符无效(同$env:X的写法)。一律写"${Drive}:\"。
这个语法解析器能抓出来(显示 URL: missing valid),但容易在长脚本里漏掉,写完 8 个脚本跑一次
[Parser]::ParseFile全量扫描最省事。 - 交付前 BOM 必须分文件处理:
.ps1要 UTF-8 with BOM(否则 PS 5.1 双击运行中文乱码),
.md不要 BOM(官方校验器读到\ufeff---会报No YAML frontmatter found)。
两个方向相反,切勿统一批量加 BOM。 - UTF-8 BOM 跨 PS 版本不一致(5.1 有 / 7 无),统一用
[IO.File]::WriteAllText+UTF8Encoding($true)。 - 每个脚本内联一份
Num / DtDay / SaveUtf8(含[Console]::OutputEncoding = UTF8),
不为共用模块做跨文件引用 —— 脚本要能单独复制出来给用户双击运行。