记一次 18W+ 项目依赖残留撑爆 Win10 回收站导致死机的抢救经历
前言:一次寻常的文件整理与意外「死机」
日常做开发项目、拉取依赖(例如前端的 node_modules、各种构建缓存等),日积月累下来可能会产生海量的碎小文件。今天(2026-10-06)我在 Windows 10 电脑中按部就班地整理磁盘空间,顺手将几个很久不用的旧项目文件夹扔进了回收站。
本以为这只是一次普通的右键「清空回收站」,没想到系统资源管理器瞬间无响应,CPU 占用率直接飙升并出现异常锁死,鼠标指针打转,整台电脑随即陷入卡死状态,连任务管理器都难以唤醒。
破局:彻底删除 $Recycle.Bin 目录的 PowerShell 脚本
硬撑着右键清空显然不可行,直接手动删除系统回收站根目录又容易引发权限问题与 GUID 混乱。在反复尝试后,得到了一个更加彻底的方案:不再逐文件分批枚举,而是直接以管理员权限逐盘移除 $Recycle.Bin 目录,遇到权限不足时自动接管所有权并修复 ACL,Windows 会在后续需要时自动重建回收站,安全干净。
核心思路
自动提权: 脚本启动时自动检测当前是否为管理员权限,若不是则通过 UAC 重新以管理员身份启动自身,无需手动右键「以管理员身份运行」。
自动枚举磁盘: 通过
Win32_LogicalDisk自动获取所有本地固定磁盘(DriveType=3)和可移动磁盘(DriveType=2),不再硬编码盘符,盘符排序后逐个处理。直接删除 + 权限修复兜底: 首先调用
cmd.exe /c rd /s /q直接移除$Recycle.Bin目录(系统级删除命令,速度极快);若首次删除未完成,则依次调用takeown接管所有权、icacls为 Administrators 组授予完全控制权限,再次重试删除。安全校验: 处理前严格校验路径,确保只操作盘符根目录下的
$Recycle.Bin,避免路径拼接异常导致误删。进度与日志: 通过
Write-Progress显示整体进度,所有操作写入%TEMP%下带时间戳的日志文件,最终输出成功/跳过/失败汇总。
完整脚本代码
#requires -Version 5.1
# Windows 10 - 清空所有本地固定磁盘及可移动磁盘的回收站
# 警告:永久删除回收站内容,不可恢复
$ErrorActionPreference = 'Continue'
# ---------- 1. 自动请求管理员权限 ----------
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($identity)
$isAdmin = $principal.IsInRole(
[Security.Principal.WindowsBuiltInRole]::Administrator
)
if (-not $isAdmin) {
if (-not $PSCommandPath) {
Write-Host "请将脚本保存为 .ps1 文件后运行。" -ForegroundColor Red
Read-Host "按回车退出"
exit 1
}
$argsList = "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`""
try {
Start-Process -FilePath "powershell.exe" `
-ArgumentList $argsList -Verb RunAs
}
catch {
Write-Host "无法获取管理员权限:$($_.Exception.Message)" `
-ForegroundColor Red
Read-Host "按回车退出"
}
exit
}
// [!code fold:start]
# ---------- 2. 创建日志 ----------
$logFile = Join-Path $env:TEMP (
"RecycleBinCleanup_{0:yyyyMMdd_HHmmss}.log" -f (Get-Date)
)
function Write-Log {
param([string]$Message)
$line = "{0:yyyy-MM-dd HH:mm:ss} {1}" -f (Get-Date), $Message
Write-Host $line
Add-Content -LiteralPath $logFile -Value $line -Encoding UTF8
}
Write-Log "========== 开始清理回收站 =========="
Write-Log "日志文件:$logFile"
# ---------- 3. 获取本地固定盘和可移动盘 ----------
try {
$drives = @(
Get-CimInstance Win32_LogicalDisk |
Where-Object { $_.DriveType -in @(2, 3) } |
Sort-Object DeviceID
)
}
catch {
Write-Log "获取磁盘列表失败:$($_.Exception.Message)"
Read-Host "按回车退出"
exit 1
}
if ($drives.Count -eq 0) {
Write-Log "没有发现可处理的本地磁盘。"
Read-Host "按回车退出"
exit 0
}
$success = 0
$failed = 0
$skipped = 0
$total = $drives.Count
$index = 0
# ---------- 4. 逐磁盘清理 ----------
foreach ($drive in $drives) {
$index++
$letter = $drive.DeviceID
$recycleBin = Join-Path ($letter + '\') '$Recycle.Bin'
Write-Progress `
-Activity "清理 Windows 回收站" `
-Status "正在处理 $letter ($index/$total)" `
-PercentComplete (($index / $total) * 100)
Write-Log "正在处理磁盘 $letter"
if (-not (Test-Path -LiteralPath $recycleBin -PathType Container)) {
Write-Log "$letter 没有回收站目录,跳过。"
$skipped++
continue
}
# 安全检查:只允许处理盘符根目录下的 $Recycle.Bin
$expected = $letter + '\$Recycle.Bin'
if ($recycleBin -ine $expected) {
Write-Log "路径安全检查未通过,跳过:$recycleBin"
$failed++
continue
}
# 第一次尝试直接删除,避免不必要的全盘权限扫描
$output = & "$env:SystemRoot\System32\cmd.exe" `
/d /c "rd /s /q `"$recycleBin`"" 2>&1
$exitCode = $LASTEXITCODE
if ($exitCode -ne 0 -or
(Test-Path -LiteralPath $recycleBin -PathType Container)) {
Write-Log "$letter 首次清理未完成,尝试修复权限。"
# 获取目录及其子项的所有权
$output = & "$env:SystemRoot\System32\takeown.exe" `
/f $recycleBin /r /d Y 2>&1
$takeownCode = $LASTEXITCODE
if ($takeownCode -ne 0) {
Write-Log "$letter 获取所有权时出现错误:$($output -join ' ')"
}
# 向内置 Administrators 组授予完全控制权限
$output = & "$env:SystemRoot\System32\icacls.exe" `
$recycleBin /grant '*S-1-5-32-544:(OI)(CI)F' `
/t /c /q 2>&1
$aclCode = $LASTEXITCODE
if ($aclCode -ne 0) {
Write-Log "$letter 修改权限时出现错误:$($output -join ' ')"
}
# 再次尝试清理
$output = & "$env:SystemRoot\System32\cmd.exe" `
/d /c "rd /s /q `"$recycleBin`"" 2>&1
$exitCode = $LASTEXITCODE
}
# ---------- 5. 验证结果 ----------
if (-not (Test-Path -LiteralPath $recycleBin -PathType Container)) {
Write-Log "$letter 回收站目录已清除。"
$success++
}
else {
Write-Log "$letter 清理未能完成,可能有文件占用或权限限制。"
if ($output) {
Write-Log "最后的命令输出:$($output -join ' ')"
}
$failed++
}
}
Write-Progress -Activity "清理 Windows 回收站" -Completed
# ---------- 6. 输出汇总 ----------
Write-Log "========== 清理结束 =========="
Write-Log "清理成功:$success 个磁盘"
Write-Log "跳过:$skipped 个磁盘"
Write-Log "失败或未完成:$failed 个磁盘"
Write-Log "日志位置:$logFile"
Write-Host ""
Write-Host "清理任务结束。" -ForegroundColor Cyan
Write-Host "成功:$success 跳过:$skipped 失败:$failed"
Write-Host "日志:$logFile"
Write-Host "注意:Windows 通常会在以后需要时重新创建回收站目录。"
Read-Host "按回车退出"
使用方法与清理实录
将脚本保存为 .ps1 文件后直接运行即可,脚本会自动弹出 UAC 提权请求。终端与日志会实时显示每一块磁盘的处理进度:
%TEMP% 目录下生成带时间戳的日志文件。$Recycle.Bin 目录则直接跳过。rd /s /q 直接删除回收站目录;如遇权限不足,自动调用 takeown 接管所有权、icacls 授予 Administrators 完全控制权限后重试。Write-Progress 进度条结束。rd /s /q 命令直删目录,避开了资源管理器与 PowerShell 逐文件枚举的开销,即使面对 18W+ 小文件炸弹也能快速完成,不会再出现 CPU 占满、界面卡死的情况。给 Windows 10 用户的几点避坑建议
node_modules、vendor 还是虚拟环境 .venv,删除前最好使用 Shift + Delete 永久删除,或者直接通过命令行 rimraf / rd /s /q,千万不要随手拖入回收站。2. 定期巡检回收站文件数: 不要只看回收站占用的磁盘体积,小文件的数量(inode/元数据)才是引发资源管理器卡顿的元凶。
3. 卡死时切忌反复强制重启: 如果已经触发了清空卡死,切勿强行断电,可以尝试调出任务管理器结束
explorer.exe 进程,然后运行上面的脚本自动清理。4. 无需担心回收站被删:
$Recycle.Bin 是系统受保护目录,删除后 Windows 会在下次需要时自动重建,不会影响系统正常运行。
希望这次险些被「小文件炸弹」干翻的真实经历与解决方案,能给同样在 Win10 环境下做开发运维的小伙伴们提供一些参考与帮助。