Загрузка данных
$ErrorActionPreference = "Continue"
$TimeStamp = Get-Date -Format "yyyyMMdd_HHmmss"
$Log = "C:\Disk_C_AllUsers_Cache_Cleanup_$TimeStamp.log"
function Write-Log {
param(
[string]$Text
)
$Line = "{0} {1}" -f `
(Get-Date -Format "yyyy-MM-dd HH:mm:ss"),
$Text
Write-Host $Line
$Line |
Out-File `
-FilePath $Log `
-Append `
-Encoding UTF8
}
function Format-Size {
param(
[long]$Bytes
)
if ($Bytes -ge 1GB) {
return "{0:N2} GB" -f ($Bytes / 1GB)
}
if ($Bytes -ge 1MB) {
return "{0:N2} MB" -f ($Bytes / 1MB)
}
if ($Bytes -ge 1KB) {
return "{0:N2} KB" -f ($Bytes / 1KB)
}
return "{0} B" -f $Bytes
}
function Get-CDriveInfo {
$Drive = Get-WmiObject `
-Class Win32_LogicalDisk `
-Filter "DeviceID='C:'"
[pscustomobject]@{
SizeGB = [math]::Round(
$Drive.Size / 1GB,
2
)
UsedGB = [math]::Round(
($Drive.Size - $Drive.FreeSpace) / 1GB,
2
)
FreeGB = [math]::Round(
$Drive.FreeSpace / 1GB,
2
)
FreePct = [math]::Round(
($Drive.FreeSpace / $Drive.Size) * 100,
1
)
}
}
function Get-PathSize {
param(
[string]$Path
)
if (-not (Test-Path -LiteralPath $Path)) {
return 0L
}
try {
$Item = Get-Item `
-LiteralPath $Path `
-Force `
-ErrorAction Stop
if (-not $Item.PSIsContainer) {
return [long]$Item.Length
}
$Measure = Get-ChildItem `
-LiteralPath $Path `
-File `
-Force `
-Recurse `
-ErrorAction SilentlyContinue |
Measure-Object `
-Property Length `
-Sum
if ($Measure.Sum) {
return [long]$Measure.Sum
}
}
catch {
}
return 0L
}
function Get-ProfileUserName {
param(
[string]$SID,
[string]$ProfilePath
)
try {
$SecurityIdentifier = New-Object `
System.Security.Principal.SecurityIdentifier(
$SID
)
$Account = $SecurityIdentifier.Translate(
[System.Security.Principal.NTAccount]
).Value
return ($Account -split "\\")[-1]
}
catch {
return Split-Path `
-Path $ProfilePath `
-Leaf
}
}
function Get-BlockingProcesses {
param(
[string]$UserName,
[string[]]$ProcessNames
)
if (-not $ProcessNames -or $ProcessNames.Count -eq 0) {
return @()
}
return @(
$Script:OwnedProcesses |
Where-Object {
$_.User -ieq $UserName -and
$ProcessNames -icontains $_.Name
}
)
}
function Clear-CacheContents {
param(
[string]$ProfilePath,
[string]$UserName,
[string]$Category,
[string]$Path,
[string[]]$BlockingProcesses
)
if (-not (Test-Path -LiteralPath $Path)) {
return
}
$SizeBefore = Get-PathSize -Path $Path
if ($SizeBefore -eq 0) {
return
}
$Blockers = Get-BlockingProcesses `
-UserName $UserName `
-ProcessNames $BlockingProcesses
if ($Blockers.Count -gt 0) {
$Names = (
$Blockers |
Select-Object `
-ExpandProperty Name `
-Unique
) -join ", "
Write-Log (
"ПРОПУЩЕНО: {0}; пользователь: {1}; процессы: {2}; путь: {3}" -f `
$Category,
$UserName,
$Names,
$Path
)
$Script:SkippedCount++
return
}
Write-Log (
"Очистка: {0}; пользователь: {1}; размер: {2}; путь: {3}" -f `
$Category,
$UserName,
(Format-Size $SizeBefore),
$Path
)
$ErrorsBefore = $Script:ErrorCount
$Items = Get-ChildItem `
-LiteralPath $Path `
-Force `
-ErrorAction SilentlyContinue
foreach ($Item in $Items) {
try {
Remove-Item `
-LiteralPath $Item.FullName `
-Recurse `
-Force `
-ErrorAction Stop
}
catch {
$Script:ErrorCount++
Write-Log (
"Не удалось удалить: {0}; ошибка: {1}" -f `
$Item.FullName,
$_.Exception.Message
)
}
}
$SizeAfter = Get-PathSize -Path $Path
$Freed = $SizeBefore - $SizeAfter
if ($Freed -lt 0) {
$Freed = 0
}
$Script:RemovedBytes += $Freed
Write-Log (
"Результат: {0}; освобождено: {1}; осталось: {2}; ошибок: {3}" -f `
$Category,
(Format-Size $Freed),
(Format-Size $SizeAfter),
($Script:ErrorCount - $ErrorsBefore)
)
}
function Clear-OldFiles {
param(
[string]$ProfilePath,
[string]$UserName,
[string]$Category,
[string]$Path,
[int]$OlderThanDays
)
if (-not (Test-Path -LiteralPath $Path)) {
return
}
$Limit = (Get-Date).AddDays(-$OlderThanDays)
$Files = @(
Get-ChildItem `
-LiteralPath $Path `
-File `
-Force `
-Recurse `
-ErrorAction SilentlyContinue |
Where-Object {
$_.LastWriteTime -lt $Limit
}
)
if ($Files.Count -eq 0) {
return
}
$SizeBefore = (
$Files |
Measure-Object `
-Property Length `
-Sum
).Sum
if (-not $SizeBefore) {
$SizeBefore = 0L
}
Write-Log (
"Очистка: {0}; пользователь: {1}; старше: {2} дней; размер: {3}" -f `
$Category,
$UserName,
$OlderThanDays,
(Format-Size $SizeBefore)
)
$Removed = 0L
foreach ($File in $Files) {
try {
$Length = [long]$File.Length
Remove-Item `
-LiteralPath $File.FullName `
-Force `
-ErrorAction Stop
$Removed += $Length
}
catch {
$Script:ErrorCount++
Write-Log (
"Не удалось удалить: {0}; ошибка: {1}" -f `
$File.FullName,
$_.Exception.Message
)
}
}
Get-ChildItem `
-LiteralPath $Path `
-Directory `
-Force `
-Recurse `
-ErrorAction SilentlyContinue |
Sort-Object `
-Property FullName `
-Descending |
ForEach-Object {
try {
$Children = Get-ChildItem `
-LiteralPath $_.FullName `
-Force `
-ErrorAction SilentlyContinue
if (-not $Children) {
Remove-Item `
-LiteralPath $_.FullName `
-Force `
-ErrorAction SilentlyContinue
}
}
catch {
}
}
$Script:RemovedBytes += $Removed
Write-Log (
"Результат: {0}; освобождено: {1}" -f `
$Category,
(Format-Size $Removed)
)
}
function Clear-FirefoxCaches {
param(
[string]$ProfilePath,
[string]$UserName
)
$FirefoxProcesses = @(
"firefox.exe"
)
$Blockers = Get-BlockingProcesses `
-UserName $UserName `
-ProcessNames $FirefoxProcesses
if ($Blockers.Count -gt 0) {
Write-Log (
"Firefox-кэш пропущен для {0}: Firefox запущен" -f `
$UserName
)
$Script:SkippedCount++
return
}
$FirefoxRoot = Join-Path `
$ProfilePath `
"AppData\Local\Mozilla\Firefox\Profiles"
if (-not (Test-Path -LiteralPath $FirefoxRoot)) {
return
}
$FirefoxProfiles = Get-ChildItem `
-LiteralPath $FirefoxRoot `
-Directory `
-Force `
-ErrorAction SilentlyContinue
foreach ($FirefoxProfile in $FirefoxProfiles) {
foreach ($CacheName in @(
"cache2",
"startupCache",
"shader-cache",
"OfflineCache",
"thumbnails"
)) {
$CachePath = Join-Path `
$FirefoxProfile.FullName `
$CacheName
Clear-CacheContents `
-ProfilePath $ProfilePath `
-UserName $UserName `
-Category ("Firefox {0}" -f $CacheName) `
-Path $CachePath `
-BlockingProcesses @()
}
}
}
function Clear-ChromiumCaches {
param(
[string]$ProfilePath,
[string]$UserName
)
$ChromiumProcesses = @(
"chrome.exe",
"msedge.exe",
"browser.exe",
"yandex.exe",
"opera.exe"
)
$Blockers = Get-BlockingProcesses `
-UserName $UserName `
-ProcessNames $ChromiumProcesses
if ($Blockers.Count -gt 0) {
$Names = (
$Blockers |
Select-Object `
-ExpandProperty Name `
-Unique
) -join ", "
Write-Log (
"Chromium-кэши пропущены для {0}: запущены процессы {1}" -f `
$UserName,
$Names
)
$Script:SkippedCount++
return
}
$BrowserRoots = @(
(Join-Path $ProfilePath "AppData\Local\Google\Chrome\User Data"),
(Join-Path $ProfilePath "AppData\Local\Microsoft\Edge\User Data"),
(Join-Path $ProfilePath "AppData\Local\Yandex\YandexBrowser\User Data")
)
foreach ($BrowserRoot in $BrowserRoots) {
if (-not (Test-Path -LiteralPath $BrowserRoot)) {
continue
}
$BrowserProfiles = Get-ChildItem `
-LiteralPath $BrowserRoot `
-Directory `
-Force `
-ErrorAction SilentlyContinue |
Where-Object {
$_.Name -eq "Default" -or
$_.Name -like "Profile *"
}
foreach ($BrowserProfile in $BrowserProfiles) {
foreach ($CacheName in @(
"Cache",
"Code Cache",
"GPUCache",
"DawnCache",
"GrShaderCache",
"ShaderCache"
)) {
$CachePath = Join-Path `
$BrowserProfile.FullName `
$CacheName
Clear-CacheContents `
-ProfilePath $ProfilePath `
-UserName $UserName `
-Category ("Chromium {0}" -f $CacheName) `
-Path $CachePath `
-BlockingProcesses @()
}
}
}
}
$IsAdmin = (
New-Object Security.Principal.WindowsPrincipal(
[Security.Principal.WindowsIdentity]::GetCurrent()
)
).IsInRole(
[Security.Principal.WindowsBuiltInRole]::Administrator
)
if (-not $IsAdmin) {
Write-Host ""
Write-Host "PowerShell необходимо запустить от имени администратора." `
-ForegroundColor Red
Write-Host ""
return
}
$Before = Get-CDriveInfo
$Script:RemovedBytes = 0L
$Script:ErrorCount = 0
$Script:SkippedCount = 0
Write-Log "============================================================"
Write-Log "ОЧИСТКА КЭШЕЙ ВСЕХ ПОЛЬЗОВАТЕЛЕЙ"
Write-Log "============================================================"
Write-Log (
"До очистки: свободно {0} GB из {1} GB, {2}%" -f `
$Before.FreeGB,
$Before.SizeGB,
$Before.FreePct
)
Write-Log ""
Write-Log "Получение процессов и их владельцев..."
$Script:OwnedProcesses = foreach (
$Process in Get-WmiObject -Class Win32_Process
) {
try {
$Owner = $Process.GetOwner()
if ($Owner.ReturnValue -eq 0) {
[pscustomobject]@{
User = $Owner.User
Domain = $Owner.Domain
Name = $Process.Name
ProcessId = $Process.ProcessId
}
}
}
catch {
}
}
Write-Log (
"Получено процессов: {0}" -f `
@($Script:OwnedProcesses).Count
)
$Profiles = Get-WmiObject `
-Class Win32_UserProfile |
Where-Object {
-not $_.Special -and
$_.LocalPath -like "C:\Users\*" -and
(Test-Path -LiteralPath $_.LocalPath)
} |
Sort-Object `
-Property LocalPath
Write-Log (
"Найдено пользовательских профилей: {0}" -f `
@($Profiles).Count
)
$PythonRustProcesses = @(
"python.exe",
"pythonw.exe",
"pip.exe",
"pip3.exe",
"uv.exe",
"cargo.exe",
"rustc.exe",
"rustup.exe",
"rustup-init.exe",
"maturin.exe"
)
$NodeProcesses = @(
"node.exe",
"npm.exe",
"npm.cmd",
"npx.exe",
"npx.cmd"
)
$JavaProcesses = @(
"java.exe",
"javaw.exe",
"soapui.exe"
)
$RdpProcesses = @(
"mstsc.exe"
)
foreach ($Profile in $Profiles) {
$ProfilePath = $Profile.LocalPath
$UserName = Get-ProfileUserName `
-SID $Profile.SID `
-ProfilePath $ProfilePath
Write-Log ""
Write-Log "------------------------------------------------------------"
Write-Log (
"Профиль: {0}; пользователь: {1}; загружен: {2}" -f `
$ProfilePath,
$UserName,
$Profile.Loaded
)
Clear-OldFiles `
-ProfilePath $ProfilePath `
-UserName $UserName `
-Category "TEMP" `
-Path (Join-Path $ProfilePath "AppData\Local\Temp") `
-OlderThanDays 14
Clear-OldFiles `
-ProfilePath $ProfilePath `
-UserName $UserName `
-Category "CrashDumps" `
-Path (Join-Path $ProfilePath "AppData\Local\CrashDumps") `
-OlderThanDays 7
Clear-CacheContents `
-ProfilePath $ProfilePath `
-UserName $UserName `
-Category "puccinialin" `
-Path (Join-Path $ProfilePath "AppData\Local\puccinialin") `
-BlockingProcesses $PythonRustProcesses
Clear-CacheContents `
-ProfilePath $ProfilePath `
-UserName $UserName `
-Category "pip cache" `
-Path (Join-Path $ProfilePath "AppData\Local\pip\cache") `
-BlockingProcesses $PythonRustProcesses
Clear-CacheContents `
-ProfilePath $ProfilePath `
-UserName $UserName `
-Category "npm cache" `
-Path (Join-Path $ProfilePath "AppData\Local\npm-cache") `
-BlockingProcesses $NodeProcesses
Clear-CacheContents `
-ProfilePath $ProfilePath `
-UserName $UserName `
-Category "OpenJFX cache" `
-Path (Join-Path $ProfilePath ".openjfx\cache") `
-BlockingProcesses $JavaProcesses
Clear-CacheContents `
-ProfilePath $ProfilePath `
-UserName $UserName `
-Category "RDP bitmap cache" `
-Path (
Join-Path `
$ProfilePath `
"AppData\Local\Microsoft\Terminal Server Client\Cache"
) `
-BlockingProcesses $RdpProcesses
Clear-FirefoxCaches `
-ProfilePath $ProfilePath `
-UserName $UserName
Clear-ChromiumCaches `
-ProfilePath $ProfilePath `
-UserName $UserName
}
$After = Get-CDriveInfo
$FreedOnDisk = [math]::Round(
$After.FreeGB - $Before.FreeGB,
2
)
Write-Log ""
Write-Log "============================================================"
Write-Log "ОЧИСТКА ЗАВЕРШЕНА"
Write-Log "============================================================"
Write-Log (
"До очистки свободно: {0} GB" -f `
$Before.FreeGB
)
Write-Log (
"После очистки свободно: {0} GB" -f `
$After.FreeGB
)
Write-Log (
"Освобождено по диску: {0} GB" -f `
$FreedOnDisk
)
Write-Log (
"Удалено файлов кэша: {0}" -f `
(Format-Size $Script:RemovedBytes)
)
Write-Log (
"Пропущено операций из-за работающих приложений: {0}" -f `
$Script:SkippedCount
)
Write-Log (
"Ошибок удаления: {0}" -f `
$Script:ErrorCount
)
Write-Log (
"Свободно сейчас: {0}%" -f `
$After.FreePct
)
Write-Log (
"Лог: {0}" -f `
$Log
)
Write-Host ""
Write-Host "============================================================"
Write-Host "СОСТОЯНИЕ ДИСКА C:"
Write-Host "============================================================"
Write-Host ""
Get-CDriveInfo |
Format-List
Write-Host "Лог: $Log" -ForegroundColor Cyan