Windows 已安装程序跨盘迁移
何时用
用户要把已经装好的程序挪到别的盘(省 C 盘空间)。不是新装,新装直接改安装路径即可。
核心思路:junction 重定向
不要去改快捷方式(改 .lnk 需要 COM,常被安全策略拦截)。正确做法是:
复制 → 校验 → 删原位 → 在原位建 NTFS junction 指向新位置。
Windows 应用穿透 junction 无感,桌面/开始菜单/卸载器全部照常工作,C 盘只留 0 字节的联接。
步骤
1. 摸清家底
ls -d /c/Users/<用户>/AppData/Local/Programs/* # 用户级安装常见位置
tasklist | grep -i <程序名> # 是否在运行
顺带查三类附带目录(常在 AppData 下,Electron 固定用 %APPDATA%,一般不动):
- AppData\Roaming\<app> — 配置/登录态,通常很小,留着
- AppData\Local\<app>-updater — electron-updater 缓存,常几十~上百 MB,可安全清理
2. 关进程
taskkill //F //IM <App>.exe
确认无残留 + 主 exe 可写(-w 测试通过)再动手。
3. 复制(robocopy)
export MSYS_NO_PATHCONV=1 # 必须!否则 /R:2 被 MSYS 转成 E:/ 报"无效参数 #3"
/c/windows/system32/robocopy.exe "C:\源" "D:\目标" /E /COPY:DAT /R:2 /W:1 /NFL /NDL /NP
退出码 <8 即成功(1 = 有文件被复制,正常)。
4. 校验(不可跳过)
两侧 find ... -type f | wc -l 与 du -sh 必须一致,再抽查主 exe / 卸载器 / resources。
5. 切换
mv "原名" "原名_OLD_BACKUP" # 先改名,不直接删
New-Item -ItemType Junction -Path 'C:\原路径' -Target 'D:\新路径'
验证:(Get-ChildItem 'C:\原路径' -Recurse -File | Measure-Object).Count 应等于新目录文件数。
6. 改卸载注册表
$key = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\<GUID>'
Set-ItemProperty $key -Name 'UninstallString' -Value '"D:\新路径\Uninstall XX.exe" /currentuser'
Set-ItemProperty $key -Name 'DisplayIcon' -Value 'D:\新路径\XX.exe,0'
Set-ItemProperty $key -Name 'InstallLocation' -Value 'D:\新路径'
找 key:遍历 HKCU / HKLM / HKLM\WOW6432Node 的 Uninstall,匹配 DisplayName。
junction 存在时这步可选(C 路径照样能用),但改了更干净。
7. 删除备份
确认 4、5 都通过后删 *_OLD_BACKUP。
环境坑(本机实测)
| 坑 | 绕法 |
|---|---|
reg.exe 在沙箱黑名单 |
用 PowerShell 的注册表 Provider |
PowerShell 里禁 COM(WScript.Shell) |
别改 .lnk,走 junction |
Bash 里调 powershell.exe 被拦 |
只能用 PowerShell 工具 |
| PowerShell 工具不回传 stdout | 结果 Out-File 到文件,再用 Read 读 |
Remove-Item 被 safe-delete fail-closed(trash-failed) |
改用 Bash rm -rf |
Git Bash 的 find 不跟随 junction(报 0) |
用 PowerShell Get-ChildItem -Recurse 或 ls 验证 |
| MSYS 路径转换毁 robocopy 参数 | export MSYS_NO_PATHCONV=1 |
收尾提醒
- GUI 程序沙箱起不来,让用户自己双击图标验证一次再收工
- MCP/HTTP 类服务(如 MultiPost 的 127.0.0.1 端口)与安装路径无关,不受影响