# ============================================================ # Docker Desktop (Windows + WSL2) -- Temizlik, Bakim & VHDX Shrink # Calistirma : Yonetici olarak PowerShell'de: # .\docker-cleanup.ps1 # .\docker-cleanup.ps1 -All (volume dahil) # .\docker-cleanup.ps1 -DryRun (sadece goster) # .\docker-cleanup.ps1 -Hours 48 (filtre saati) # NOT: VHDX shrink icin Yonetici (Administrator) yetkisi gerekir. # ============================================================ param( [switch]$All, [switch]$DryRun, [int]$Hours = 168 ) # ============================================================ # YARDIMCI FONKSIYONLAR # ============================================================ function Hr { Write-Host ("-" * 56) -ForegroundColor DarkGray } function Hr2 { Write-Host ("=" * 56) -ForegroundColor DarkGray } function Step { param($n,$t) Write-Host "`n [$n] $t" -ForegroundColor Cyan } function Info { param($t) Write-Host " -> $t" -ForegroundColor Yellow } function Ok { param($t) Write-Host " OK $t" -ForegroundColor Green } function Warn { param($t) Write-Host " !! $t" -ForegroundColor Red } function Skip { param($t) Write-Host " -- $t" -ForegroundColor DarkGray } function Blank { Write-Host "" } function Format-Bytes { 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) } return "{0:N0} KB" -f ($bytes / 1KB) } function Run-Docker { param([string]$Cmd) if ($DryRun) { Write-Host " [dry-run] docker $Cmd" -ForegroundColor DarkGray } else { $result = Invoke-Expression "docker $Cmd" 2>&1 $result | ForEach-Object { Write-Host " $_" -ForegroundColor Gray } } } function Count-Lines { param([string]$Cmd) $out = Invoke-Expression $Cmd 2>$null if (-not $out) { return 0 } return ($out | Where-Object { $_ -ne "" }).Count } # ============================================================ # ON KONTROLLER # ============================================================ # Yonetici yetkisi var mi? $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator ) # Docker calisiyor mu? $dockerOk = $false try { docker info 2>&1 | Out-Null $dockerOk = $true } catch {} # ============================================================ # BASLIK # ============================================================ Clear-Host Hr2 Write-Host " Docker Desktop - Tam Temizlik, Bakim & VHDX Shrink" -ForegroundColor White -BackgroundColor DarkBlue Write-Host " Tarih : $(Get-Date -Format 'dd.MM.yyyy HH:mm')" -ForegroundColor Gray Write-Host " Filtre : Son $Hours saat" -ForegroundColor Gray Write-Host " Yonetici : $(if ($isAdmin) { 'EVET (VHDX shrink aktif)' } else { 'HAYIR (VHDX shrink atlanacak)' })" -ForegroundColor $(if ($isAdmin) { 'Green' } else { 'Red' }) if ($DryRun) { Write-Host " MOD : DRY-RUN (hicbir sey degistirilmeyecek)" -ForegroundColor Yellow } if ($All) { Write-Host " EKSTRA : Volume temizligi aktif" -ForegroundColor Red } Hr2 if (-not $dockerOk) { Warn "Docker Desktop calisiyor degil veya erisim yok." Warn "Lutfen Docker Desktop'i acin ve tekrar calistirin." Blank Read-Host " Cikis icin Enter" exit 1 } if (-not $isAdmin) { Blank Warn "VHDX shrink icin bu scripti Yonetici olarak calistirin:" Info "PowerShell'e sag tiklayin -> 'Yonetici olarak calistir'" Info "Devam edilecek ama VHDX shrink adimi atlanacak..." Blank } # ============================================================ # ADIM 0 -- Baslangic disk durumu # ============================================================ Step "0" "Baslangic disk kullanimi (Docker)" docker system df # VHDX boyutlari $vhdxDir = "$env:LOCALAPPDATA\Docker\wsl\disk" $vhdxFiles = @() if (Test-Path $vhdxDir) { $vhdxFiles = Get-ChildItem -Path $vhdxDir -Filter "*.vhdx" -ErrorAction SilentlyContinue if ($vhdxFiles.Count -gt 0) { Blank Info "VHDX dosyalari ($vhdxDir):" foreach ($f in $vhdxFiles) { Info (" {0,-35} {1}" -f $f.Name, (Format-Bytes $f.Length)) } } } Hr # ============================================================ # ADIM 1 -- Konteyner temizligi # ============================================================ Step "1" "Durdurulmus konteynerler temizleniyor" $stoppedCount = Count-Lines "docker ps -aq --filter status=exited" $deadCount = Count-Lines "docker ps -aq --filter status=dead" $createdCount = Count-Lines "docker ps -aq --filter status=created" $total = $stoppedCount + $deadCount + $createdCount Info "Exited : $stoppedCount | Dead : $deadCount | Created : $createdCount | Toplam : $total" if ($total -gt 0) { Run-Docker "container prune --force --filter `"until=${Hours}h`"" Ok "Konteyner temizligi tamamlandi" } else { Ok "Temizlenecek konteyner yok" } # ============================================================ # ADIM 2 -- Imaj temizligi # ============================================================ Step "2" "Kullanilmayan imajlar temizleniyor" $danglingCount = Count-Lines "docker images -f dangling=true -q" Info "Dangling imaj: $danglingCount adet" Run-Docker "image prune -a --force --filter `"until=${Hours}h`"" Ok "Imaj temizligi tamamlandi" # ============================================================ # ADIM 3 -- Build cache # ============================================================ Step "3" "Build cache temizleniyor" $dfOut = docker system df 2>$null $cacheLine = $dfOut | Select-String "Build Cache" Info "Mevcut cache: $cacheLine" Run-Docker "builder prune --force --filter `"until=${Hours}h`"" Ok "Build cache temizlendi" # ============================================================ # ADIM 4 -- Ag temizligi # ============================================================ Step "4" "Kullanilmayan Docker aglari temizleniyor" Run-Docker "network prune --force" Ok "Ag temizligi tamamlandi" # ============================================================ # ADIM 5 -- Volume temizligi (opsiyonel) # ============================================================ Step "5" "Volume temizligi" if ($All) { Warn "DIKKAT: Kalici veri iceren volume'lar silinebilir!" $confirm = Read-Host " Devam? (E/H)" if ($confirm -match "^[Ee]$") { $volCount = Count-Lines "docker volume ls -f dangling=true -q" Info "Baglantisiz volume: $volCount adet" if ($volCount -gt 0) { Run-Docker "volume prune --force" Ok "Volume temizligi tamamlandi" } else { Ok "Temizlenecek volume yok" } } else { Skip "Volume temizligi kullanici tarafindan atlandi" } } else { Skip "Atlandi. Dahil etmek icin: -All parametresi" } # ============================================================ # ADIM 6 -- WSL2 kapat + VHDX Shrink # ============================================================ Step "6" "WSL2 kapatiliyor + VHDX shrink yapiliyor" if (-not $isAdmin) { Warn "Yonetici yetkisi yok -- VHDX shrink atlaniyor." Warn "Scripti 'Yonetici olarak calistir' ile tekrar deneyin." } elseif ($vhdxFiles.Count -eq 0) { Skip "VHDX dosyasi bulunamadi: $vhdxDir" } else { Info "WSL2 durduruluyor (wsl --shutdown)..." if (-not $DryRun) { wsl --shutdown Start-Sleep -Seconds 3 Ok "WSL2 durduruldu" } else { Skip "[dry-run] wsl --shutdown" } foreach ($vhdx in $vhdxFiles) { $sizeBefore = $vhdx.Length Info ("Shrink basliyor: {0} ({1})" -f $vhdx.Name, (Format-Bytes $sizeBefore)) if (-not $DryRun) { $diskpartScript = @" select vdisk file="$($vhdx.FullName)" attach vdisk readonly compact vdisk detach vdisk exit "@ $tmpScript = "$env:TEMP\docker_shrink_$($vhdx.BaseName).txt" $diskpartScript | Out-File -FilePath $tmpScript -Encoding ascii $proc = Start-Process -FilePath "diskpart.exe" ` -ArgumentList "/s `"$tmpScript`"" ` -Wait -PassThru -NoNewWindow ` -RedirectStandardOutput "$env:TEMP\diskpart_out.txt" ` -RedirectStandardError "$env:TEMP\diskpart_err.txt" Remove-Item $tmpScript -ErrorAction SilentlyContinue # Boyut degisimini goster $vhdx.Refresh() $sizeAfter = $vhdx.Length $saved = $sizeBefore - $sizeAfter if ($saved -gt 0) { Ok (" {0}: {1} -> {2} (kazanilan: {3})" -f ` $vhdx.Name, ` (Format-Bytes $sizeBefore), ` (Format-Bytes $sizeAfter), ` (Format-Bytes $saved)) } else { Ok (" {0}: Boyut degismedi (zaten optimize)" -f $vhdx.Name) } } else { Skip ("[dry-run] diskpart compact: {0}" -f $vhdx.Name) } } if (-not $DryRun) { Info "Docker Desktop yeniden baslatiliyor..." Start-Process "C:\Program Files\Docker\Docker\Docker Desktop.exe" -ErrorAction SilentlyContinue Ok "Docker Desktop baslatildi" } } # ============================================================ # ADIM 7 -- Sonuc raporu # ============================================================ Hr Step "7" "Sonuc ozeti" docker system df if ($vhdxFiles.Count -gt 0 -and $isAdmin -and -not $DryRun) { Blank Info "VHDX guncel boyutlar:" foreach ($f in $vhdxFiles) { $f.Refresh() Info (" {0,-35} {1}" -f $f.Name, (Format-Bytes $f.Length)) } } Hr2 Blank Write-Host " Temizlik ve bakim tamamlandi!" -ForegroundColor Green if ($DryRun) { Warn "(Dry-run moduydu -- hicbir degisiklik yapilmadi)" } Blank Hr2 Read-Host " Cikis icin Enter"