一鍵搞定!自動化壓縮 WSL2 虛擬磁碟,釋放大量硬碟空間

2025-07-06 09:27:45 Category Icon 系統工具

一鍵搞定!自動化壓縮 WSL2 虛擬磁碟,釋放大量硬碟空間

你的 C 槽空間是不是越來越小,檢查後發現一個名為 ext4.vhdx 的檔案佔據了幾十甚至上百 GB?如果你是 Windows Subsystem for Linux (WSL2) 的使用者,這絕對是你我共同的痛點。

WSL2 的虛擬磁碟檔案 ext4.vhdx 有個特性:它會隨著你使用而動態增長,但當你刪除 WSL 內的檔案後,它不會自動縮小。這導致磁碟空間被「名存實亡」的檔案佔據,日積月累下非常可觀。

傳統的解決方法非常繁瑣:

  1. 手動用管理員權限打開 PowerShell。
  2. 執行 wsl --shutdown
  3. 想辦法找到那個藏在 AppData 深處、路徑超長的 ext4.vhdx 檔案。
  4. 執行磁碟優化指令。
  5. 再手動啟動 WSL。

這一連串操作既麻煩又容易出錯。今天,我們就用一個終極 PowerShell 腳本,將這一切流程自動化,真正實現「一鍵瘦身」!

這個腳本有多厲害?

這個腳本整合了我們在解決問題過程中遇到的所有智慧,它能做到:

  • 自動關閉與重啟 WSL:你不需要手動執行任何 wsl 指令,腳本會處理好開頭和結尾。
  • 智慧尋找 VHDX 路徑:無論你的 WSL 是從 Microsoft Store 安裝,還是手動匯入的,腳本都能透過查詢登錄檔找到它的準確位置,你再也不用去複製那超長的路徑了。
  • 兼容 Windows 家用版與專業版:腳本會自動偵測你的 Windows 版本。如果你是專業版,它會使用 Optimize-Vhd 指令;如果你是家用版,它會自動切換到內建的 diskpart 工具來完成壓縮,適用性極高!
  • 清晰回報成果:在執行壓縮前後,腳本會顯示檔案大小,並在最後計算出總共幫你節省了多少硬碟空間,讓你對成果一目了然。

如何使用?

整個過程只需要三個簡單的步驟。

步驟一:建立腳本檔案

首先,在你的電腦上任何你方便的地方,建立一個新的文字檔案,將它命名為 Optimize-WSL.ps1。然後,將下方的完整程式碼複製並貼到這個檔案中。

# ===================================================================
#      腳本:自動化 WSL2 虛擬磁碟 (VHDX) 壓縮優化與重啟工具
#      注意:請務必以「系統管理員」權限執行此腳本
# ===================================================================

# --- 步驟 1: 設定您要優化的 WSL 發行版名稱 ---
$distroName = "Ubuntu-24.04"

# ==================== 腳本主體,通常無需修改以下內容 ====================
$vhdxPath = $null

# --- 步驟 2: 自動在登錄檔中尋找 VHDX 檔案路徑 ---
Write-Host "步驟 2/8: 正在登錄檔中尋找 '$distroName' 的設定..." -ForegroundColor Yellow
try {
    $lxssPath = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss"
    $distroKeys = Get-ChildItem -Path $lxssPath
    foreach ($distroKey in $distroKeys) {
        $properties = Get-ItemProperty -Path $distroKey.PSPath
        if ($properties.DistributionName -eq $distroName) {
            $basePath = $properties.BasePath
            $vhdxPath = Join-Path $basePath "ext4.vhdx"
            break
        }
    }
} catch {
    Write-Host "錯誤:查詢登錄檔時發生意外錯誤: $($_.Exception.Message)" -ForegroundColor Red
    Read-Host "按 Enter 鍵結束..."; exit
}

# --- 步驟 3: 驗證 VHDX 檔案路徑 ---
Write-Host ""
Write-Host "步驟 3/8: 驗證 VHDX 檔案路徑..." -ForegroundColor Yellow
if (-not (Test-Path $vhdxPath)) {
    Write-Host "錯誤:無法找到 '$distroName' 的 VHDX 檔案。" -ForegroundColor Red
    Read-Host "按 Enter 鍵結束..."; exit
}
Write-Host "已確認 VHDX 檔案路徑: $vhdxPath" -ForegroundColor Green

# --- 步驟 4: 取得壓縮前的檔案大小 ---
Write-Host ""
Write-Host "步驟 4/8: 正在取得壓縮前的檔案大小..." -ForegroundColor Yellow
$fileInfoBefore = Get-Item -Path $vhdxPath
$sizeBeforeBytes = $fileInfoBefore.Length
$sizeBeforeGB = $sizeBeforeBytes / 1GB
Write-Host "壓縮前大小: $($sizeBeforeGB.ToString("N2")) GB" -ForegroundColor Cyan

