Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學

Win10 C 槽 WinSxS 資料夾能不能刪?DISM 查真實大小 + 批次腳本清理舊版本元件

編輯:Windows 10 系統介紹

C:\Windows\WinSxS(元件存放區)隨時間增大佔用大量空間,實為硬連結指向 System32,資源管理員顯示大小虛高。用 Dism.exe /Online /Cleanup-Image /AnalyzeComponentStore 查真實大小,再用批次腳本掃描刪除舊版本元件(保留最新版),安全釋放空間。

查看 WinSxS 真實大小

  1. 管理員 CMD 執行:
    Dism.exe /Online /Cleanup-Image /AnalyzeComponentStore
  2. 輸出「實際大小」遠低於總大小,差異為硬連結共享空間。

批次腳本清理舊版元件(進階)

將下列腳本存為 clean_winsxs.bat 以管理員執行,會:
• 掃描 WinSxS 所有元件資料夾(命名格式:類型_名稱_版本_語言_簽章)
• 比較版本號,僅保留最新版本,其餘移至 C:\Windows\winsxs_del 備份
• 記錄 %TEMP%\winsxs-clear.log

@echo off
set mxms=a
if not "!mxms!" == "a" set mxms=&&%comspec% /V:ON /C %0 %* && goto :EOF
set mxms=
rem 演算法描述: 掃描 winsxs 目錄, 刪除舊版本元件資料夾
set startT=%TIME%
set move_dir=%SystemRoot%\winsxs_del
if not exist %move_dir%\nul md %move_dir%
set log=%temp%\winsxs-clear.log
pushd "%SystemRoot%\winsxs"
echo ===================== start TE% %TIME% ============================ >> "%log%"
FOR /F "eol=; tokens=1-4 delims= " %%a in ('dir /ad /o-n %SystemRoot%\winsxs\*.*') do (
 if "%%c" == "<DIR>" if exist "%SystemRoot%\winsxs\%%d" call:fnDoClear %%d
)
echo ===================== OK! TE% %TIME% ============================ >> "%log%"
echo clear OK!
echo from %startT% to %TIME%. Check your '%move_dir%' please.
echo view log from %log%
set startT=
set move_dir=
popd
goto :EOF
:fnDoClear
rem arg: dir_name
rem 分解目錄名
FOR /F "eol=; tokens=1-14 delims=_" %%g in ("%1") do (
 call:fnSplitName %1
 if not "%f_type%" == "" call:fnDoClearDir %1 !f_type! !f_name! !f_id! !f_rev! !f_lang! !f_sign!
)
goto :EOF
:fnSplitName
rem arg: dir_name
rem return f_xxx vars
set f_type=
set f_name=
set f_id=
set f_rev=
set f_lang=
set f_sign=
FOR /F "eol=; tokens=1-14 delims=_" %%g in ("%1") do (
 if "%%m" == "" (
  set f_type=%%g
  set f_name=%%h
  set f_id=%%i
  set f_rev=%%j
  set f_lang=%%k
  set f_sign=%%l
 ) else ( if "%%n" == "" (
  set f_type=%%g
  set f_name=%%h_%%i
  set f_id=%%j
  set f_rev=%%k
  set f_lang=%%l
  set f_sign=%%m
 ) else ( if "%%o" == "" (
  set f_type=%%g
  set f_name=%%h_%%i_%%j
  set f_id=%%k
  set f_rev=%%l
  set f_lang=%%m
  set f_sign=%%n
 ) else ( if "%%p" == "" (
  set f_type=%%g
  set f_name=%%h_%%i_%%j_%%k
  set f_id=%%l
  set f_rev=%%m
  set f_lang=%%n
  set f_sign=%%o
 ) else ( if "%%q" == "" (
  set f_type=%%g
  set f_name=%%h_%%i_%%j_%%k_%%l
  set f_id=%%m
  set f_rev=%%n
  set f_lang=%%o
  set f_sign=%%p
 ) else ( if "%%r" == "" (
  set f_type=%%g
  set f_name=%%h_%%i_%%j_%%k_%%l_%%m
  set f_id=%%n
  set f_rev=%%o
  set f_lang=%%p
  set f_sign=%%q
 ) else ( if "%%s" == "" (
  set f_type=%%g
  set f_name=%%h_%%i_%%j_%%k_%%l_%%m_%%n
  set f_id=%%o
  set f_rev=%%p
  set f_lang=%%q
  set f_sign=%%r
 ) else ( if "%%t" == "" (
  set f_type=%%g
  set f_name=%%h_%%i_%%j_%%k_%%l_%%m_%%n_%%o
  set f_id=%%p
  set f_rev=%%q
  set f_lang=%%r
  set f_sign=%%s
 ) else ( if "%%u" == "" (
  set f_type=%%g
  set f_name=%%h_%%i_%%j_%%k_%%l_%%m_%%n_%%o_%%p
  set f_id=%%q
  set f_rev=%%r
  set f_lang=%%s
  set f_sign=%%t
 ) else ( if "%%v" == "" (
  set f_type=%%g
  set f_name=%%h_%%i_%%j_%%k_%%l_%%m_%%n_%%o_%%p_%%q
  set f_id=%%r
  set f_rev=%%s
  set f_lang=%%t
  set f_sign=%%u
 ) else (
  echo ERROR: can not split "%1"
 )))))))))))
)
)
goto :EOF
:fnDoClearDir
rem arg: dir_name type namespace id revision lang sign
rem 找到最新版本的目錄名
call:fnStdVer %5
set curorgver=%5
set curver=%R_STDVER%
set cursign=%7
set R_STDVER=
set newver=
set neworgver=
set newsign=
FOR /F "eol=; tokens=1-4 delims= " %%a in ('dir /ad /o-n %2_%3_%4_*_%6_*') do (
 if "%%c" == "<DIR>" (
  call:fnSplitName %%d
  if not "!f_type!" == "" call:fnCompVer "!newver!" !f_rev! !f_sign!
 )
)
rem 如果沒找到則返回
if "%newver%" == "" goto :EOF
rem 如果找到,則將所有舊版本的清除
echo keep %2_%3_%4 %6 version %neworgver%
echo keep %2_%3_%4 %6 version %neworgver% >> "%log%"
FOR /F "eol=; tokens=1-4 delims= " %%a in ('dir /ad /o-n %2_%3_%4_*_%6_*') do (
 if "%%%c" == "<DIR>" (
  call:fnSplitName %%d
  if not "!f_type!" == "" (
   if not "!neworgver!" == "!f_rev!" if not "!newsign!" == "!f_sign!" (
    echo ... clear %2_%3_%4 %6 version !f_rev!
    echo ... clear %2_%3_%4 %6 version !f_rev! >> "%log%"
    call:fnDelDir "%%d"
   )
  )
 )
)
goto :EOF
:fnCompVer
rem oldver newver newsign
rem result set var newver
rem 分解ver的每一個部分,左側填充0之後再比較
set V1=%~1
call:fnStdVer %2
set V2=%R_STDVER%
set R_STDVER=
if "%~1" == "" set neworgver=%2&&set newver=%V2%&&set newsign=%3&& goto :EOF
if /I "%V1%" LSS "%V2%" set neworgver=%2&&set newver=%V2%&&set newsign=%3&& goto :EOF
goto :EOF
:fnStdVer
rem arg: ver
FOR /F "eol=; tokens=1-10 delims=." %%v in ("%1") do call:fnStdVerImpl %%v %%w %%x %%y %%z
goto :EOF
:fnStdVerImpl
rem major, minor, revision, build
rem result set in R_STDVER
set svi_1=0000000000%1
set svi_2=0000000000%2
set svi_3=0000000000%3
set svi_4=0000000000%4
set svi_5=0000000000%5
set svi_6=0000000000%6
set R_STDVER=%svi_1:~-10%.%svi_2:~-10%.%svi_3:~-10%.%svi_4:~-10%.%svi_5:~-10%.%svi_6:~-10%
goto :EOF
:fnDelDir
rem arg: dir
echo deleting %SystemRoot%\winsxs\%~1 >> "%log%"
echo --- takeown >> "%log%"
takeown /r /f "%SystemRoot%\winsxs\%~1" >> "%log%"
echo --- takeown = %ERRORLEVEL% >> "%log%"
echo --- cacls >> "%log%"
cacls "%SystemRoot%\winsxs\%~1" /t /e /g everyone:f >> "%log%"
echo --- cacls = %ERRORLEVEL% >> "%log%"
echo --- move >> "%log%"
move "%SystemRoot%\winsxs\%~1" "%move_dir%\%~1" >> "%log%"
echo --- move = %ERRORLEVEL% >> "%log%"
goto :EOF

官方建議替代方案(更安全):
Dism.exe /Online /Cleanup-Image /StartComponentCleanup(移除已取代元件)
Dism.exe /Online /Cleanup-Image /StartComponentCleanup /ResetBase(將最新版本設為基準,無法回溯更新)
執行前請備份重要資料,若出現「拒絕存取」代表權限不足,需以 TrustedInstaller/NT AUTHORITY\SYSTEM 權限執行(可用 psexec -s -i cmd)。

Copyright © Windows教程網 All Rights Reserved