PowerShell脚本实战:从零搭建C盘自动清理方案
C盘又飘红了磁盘空间不足的弹窗跳出来的时候大多数人第一反应是打开各种清理软件点一遍“一键清理”。但用过的人都知道这玩意清完没多久空间又回去了而且动不动夹带私货动不动就要你开会员。我自己是写脚本的人从接触bat到后来用PowerShell折腾过不少清理方案今天就把这套本地电脑C盘清理脚本从头到尾拆一遍包含清理目录的边界、脚本怎么写、为什么有的脚本一运行就闪退、怎么挂到任务计划里让它自己干活。无论你是普通用户还是写代码的照着抄作业就行。1. C盘为什么总是爆满先搞清楚垃圾到底堆在哪里1.1 最常见的三类C盘“吞金兽”C盘空间不是一夜之间没的。你回忆一下系统盘空间通常是被三类东西吃掉第一类是系统和软件的临时文件说白了就是程序跑的时候生成的中间产物很多程序退出之后并不会主动清理日积月累就是几个G甚至十几个G第二类是缓存文件浏览器缓存、缩略图缓存、软件更新缓存这类文件设计出来的本意是加速下次访问但如果长期没人管就会膨胀到非常离谱的体量第三类是日志和旧版本文件Windows系统更新会留下备份系统事件日志一直在写软件卸载之后也会残留一堆配置和数据这些都属于“看起来不占地方实际加起来吓死人”的部分。我见过最夸张的一台机器C盘500G用了490多G排查下来Windows更新缓存占了80多G浏览器缓存占了几十个G光是这两个大头清完就释放了接近一半空间。所以你看清理的前提是先定位知道垃圾集中在哪里脚本才有意义。1.2 为什么手动清理和垃圾清理软件经常不管用手动清理的问题在于不明所以。大多数人只知道清回收站清下载文件夹但这些根本动不了上面说的几块大骨头。Windows自带的磁盘清理是一个入口但它默认不会打开所有清理项而且它对很多第三方软件缓存毫无办法。至于第三方清理软件问题更大一个是弹窗广告和推广捆绑另一个是它们为了让你继续买会员通常会留一手真正能清出来的空间永远不可能让你满意。更深一层的原因很多用户懒得去搞懂哪些目录能删哪些不能删干脆全部交给工具但工具本身的规则是黑盒的。我的观点是清理这件事一定要掌握在自己手里你不需要一次性搞清楚Windows所有目录的用途只要能守住几条安全边界写一个脚本把那些明确无害的文件清掉效果就比大多数一键清理工具好得多。这也是我为什么一直坚持用脚本的原因项目是自己写的每一步干什么清清楚楚不会误删不会被套路。2. 清理脚本的核心边界什么能删、什么不能删写清理脚本第一原则不是“清得多”而是“删不错”。我见过有人图省事直接对整个 C 盘跑递归删除结果系统崩了只能重装。所以脚本里每一条目录路径都必须有明确的依据。下面我把清理清单和禁区完整摆出来照着抄可以但前提是你得理解为什么。2.1 可安全删除的目录清单先说能删的我把它们分成几个级别按安全性从高到低排清理项路径说明风险等级用户临时目录%TEMP%、%LOCALAPPDATA%\Temp程序运行时生成的临时文件低系统临时目录C:\Windows\Temp系统组件、安装程序产生的临时文件低Windows更新缓存C:\Windows\SoftwareDistribution\Download更新的安装包缓存安装完成后无用低需停服务回收站C:\$Recycle.Bin通过Clear-RecycleBin命令清空低缩略图缓存%LOCALAPPDATA%\Microsoft\Windows\Explorer图片缩略图缓存自动重建低软件日志C:\Windows\Logs下载目录等系统组件运行日志中浏览器缓存%LOCALAPPDATA%\Microsoft\Edge\User Data\Default\Cache等浏览器网络缓存中分发缓存 (WinSxS)C:\Windows\WinSxS不能直接删文件用DISM组件清理中这里面最容易被大家忽略的是%LOCALAPPDATA%\Temp。很多人只清C:\Windows\Temp但当前用户的临时目录往往是最大的垃圾场编译缓存、软件解压的中间产物、聊天软件图片临时加载文件全在那。我清理过的机器里光这个目录清出 10G 以上都很常见。2.2 千万不能碰的目录和文件红色禁区不用记太多但要记得死C:\Windows\System32和C:\Windows\SysWOW64这俩是系统核心运行库删一个文件系统就可能蓝屏。C:\Windows\WinSxS这个目录很特殊它只是看起来大里面是并行组件存储不能直接手动删文件要用Dism /Online /Cleanup-Image /StartComponentCleanup去清理旧版本组件。C:\Program Files和C:\Program Files (x86)这是安装软件的位置不能靠脚本“清理”卸载软件要走正规卸载程序。C:\Users\你的用户名下的文档、桌面、图片、视频目录默认不能清理除非脚本里明确指定了只清某一类缓存子目录。页文件pagefile.sys和休眠文件hiberfil.sys这俩是系统虚拟内存和休眠镜像不是垃圾文件删除会导致系统不稳定只能通过系统设置调整大小或关闭休眠功能。2.3 删除前必须养成的备份习惯哪怕清单再安全我也建议在正式清理前做一次系统还原点或者至少把脚本删掉的内容先记到日志里。操作方式很简单在PowerShell里跑Checkpoint-Computer -Description Before-Cleanup -RestorePointType MODIFY_SETTINGS建一个还原点之后就算手滑删了不该删的也有后悔药。我实际清理过几百台机器从没遇到过还原点用上的情况但心理安全感完全不一样强烈建议保留这层保险。3. 从零写一个C盘清理脚本环境准备与脚本主体3.1 清理脚本的选型批处理还是PowerShell很多人在群里面问清理脚本怎么写我看到的大量答案是放一段.bat批处理。bat 确实简单几行del命令就能跑但它有几个绕不开的痛点中文路径容易乱码删除大量文件时没有进度反馈出错处理很弱。所以我自己的主力方案是 PowerShell 脚本.ps1格式。PowerShell 优势很明显原生支持中文不存在编码问题有Remove-Item -ErrorAction SilentlyContinue这种细粒度的错误控制可以直接调用 .NET 类库比如算目录大小、处理文件占用能配合 Windows 任务计划程序做高级调度。当然最后我会补一个 bat 版本给那些不想碰 PowerShell 执行策略的老哥应急用。但如果条件允许真心建议用 ps1。3.2 可用脚本逐段拆解下面这个脚本是我自己日常在用的精简版先放完整代码再逐段解释。# C盘清理脚本 Clean-CDrive.ps1 # 运行前建议以管理员身份打开 PowerShell $logPath C:\CleanupLogs\clean_$(Get-Date -Format yyyyMMdd_HHmmss).log New-Item -ItemType Directory -Path (Split-Path $logPath) -Force | Out-Null function Write-Log { param([string]$Message) $ts Get-Date -Format yyyy-MM-dd HH:mm:ss Write-Host $ts $Message Add-Content -Path $logPath -Value $ts $Message } # 1. 清理用户临时目录和系统临时目录 $tempPaths ( $env:TEMP, $env:LOCALAPPDATA\Temp, C:\Windows\Temp ) foreach ($p in $tempPaths) { if (Test-Path $p) { $before (Get-ChildItem $p -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum Remove-Item $p\* -Recurse -Force -ErrorAction SilentlyContinue $after (Get-ChildItem $p -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum $freed [math]::Round(($before - $after) / 1MB, 2) Write-Log Cleaned $p, freed ${freed} MB } } # 2. 清空回收站 Clear-RecycleBin -Force -ErrorAction SilentlyContinue Write-Log Recycle Bin cleared # 3. 清理 Windows 更新缓存先停止 Windows Update 服务 $wuService Get-Service -Name wuauserv -ErrorAction SilentlyContinue if ($wuService) { Stop-Service -Name wuauserv -Force -ErrorAction SilentlyContinue Remove-Item C:\Windows\SoftwareDistribution\Download\* -Recurse -Force -ErrorAction SilentlyContinue Start-Service -Name wuauserv -ErrorAction SilentlyContinue Write-Log Windows Update cache cleaned } # 4. 清理缩略图缓存 Remove-Item $env:LOCALAPPDATA\Microsoft\Windows\Explorer\thumbcache_*.db -Force -ErrorAction SilentlyContinue Write-Log Thumbnail cache cleaned # 5. 清理浏览器缓存Edge / Chrome按需取消注释 $browserCachePaths ( $env:LOCALAPPDATA\Microsoft\Edge\User Data\Default\Cache, $env:LOCALAPPDATA\Google\Chrome\User Data\Default\Cache ) foreach ($p in $browserCachePaths) { if (Test-Path $p) { Remove-Item $p\* -Recurse -Force -ErrorAction SilentlyContinue Write-Log Browser cache cleaned: $p } } # 6. 使用 DISM 清理 WinSxS 旧组件耗时较长可选 # Dism.exe /Online /Cleanup-Image /StartComponentCleanup # Write-Log WinSxS component cleanup done Write-Log Cleanup finished.3.3 核心逻辑说明这段脚本的核心逻辑分三步锁定目录、删除内容、记录日志。第1步$tempPaths是一个数组里面放了我们要清理的所有临时目录路径。“清理目录”实际含义是删除目录里的所有内容而不是删除目录本身所以用的是$p\*不是$p。这个细节很重要否则你会发现清理完 Temp 目录自己也消失了。第2步Remove-Item -Recurse -Force -ErrorAction SilentlyContinue是关键组合。-Recurse表示递归删除子目录和子文件-Force强制删除隐藏和只读文件-ErrorAction SilentlyContinue的意思是遇到正在被占用的文件、没有权限的文件时不要报错中断直接跳过。这个参数对脚本稳定性太重要了没有它清理到一半碰到一个被占用的 dll 文件整个脚本就会红屏。第3步我用了一个Write-Log函数每次清一个目录就记录清了多少空间、什么时候清的。这个日志习惯是写清理脚本最容易忽略的地方但实际价值很高——你能清楚地看到每次清理的真实效果而不是凭感觉说“清完是不是少了几个G”。另外注意第3段清理 Windows 更新缓存之前先停掉了wuauserv服务清完再启动。如果不这么做下载缓存目录的文件正处于被系统服务锁定的状态删除会失败甚至可能导致后续更新异常。我之前第一次写这功能时就没停服务结果清除失败不说文件还残留在那里空间完全没释放。4. 脚本运行过程中的三大致命坑闪退、执行策略与文件占用4.1 Windows脚本命令闪退的排查链路很多人在网上搜“Windows脚本命令闪退”搜到了脚本抄下来双击运行结果窗口闪了一下就没了什么都没发生。这个我有话说闪退的原因 90% 是这三个第一个原因是脚本文件编码不对。bat 脚本如果里面有中文文件保存成了 UTF-8 编码那么 cmd 默认用系统 ANSI 编码解析中文全部变乱码执行到乱码那一行就直接退出了。解决办法是bat文件另存为 ANSI 编码或者干脆 PowerShell 脚本保存成 UTF-8 with BOM。我在实际写脚本时纯 bat 就直接全英文注释不碰中文这是最省事的。第二个原因是脚本路径名带了空格。很多人把脚本放在C:\Users\My Documents\C Drive Cleanup\这种带空格的目录里面双击 bat 或 ps1 运行后路径被截断找不到文件一闪而过。解决办法是运行之前先cd /d切换到脚本所在目录或者在调用脚本的时候用引号把完整路径包起来。第三个原因是执行策略限制。PowerShell 默认情况下禁止运行未签名的本地脚本双击 ps1 文件时系统只会在记事本里打开它而不是执行。这个时候就算不闪退你也跑不起来。4.2 PowerShell执行策略与“无法加载文件”问题在 PowerShell 里面执行脚本时如果系统提示 “无法加载文件 ...因为在此系统上禁止运行脚本”那你遇到的就是执行策略问题。这个问题在热搜词里面反复出现原因很简单Windows 默认的Restricted策略基本不允许跑本地 ps1 脚本。解决方式有两种# 查看当前执行策略 Get-ExecutionPolicy -List # 当前用户设置成 RemoteSigned允许本地未签名脚本运行 Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUserRemoteSigned的意思是本地创建的脚本可以运行从互联网下载的脚本必须带可信签名才能运行。日常调试清理脚本RemoteSigned是最合适的配置不要图省事直接设成Unrestricted没必要给自己挖坑。如果你是以管理员身份运行 PowerShell还可以用组策略的方式去开但个人电脑直接用命令行设置就行一劳永逸。4.3 文件占用导致的删除失败脚本运行一段时间后你会发现日志里面某些目录释放的空间是 0 MB。别慌这大概率不是脚本写错了而是文件被占用。关于占用主要有两个来源一是杀毒软件正在扫描这些临时文件二是某个应用程序正在写缓存。处理办法是给Remove-Item加上-ErrorAction SilentlyContinue跳过这些文件不要中断整个脚本。另外一个技巧是清理浏览器缓存前先退出浏览器。如果你在脚本运行的时候浏览器开着Cache 目录下的文件基本都会锁定全部删不掉。我写的脚本里不会强制关闭浏览器因为太霸道了所以我通常在脚本开头加一个提醒Write-Host 请先关闭浏览器再运行清理脚本否则缓存清理不完整。 -ForegroundColor Yellow这种提醒对用户体验很重要运行之前就知道该怎么做而不是跑了半天才发现啥也没清掉。5. 让清理变成日常任务计划程序与开机自启的折腾经验5.1 用任务计划程序做自动清理清理脚本最大的价值在于定时执行而不是每次手痒了才跑一次。Windows 自带的“任务计划程序”就能搞定不依赖任何第三方工具。操作步骤并不复杂按Win R输入taskschd.msc打开任务计划程序右侧点击“创建基本任务”名称填 “C盘自动清理”触发器选“每天”时间你可以选凌晨或者午休时间我一般是凌晨2点那时候基本不会有人用电脑操作选“启动程序”程序填powershell.exe参数填-NoProfile -ExecutionPolicy Bypass -File C:\Scripts\Clean-CDrive.ps1完了之后双击这个任务在“常规”选项卡勾选“使用最高权限运行”确保脚本以管理员权限执行。这里有个小坑如果任务计划里调用的 ps1 路径含有空格参数里必须加上引号否则系统找不到文件。我见过太多人在这一步翻车任务计划一直报错找不到文件其实就把路径加上英文双引号就行。另外触发器设置成“每天”不是死板的你可以切成“每周”或“登录时”看你自己使用习惯。如果你电脑每天固定时间开机选每天没问题如果电脑不是天天开建议选“启动时”或者“登录时”否则一周过去一次都没跑过。5.2 开机自启脚本的配置门槛有些人不想用任务计划就想让脚本开机直接跑。思路也不难把 ps1 的快捷方式放到开机启动目录shell:startup即可或者注册一个 Run 注册表项。但我实际用下来强烈不建议用开机自启方式运行清理脚本。原因是开机瞬间系统和各种软件都在初始化文件锁定非常严重临时目录里可能有大量的文件正在被写。这时候你跑清理脚本大部分文件删不动效率极低而且还有可能误伤启动中的软件所需的临时文件导致软件启动出错。任务计划的好处是触发时机可控你完全可以设定在开机后10分钟执行那时候系统和常用软件已经稳定下来了。如果想在 PowerShell 脚本里做“延迟启动”可以直接写Start-Sleep -Seconds 60放在脚本开头等待一分钟再开始清理简单粗暴但也有效。5.3 日志分析与清理效果验证脚本跑完不能白跑你得看日志。我写的脚本会把每次清理的时间和释放空间写到C:\CleanupLogs目录下文件名带时间戳。看日志的意思不是只瞄一眼“嗯跑完了”而是对比几次清理的数据。举个实例来说明我第一次帮同事清理他的工作笔记本跑了脚本日志显示临时目录释放了 3.2GBWindows更新缓存释放了 5.8GB回收站释放了 1.1GB加起来大概 10GB 左右。表面上看效果很好但这说明这台电脑已经很久没清理过了。等到第二次清理日志显示释放空间只有 300MB这个时候就说明系统进入正常节奏了。如果哪一天日志数据突然又飙到好几个G那大概率是某个软件出了问题疯狂写缓存那就不只是清理的问题了得排查软件本身。6. 清理脚本的进阶玩法空间统计、多级策略与扩展方向6.1 用脚本统计大文件并给出清理建议基础清理脚本能解决80%的C盘空间问题但剩下的20%往往是大文件占据的。比如微信和QQ的聊天记录、开发工具缓存的虚拟设备文件、Docker镜像那些大家伙脚本不能盲目清理但它可以帮你找出来。在 PowerShell 里统计文件夹大小是很成熟的操作我一般会用这样的函数function Get-FolderSize { param([string]$Path) $size (Get-ChildItem $Path -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum return [math]::Round($size / 1GB, 2) } Get-FolderSize C:\Users\$env:USERNAME\AppData\Documents\WeChat Files把常见大目录列出来用这个函数跑一遍你就知道接下来该手动处理哪些东西。这种方法比在资源管理器里面右键看属性要快太多而且可以一次看十几个目录。6.2 多级清理策略轻量、标准、深度写脚本这东西最怕的就是一刀切。后来我想了一个办法给清理脚本增加三个模式轻量模式只清理用户临时目录和回收站耗时几秒安全系数极高适合每天定时跑。标准模式在轻量模式基础上加上系统临时目录、Windows更新缓存、缩略图缓存适合每周跑一次。深度模式标准模式基础上启动 DISM 组件清理、清理浏览器缓存、清理旧日志耗时十几分钟到半小时适合每月跑一次。实现方式很简单脚本开头加一个参数param( [ValidateSet(lite, standard, deep)] [string]$Mode standard ) switch ($Mode) { lite { $cleanWinUpdate $false; $cleanBrowser $false; $cleanDism $false } standard { $cleanWinUpdate $true; $cleanBrowser $false; $cleanDism $false } deep { $cleanWinUpdate $true; $cleanBrowser $true; $cleanDism $true } }在各个清理段落的 if 判断里加上对应开关就行。然后任务计划程序里建三个任务分别调度不同模式完美做到“日常不折腾、定期大扫除”。6.3 关于“设备老化测试全自动执行脚本”里的思路借鉴搜索热搜词里看到“设备老化测试全自动执行脚本”这让我想到清理脚本其实也可以往这个方向扩展。设备老化测试的核心思路是持续监控设备状态自动记录数据发现异常自动处理——清理脚本完全可以借用同样的思路比如加上磁盘剩余空间监控功能if ((Get-PSDrive C).Free / 1GB -lt 20) { Write-Log C盘剩余空间低于20GB开始自动清理 # 调用标准清理流程 $PSScriptRoot\Clean-CDrive.ps1 -Mode standard } else { Write-Log C盘剩余空间充足本次跳过清理 }把这个监控脚本做成计划任务每天执行一次它就能自动判断是否需要清理。这种做法比固定每天跑一次清理脚本更聪明它把“清理”从定时动作变成了条件触发动作大幅减少对系统的无效操作。我现在的个人电脑就是这么配置的跑了大半年C盘空间一直稳定在安全线以上基本没再手动作业过。6.4 脚本的本土化调整建议最后说一个因地制宜的点。网上很多清理脚本是直接从英文论坛抄的清理的目录也是英文系统默认路径。但国内用户环境普遍用的应用是微信、QQ、钉钉、企业微信这些它们的缓存目录往往在Documents、AppData和聊天软件的专门目录下不在外国脚本的清单里。以微信为例它的文件存储默认位置在C:\Users\用户名\Documents\WeChat Files这个目录里除了聊天记录还有大量图片和视频缓存。清理的时候千万不能整个删除否则聊天记录全没了。正确做法是进入这个目录找到对应微信号的子目录再清理里面的FileStorage\Cache、FileStorage\Video这些纯缓存子目录。这块内容是脚本无法完全自动化的因为每个人的微信存储路径不一致所以我建议你根据自己的实际使用软件把这类路径逐个加进脚本的白名单里定期清理。我在文档注释里也留了这些自定义路径的位置看到脚本里那段注释“在此添加你常用的第三方软件缓存路径”就是提醒使用者根据自己的软件环境继续扩展。清理脚本不是写完了就一劳永逸的它是一个随着你使用习惯不断迭代的小项目。自己在实际使用这套脚本的过程中最大的体会就是“克制”两个字。别看脚本写出来能一键清理好几个G但设计思路每一步都在想怎么少删、怎么稳删。清理工具不是越激进越好而是把一个动作重复做、稳定做长期下来系统盘才会一直保持健康。你从手动清理过渡到脚本清理之后就会发现每隔一段时间跑一次脚本已经变成一种习惯看着日志里持续稳定的释放数据比那些花里胡哨的清理软件界面让人安心得多。