# --- 步驟 5: 關閉 WSL2 虛擬機 ---
Write-Host ""
Write-Host "步驟 5/8: 正在關閉所有 WSL2 執行個體..." -ForegroundColor Yellow
wsl.exe --shutdown
Write-Host "WSL2 已成功關閉。" -ForegroundColor Green

# --- 步驟 6: 執行 VHDX 壓縮優化 ---
Write-Host ""
Write-Host "步驟 6/8: 正在執行 VHDX 檔案壓縮優化..." -ForegroundColor Yellow

$optimizeVhdExists = Get-Command Optimize-Vhd -ErrorAction SilentlyContinue
if ($optimizeVhdExists) {
    Write-Host "偵測到 Optimize-Vhd 指令,使用 Hyper-V 模式。" -ForegroundColor Cyan
    try { Optimize-Vhd -Path $vhdxPath -Mode Full -ErrorAction Stop } catch {
        Write-Host "錯誤:VHDX 優化失敗: $($_.Exception.Message)" -ForegroundColor Red
        Read-Host "按 Enter 鍵結束..."; exit
    }
} else {
    Write-Host "未偵測到 Optimize-Vhd,切換至 diskpart 模式 (適用於 Windows 家用版)。" -ForegroundColor Cyan
    $scriptContent = @"
select vdisk file="$vhdxPath"
attach vdisk readonly
compact vdisk
detach vdisk
exit
"@
    $tempScript = "$env:TEMP\diskpart_script.txt"
    try {
        Set-Content -Path $tempScript -Value $scriptContent; diskpart /s $tempScript
    } catch {
        Write-Host "錯誤:使用 diskpart 進行 VHDX 優化時失敗: $($_.Exception.Message)" -ForegroundColor Red
        Read-Host "按 Enter 鍵結束..."; exit
    } finally {
        if (Test-Path $tempScript) { Remove-Item $tempScript }
    }
}

# --- 步驟 7: 取得壓縮後的檔案大小並回報成果 ---
Write-Host ""
Write-Host "步驟 7/8: 正在取得壓縮後的檔案大小並計算成果..." -ForegroundColor Yellow
$fileInfoAfter = Get-Item -Path $vhdxPath
$sizeAfterBytes = $fileInfoAfter.Length
$sizeAfterGB = $sizeAfterBytes / 1GB
$savedBytes = $sizeBeforeBytes - $sizeAfterBytes
$savedGB = $savedBytes / 1GB

Write-Host "壓縮後大小: $($sizeAfterGB.ToString("N2")) GB" -ForegroundColor Cyan
if ($savedBytes -gt 0) {
    Write-Host "成功節省空間: $($savedGB.ToString("N2")) GB" -ForegroundColor Green
} else {
    Write-Host "檔案大小沒有變化。" -ForegroundColor Yellow
}

# --- 步驟 8: 重新啟動 WSL ---
Write-Host ""
Write-Host "步驟 8/8: 正在重新啟動發行版 '$distroName'..." -ForegroundColor Yellow
wsl.exe -d $distroName

# --- 腳本結束 ---
Write-Host ""
Write-Host "所有流程已完成!WSL 應已在新的終端機視窗中啟動。" -ForegroundColor Green
Read-Host "按 Enter 鍵關閉此腳本視窗..."

步驟二:修改你的 WSL 發行版名稱

打開你剛剛建立的 Optimize-WSL.ps1 檔案,找到第一行的程式碼:

$distroName = "Ubuntu-24.04"

這是整個腳本唯一需要你修改的地方。請將 "Ubuntu-24.04" 替換成你自己的 WSL 發行版名稱。

不知道自己的發行版叫什麼名字?很簡單,打開 PowerShell 或 CMD,輸入 wsl -l -v,然後複製 NAME 欄位下的那個名稱,貼到腳本裡就行了。

查詢 WSL 名稱

步驟三:以系統管理員權限執行

儲存好你的腳本後,在 Optimize-WSL.ps1 檔案上按右鍵,選擇「使用 PowerShell 執行」。

第一次執行可能會遇到的問題 如果你第一次執行時出現錯誤,提示「禁止執行指令碼」,這是因為 PowerShell 的安全原則。請用系統管理員權限打開 PowerShell,執行一次 Set-ExecutionPolicy RemoteSigned,在確認視窗中輸入 Y 按下 Enter,即可一勞永逸地解決這個問題。

執行後,腳本就會開始自動化地完成所有工作,你只需要泡杯咖啡,看著它回報成果就行了!

結語

硬碟空間是開發者寶貴的資源。有了這個自動化腳本,你可以將它放在桌面或任何方便的地方,每隔一段時間就執行一次,輕鬆地為 WSL 進行維護,讓你的硬碟保持在最佳狀態。別再讓那些無用的空間佔據你的硬碟了,馬上動手試試看吧!