戰(zhàn))
1. 為什么 2024 年了還在跟 .NET Framework 3.5 死磕如果你手上有一臺(tái)剛裝好的 Windows 10 或者 Windows 11興沖沖地準(zhǔn)備裝某個(gè)行業(yè)軟件、老版 CAD 插件、財(cái)務(wù)客戶端、金蝶用友的某個(gè)模塊結(jié)果安裝程序彈出一句“需要 .NET Framework 3.5包括 .NET 2.0 和 3.0”然后系統(tǒng)自帶的在線安裝轉(zhuǎn)了半天進(jìn)度條最后報(bào) 0x800F0906 或者 0x800F081F這事兒就算正式開(kāi)始了。Windows 10/11 離線安裝 .NET Framework 3.5看著像是個(gè)上古話題實(shí)際上到今天依然是運(yùn)維、裝機(jī)、企業(yè) IT 桌面支持最常被問(wèn)到的操作之一尤其是內(nèi)網(wǎng)機(jī)器、生產(chǎn)車(chē)間電腦、隔離網(wǎng)絡(luò)里的工控終端根本連不上 Windows Update。這篇文章我打算把這塊徹底講透。適合看的人包括企業(yè) IT 運(yùn)維、給客戶裝機(jī)的技術(shù)支持、經(jīng)常折騰開(kāi)發(fā)環(huán)境的人、以及被某個(gè)軟件逼著裝 3.5 的普通用戶。核心內(nèi)容圍繞三件事展開(kāi)——為什么在線裝不上、離線包的源從哪里來(lái)、DISM 到底該怎么敲。我會(huì)把每一步的參數(shù)含義、報(bào)錯(cuò)代碼的根因、鏡像版本對(duì)不上的坑還有我自己踩過(guò)的幾次翻車(chē)經(jīng)歷都寫(xiě)進(jìn)去。讀完你應(yīng)該能做到手里只有一個(gè) Windows ISO在沒(méi)有外網(wǎng)的環(huán)境下把 .NET 3.5 穩(wěn)穩(wěn)裝上。先說(shuō)一個(gè)容易混淆的概念。.NET Framework 3.5 不是一個(gè)單獨(dú)的東西它是個(gè)“疊加包”——里面包含了 2.0、3.0 和 3.5 三個(gè)世代的運(yùn)行時(shí)還有一堆 WCF、WF、LINQ 相關(guān)的程序集。Windows 10 和 Windows 11 的內(nèi)核里其實(shí)一直保留著這套運(yùn)行時(shí)的按需功能Feature on Demand簡(jiǎn)稱 FoD文件放在系統(tǒng)鏡像的sources\sxs目錄里只是默認(rèn)不激活。所以離線安裝的本質(zhì)不是“下載安裝包”而是“告訴系統(tǒng)去本地找那堆已經(jīng)躺在鏡像里的組件把它們注冊(cè)進(jìn)系統(tǒng)”。想通這一點(diǎn)后面所有命令就好理解了。1.1 到底哪些軟件還在依賴它很多人以為 3.5 早就該淘汰了實(shí)際上依賴它的東西比想象中多。我整理了一下這幾年實(shí)際遇到的場(chǎng)景大概分這么幾類(lèi)。第一類(lèi)是行業(yè)專(zhuān)用軟件。制造業(yè)的 MES 客戶端、老版本的 SolidWorks 和 AutoCAD 插件、某些數(shù)控機(jī)床的配套上位機(jī)軟件這些軟件的開(kāi)發(fā)年代集中在 2008 到 2014 年底層就是 .NET 2.0/3.5 寫(xiě)的。廠商早就停止更新了但設(shè)備還在跑你就得給它把環(huán)境配齊。第二類(lèi)是財(cái)務(wù)和 ERP 客戶端。不少國(guó)內(nèi)財(cái)務(wù)軟件的舊版本、報(bào)表工具、稅務(wù)申報(bào)客戶端安裝時(shí)明確檢查 .NET 3.5 是否存在缺了就直接拒絕安裝。第三類(lèi)是某些開(kāi)發(fā)工具和歷史項(xiàng)目。Visual Studio 的老版本項(xiàng)目、用 ASP.NET WebForms 寫(xiě)的遺留系統(tǒng)、還有一些基于 WPF 3.5 的內(nèi)部工具。第四類(lèi)比較隱蔽——某些驅(qū)動(dòng)安裝程序、打印機(jī)工具、甚至部分游戲的啟動(dòng)器會(huì)在后臺(tái)靜默依賴 3.5 的組件缺了之后表現(xiàn)為莫名其妙的崩潰日志里才看得到FileNotFoundException: System.Web。所以判斷標(biāo)準(zhǔn)很簡(jiǎn)單只要安裝程序明確提示要 3.5或者你查事件日志看到加載mscorlib 2.0.0.0失敗那就是它。1.2 Windows 8 之后系統(tǒng)為什么默認(rèn)不裝從 Windows 8 開(kāi)始微軟把 .NET 3.5 從“默認(rèn)安裝”改成了“按需功能”。原因有兩個(gè)層面。技術(shù)上的原因是體積和依賴。3.5 這套運(yùn)行時(shí)的完整文件大概幾百 MB而且它和 .NET 4.x 是并行的兩套 CLR互不替代。微軟希望新軟件都遷移到 4.x所以把 3.5 做成可選用得到再裝。分發(fā)上的原因是安全更新。默認(rèn)不啟用意味著不需要為它持續(xù)打補(bǔ)丁減少了系統(tǒng)的攻擊面。問(wèn)題就出在這個(gè)“按需”的取件方式上。Windows 默認(rèn)的策略是去 Windows Update 上拉取 FoD 包。這就導(dǎo)致了兩個(gè)致命場(chǎng)景一是機(jī)器沒(méi)有外網(wǎng)或者被防火墻攔了 Windows Update 域名直接超時(shí)或者報(bào)錯(cuò)二是企業(yè)內(nèi)網(wǎng)有 WSUS 服務(wù)器但 WSUS 沒(méi)有同步 FoD 內(nèi)容客戶端會(huì)傻乎乎地去找 WSUS 要然后拿到 0x800F0954。這兩種情況在我們實(shí)際運(yùn)維里占了絕大多數(shù)。1.3 在線安裝為什么會(huì)失敗先把在線安裝的兩種方式擺出來(lái)方便你對(duì)照自己的情況。第一種是圖形界面控制面板 → 程序和功能 → 啟用或關(guān)閉 Windows 功能 → 勾選“.NET Framework 3.5包括 .NET 2.0 和 3.0”。這個(gè)操作背后其實(shí)調(diào)用的也是 DISM只是套了個(gè)殼。第二種是命令行DISM /Online /Enable-Feature /FeatureName:NetFx3 /All。兩者失敗的原因高度一致我列個(gè)對(duì)照表你自己對(duì)號(hào)入座。報(bào)錯(cuò)代碼觸發(fā)條件本質(zhì)原因0x800F0906無(wú)外網(wǎng)直連 Windows Update找不到下載源DNS 或連接超時(shí)0x800F081F指定了錯(cuò)誤的本地源路徑源目錄里沒(méi)有匹配版本的 sxs 文件0x800F0954域環(huán)境走 WSUSWSUS 未同步 FoD 內(nèi)容或策略強(qiáng)制只從 WSUS 取0x800F0907組策略限制“指定可選組件安裝和組件修復(fù)的設(shè)置”被配置為禁用0x800F0922磁盤(pán)空間不足或組件存儲(chǔ)損壞系統(tǒng)分區(qū)預(yù)留空間不夠或 WinSxS 異??辞宄@張表后面的操作就有了方向要么給系統(tǒng)一個(gè)靠譜的本地源要么把攔路的策略改掉。2. 離線安裝的三條路線和選型邏輯離線裝 3.5 不是只有一種方法我把它歸納成三條路線。每條路線的原理、優(yōu)劣、適用場(chǎng)景都不一樣選錯(cuò)了會(huì)在某個(gè)環(huán)節(jié)卡半天。2.1 官方源路線DISM 搭配 ISO 里的 sxs 目錄這是最正統(tǒng)的做法。你手上有和當(dāng)前系統(tǒng)版本號(hào)、語(yǔ)言、架構(gòu)三者完全一致的 Windows ISO掛載之后把sources\sxs目錄作為源傳給 DISM。DISM /Online /Enable-Feature /FeatureName:NetFx3 /All /Source:D:\sources\sxs /LimitAccess參數(shù)逐個(gè)解釋/Online表示操作當(dāng)前運(yùn)行的系統(tǒng)/Enable-Feature是啟用功能/FeatureName:NetFx3指定功能名/All表示把該功能的父功能也一并啟用/Source:后面跟本地源路徑/LimitAccess是關(guān)鍵它告訴 DISM不要回頭去找 Windows Update只用本地源。這條路線最大的優(yōu)點(diǎn)是干凈、官方、可復(fù)現(xiàn)。缺點(diǎn)也明顯你必須有匹配的 ISO。這里說(shuō)的匹配不只是“都是 Windows 10”而是要精確到內(nèi)部版本號(hào)和語(yǔ)言。用 Windows 10 21H2 的 ISO 給一臺(tái) 22H2 的機(jī)器裝很大概率報(bào) 0x800F081F。2.2 本地緩存路線從已裝好的同版本機(jī)器復(fù)制如果你手上有另一臺(tái)完全相同版本、已經(jīng)裝好 3.5 的機(jī)器可以把它C:\Windows\WinSxS里相關(guān)的組件目錄拷出來(lái)當(dāng)作源。這個(gè)方法在應(yīng)急時(shí)很好使但我不太推薦作為常規(guī)手段原因是 WinSxS 里的文件是有硬鏈接和權(quán)限保護(hù)的直接拷容易拷不全而且不同補(bǔ)丁級(jí)別的機(jī)器文件版本會(huì)有細(xì)微差異。比較穩(wěn)妥的做法是用dism /online /cleanup-image /analyzecomponentstore之類(lèi)的手段確認(rèn)或者更干脆地直接在已裝好的機(jī)器上用Export-WindowsDriver的思路導(dǎo)出——不過(guò)這個(gè)操作復(fù)雜度高應(yīng)急價(jià)值大于日常價(jià)值。真要跨機(jī)器復(fù)用我更傾向下面第三條路。2.3 部署包路線獨(dú)立 CAB 文件微軟在 FoD 的 ISO 里其實(shí)單獨(dú)提供了 CAB 包命名大致是Microsoft-Windows-NetFx3-OnDemand-Package~31bf3856ad364e35~amd64~~.cab這種格式。你可以直接對(duì) CAB 執(zhí)行安裝。DISM /Online /Add-Package /PackagePath:C:\packages\Microsoft-Windows-NetFx3-OnDemand-Package.cab這條路線適合做標(biāo)準(zhǔn)化分發(fā)——把 CAB 提取出來(lái)放進(jìn)你的軟件分發(fā)庫(kù)配合 SCCM 或者自研的部署腳本一臺(tái)臺(tái)推下去。缺點(diǎn)同樣是包必須和系統(tǒng)版本嚴(yán)格匹配且部分系統(tǒng)上 CAB 安裝后還需要補(bǔ)一次/Enable-Feature才能真正激活。2.4 三條路線的對(duì)比和我的選型建議維度ISO sxs 路線本機(jī)緩存路線CAB 包路線成功率高版本匹配時(shí)中高版本匹配時(shí)版本要求嚴(yán)格匹配嚴(yán)格匹配嚴(yán)格匹配可腳本化好差最好適合場(chǎng)景單機(jī)、現(xiàn)場(chǎng)裝機(jī)應(yīng)急批量部署我的推薦度首選備選批量時(shí)首選我個(gè)人的經(jīng)驗(yàn)是單臺(tái)機(jī)器現(xiàn)場(chǎng)處理用 ISO sxs 路線最省心如果是給一個(gè)部門(mén)幾十臺(tái)機(jī)器統(tǒng)一處理就提前把 CAB 包和腳本準(zhǔn)備好走軟件分發(fā)。緩存路線只在“手上實(shí)在沒(méi)有 ISO但旁邊有一臺(tái)好機(jī)器”的極端情況下用。3. 動(dòng)手前的準(zhǔn)備工作鏡像、權(quán)限、校驗(yàn)?zāi)サ恫徽`砍柴工。這一步做扎實(shí)后面能省掉大量排查時(shí)間。3.1 找到匹配版本的 Windows 鏡像先確認(rèn)目標(biāo)機(jī)器的準(zhǔn)確版本。打開(kāi)“運(yùn)行”輸入winver你會(huì)看到類(lèi)似“版本 22H2OS 內(nèi)部版本 22621.3155”的信息。這里要抓兩個(gè)東西版本號(hào)22H2和內(nèi)部版本號(hào)22621。然后去獲取對(duì)應(yīng)的 ISO。企業(yè)環(huán)境里通常從微軟的批量許可服務(wù)中心VLSC下載或者用 Media Creation Tool 生成。個(gè)人用戶可以走微軟官網(wǎng)的下載頁(yè)面。拿到 ISO 之后右鍵“屬性”確認(rèn)真實(shí)性別用來(lái)源不明的鏡像。提示內(nèi)部版本號(hào)的前五位是關(guān)鍵。22621 和 22631 雖然是同一代 Windows 11但嚴(yán)格來(lái)說(shuō) sxs 內(nèi)容會(huì)有差異盡量找內(nèi)部版本號(hào)一致的。3.2 校驗(yàn)鏡像的語(yǔ)言和版本一致性被忽略最多的就是語(yǔ)言。中文系統(tǒng)的機(jī)器配英文 ISOsxs 里的組件語(yǔ)言標(biāo)記對(duì)不上一樣報(bào) 0x800F081F。確認(rèn)方法ISO 里sources\sxs目錄下的文件夾名會(huì)帶語(yǔ)言代碼中文版通常是zh-cn英文版是en-us。另一個(gè)容易翻車(chē)的是版本類(lèi)型。Windows 10 家庭版、專(zhuān)業(yè)版、企業(yè)版的 sxs 內(nèi)容在大部分情況下是通用的但從 LTSC 版本拿來(lái)的 ISO 給普通版本用或者反過(guò)來(lái)偶爾會(huì)出現(xiàn)組件清單對(duì)不上的情況。我的建議是盡量找同 SKU、同語(yǔ)言、同內(nèi)部版本的 ISO。3.3 掛載 ISO 并定位 sxs 目錄掛載很簡(jiǎn)單雙擊 ISO 文件Windows 會(huì)自動(dòng)掛載成一個(gè)虛擬光驅(qū)盤(pán)符比如D:。然后確認(rèn) sxs 目錄存在dir D:\sources\sxs正常的話你會(huì)看到一堆.cab文件還有幾個(gè).mum清單文件。如果這個(gè)目錄不存在或者為空說(shuō)明你拿到的鏡像不完整——尤其是從某些渠道拿到的“精簡(jiǎn)版”鏡像sxs 目錄經(jīng)常被刪掉。這種情況直接換鏡像別浪費(fèi)時(shí)間。另外一個(gè)技巧如果不想掛載 ISO可以用wimlib或者 DISM 從install.wim里把內(nèi)容掛出來(lái)。不過(guò)對(duì)于 3.5 這個(gè)需求掛 ISO 已經(jīng)足夠沒(méi)必要繞遠(yuǎn)路。3.4 權(quán)限與執(zhí)行環(huán)境的坑DISM 操作需要管理員權(quán)限。普通的 CMD 窗口敲下去會(huì)報(bào)“錯(cuò)誤 740請(qǐng)求的操作需要提升”這種情況右鍵 CMD 選“以管理員身份運(yùn)行”即可。還有一個(gè)坑很多人栽過(guò)在 32 位進(jìn)程里調(diào)用 DISM。如果你是從某個(gè)安裝程序內(nèi)部觸發(fā)的或者用了一個(gè) 32 位的終端工具DISM 會(huì)去找SysWOW64下的版本可能行為不一致。穩(wěn)妥的做法是直接用系統(tǒng)自帶的cmd.exe在管理員模式下執(zhí)行。最后確認(rèn)系統(tǒng)分區(qū)至少有 3~5 GB 的可用空間。3.5 裝完之后 WinSxS 會(huì)膨脹空間不夠會(huì)直接報(bào) 0x800F0922。4. 命令行實(shí)操DISM 安裝全流程到這一步假設(shè)你已經(jīng)掛好了 ISO管理員 CMD 也開(kāi)好了。下面按步驟走。4.1 標(biāo)準(zhǔn)流程與參數(shù)逐條拆解先執(zhí)行這條命令DISM /Online /Enable-Feature /FeatureName:NetFx3 /All /Source:D:\sources\sxs /LimitAccess執(zhí)行后你會(huì)看到進(jìn)度條正常的話最后輸出操作成功完成。這里我把參數(shù)再拆細(xì)一點(diǎn)因?yàn)楹芏嗳藦?fù)制命令時(shí)不理解為什么這么寫(xiě)。/Online—— 針對(duì)正在運(yùn)行的操作系統(tǒng)。如果是在 WinPE 或者離線鏡像上操作就要改成/Image:加掛載路徑。這是兩碼事別搞混。/All—— 3.5 在功能樹(shù)里是個(gè)有父節(jié)點(diǎn)的拓?fù)浣Y(jié)構(gòu)/All保證父功能比如 .NET 2.0/3.0 的支撐功能一起啟用。少了它裝完之后可能某些老程序還是報(bào)錯(cuò)。/Source:D:\sources\sxs—— 這里有個(gè)細(xì)節(jié)。路徑必須是sxs這一級(jí)而不是它的上級(jí)sources。DISM 會(huì)在你給的目錄里遞歸查找清單但給的層級(jí)不對(duì)會(huì)直接判失敗。/LimitAccess—— 加了這個(gè)參數(shù)DISM 就會(huì)“死心”只用本地源不會(huì)因?yàn)楸镜厝绷四硯讉€(gè)文件就偷偷連網(wǎng)。在斷網(wǎng)環(huán)境下加不加都一樣但在半聯(lián)網(wǎng)環(huán)境下這個(gè)參數(shù)能保證行為可預(yù)測(cè)。4.2 用 install.wim 直接當(dāng)源的高級(jí)玩法如果你手里沒(méi)有 ISO但有一個(gè)install.wim文件比如從 WDS 或者 MDT 的部署共享里拿到的也能當(dāng)源用只是要先掛載出來(lái)。mkdir C:\wim_mount DISM /Mount-Image /ImageFile:D:\sources\install.wim /Index:1 /MountDir:C:\wim_mount /ReadOnly DISM /Online /Enable-Feature /FeatureName:NetFx3 /All /Source:C:\wim_mount\sources\sxs /LimitAccess DISM /Unmount-Image /MountDir:C:\wim_mount /Discard這里的/Index:1要選對(duì)。一個(gè) install.wim 里可能有家庭版、專(zhuān)業(yè)版、企業(yè)版多個(gè)索引你要選和目標(biāo)機(jī)器 SKU 對(duì)應(yīng)的那個(gè)??梢韵扰蹹ISM /Get-WimInfo /WimFile:D:\sources\install.wim看清單。/ReadOnly掛載是個(gè)好習(xí)慣避免誤改到鏡像。卸載時(shí)用/Discard保證不改動(dòng)原 WIM。這個(gè)玩法的好處是不需要虛擬光驅(qū)適合在服務(wù)器上批處理壞處是步驟多掛載和卸載都要時(shí)間。4.3 批量部署時(shí)的腳本封裝給多臺(tái)機(jī)器處理我一般寫(xiě)成這樣一段批處理放在共享目錄里推下去執(zhí)行echo off setlocal set SRC\\fileserver\deploy\win11_22h2\sources\sxs ver | findstr /i 10\. nul if %errorlevel%0 ( echo 檢測(cè)到 Windows 10/11 ) dism /online /get-featureinfo /featurename:NetFx3 | findstr /i 狀態(tài): 已啟用 nul if %errorlevel%0 ( echo NetFx3 已啟用跳過(guò) goto :end ) dism /online /enable-feature /featurename:NetFx3 /all /source:%SRC% /limitaccess if %errorlevel% neq 0 ( echo 安裝失敗錯(cuò)誤碼 %errorlevel% exit /b %errorlevel% ) echo 安裝完成 :end endlocal注意里面做了冪等檢查——先用get-featureinfo判斷是不是已經(jīng)啟用避免重復(fù)裝導(dǎo)致無(wú)謂的等待。共享路徑\\fileserver\...需要執(zhí)行賬戶有讀取權(quán)限域環(huán)境里通常用計(jì)算機(jī)賬戶或者一個(gè)有權(quán)限的服務(wù)賬戶跑。腳本里我沒(méi)加語(yǔ)言判斷和版本校驗(yàn)因?yàn)閷?shí)際部署時(shí)這些應(yīng)該在前置環(huán)節(jié)就保證。如果你要做得更嚴(yán)可以在腳本開(kāi)頭用wmic os get version比對(duì)內(nèi)部版本號(hào)。4.4 安裝完成后的驗(yàn)證方法裝完不要只看 DISM 輸出“操作成功完成”就完事要實(shí)際驗(yàn)證。第一層驗(yàn)證查功能狀態(tài)DISM /Online /Get-FeatureInfo /FeatureName:NetFx3輸出里“狀態(tài)”應(yīng)該是“已啟用”。第二層驗(yàn)證查注冊(cè)表reg query HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5 /v InstallInstall值應(yīng)該是0x1。第三層驗(yàn)證實(shí)際跑一下老程序。最直接的辦法是打開(kāi) PowerShell 之外的 CMD輸入%SystemRoot%\Microsoft.NET\Framework\v2.0.50727\csc.exe如果沒(méi)報(bào)“找不到文件”而是彈出版本信息說(shuō)明 2.0 的編譯器已經(jīng)在位了。三層都過(guò)了才算真正裝好。5. 組策略與 WSUS 環(huán)境下的特殊處理這一節(jié)專(zhuān)門(mén)給企業(yè)域環(huán)境。前面說(shuō)過(guò)域機(jī)器報(bào) 0x800F0954 的概率極高根因就在組策略。5.1 0x800F0954 的根因組策略里有這么一條路徑計(jì)算機(jī)配置 → 管理模板 → 系統(tǒng) → 指定可選組件安裝和組件修復(fù)的設(shè)置英文路徑是Computer Configuration → Administrative Templates → System → Specify settings for optional component installation and component repair如果這條策略被設(shè)成“已啟用”并且勾了“僅從 Windows Server Update Services (WSUS) 下載修復(fù)內(nèi)容”那客戶端的 DISM 就會(huì)強(qiáng)制走 WSUS。WSUS 默認(rèn)不同步 FoD 的Microsoft-Windows-NetFx3-OnDemand-Package這類(lèi)包于是客戶端請(qǐng)求不到報(bào) 0x800F0954。還有一種情況是策略沒(méi)啟用這項(xiàng)但環(huán)境里有 WSUS 且客戶端已經(jīng)通過(guò)wuauclt注冊(cè)過(guò)DISM 仍然會(huì)優(yōu)先問(wèn) WSUS。5.2 臨時(shí)修改策略的正確姿勢(shì)注意我說(shuō)的是“臨時(shí)”。生產(chǎn)環(huán)境中不該為了裝一個(gè)組件就把全局策略改掉。正確的做法是在目標(biāo)機(jī)器上臨時(shí)加一條覆蓋性注冊(cè)表裝完刪掉。策略對(duì)應(yīng)的注冊(cè)表鍵是HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU相關(guān)值包括UseWUServer。把這個(gè)值臨時(shí)設(shè)為0然后重啟 Windows Update 服務(wù)再執(zhí)行 DISM 命令裝完把值改回去。具體操作reg add HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU /v UseWUServer /t REG_DWORD /d 0 /f net stop wuauserv net start wuauserv裝完恢復(fù)reg add HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU /v UseWUServer /t REG_DWORD /d 1 /f net stop wuauserv net start wuauserv注意這個(gè)方法在大部分域環(huán)境有效但如果你的組策略是每 90 分鐘刷新一次臨時(shí)改的注冊(cè)表可能在你操作期間被刷回。穩(wěn)妥做法是操作間隔盡量短或者和域管理員協(xié)調(diào)在維護(hù)窗口做。5.3 企業(yè)域環(huán)境下的取舍從長(zhǎng)期來(lái)看域環(huán)境更優(yōu)雅的方案有兩個(gè)。一是讓 WSUS 管理員啟用“功能和語(yǔ)言包”的同步。在 WSUS 控制臺(tái)的“選項(xiàng) → 產(chǎn)品和分類(lèi)”里勾上“Windows 10, version 1903 and later”以及對(duì)應(yīng)的“功能和語(yǔ)言包”分類(lèi)FoD 內(nèi)容就會(huì)同步到 WSUS客戶端走正常通道即可裝 3.5。這個(gè)方案一次配置長(zhǎng)期受益代價(jià)是 WSUS 存儲(chǔ)會(huì)漲不少。二是走“旁加載”路線。把 sxs 目錄或者 CAB 包放到內(nèi)網(wǎng)文件服務(wù)器用組策略登錄腳本統(tǒng)一檢測(cè)安裝。這就是我前面 4.3 節(jié)的腳本思路只是把它掛到組策略的計(jì)算機(jī)啟動(dòng)腳本上。我個(gè)人的取舍機(jī)器數(shù)量少10 臺(tái)以內(nèi)現(xiàn)場(chǎng)手動(dòng)處理幾十臺(tái)以上推動(dòng) WSUS 同步上百臺(tái)上腳本分發(fā)。6. 常見(jiàn)報(bào)錯(cuò)速查與排查實(shí)錄這一節(jié)是這篇文章的干貨分量最重的部分。我把這幾年實(shí)際處理過(guò)的典型問(wèn)題整理出來(lái)。6.1 錯(cuò)誤代碼對(duì)照與定位路徑報(bào)錯(cuò)代碼優(yōu)先排查方向快速修復(fù)動(dòng)作0x800F0906網(wǎng)絡(luò)、Windows Update 服務(wù)加/LimitAccess和本地源0x800F081F源路徑、鏡像版本、語(yǔ)言匹配換匹配的 ISO確認(rèn) sxs 有內(nèi)容0x800F0954WSUS、組策略臨時(shí)改UseWUServer0x800F0907組策略“指定可選組件安裝”設(shè)置檢查策略是否配置為禁用0x800F0922磁盤(pán)空間、組件存儲(chǔ)清理 WinSxS或擴(kuò)容0x80073712組件存儲(chǔ)損壞先跑DISM /Online /Cleanup-Image /RestoreHealth0x80070005權(quán)限不足用管理員 CMD6.2 幾個(gè)真實(shí)案例的排查過(guò)程案例一Windows 11 專(zhuān)業(yè)版 Insider Preview 29667.1000 無(wú)法安裝 .NET Framework 3.5 SP1這個(gè)場(chǎng)景挺典型。用戶裝的是 Insider Preview 的某個(gè)預(yù)發(fā)布版本機(jī)器聯(lián)網(wǎng)但拿不到匹配的 FoD 包。原因有兩個(gè)一是 Insider 版本的 FoD 內(nèi)容在 Windows Update 上分發(fā)是滯后的很多時(shí)候預(yù)覽版剛發(fā)布時(shí)對(duì)應(yīng)的按需包還沒(méi)上線二是用戶手上沒(méi)有和 29667 這個(gè)內(nèi)部版本匹配的 ISO。我的處理思路是先確認(rèn)是不是版本匹配問(wèn)題用winver看內(nèi)部版本再去 Windows Update 上跑一次完整更新如果還是不行說(shuō)明 FoD 通道沒(méi)放內(nèi)容這時(shí)候要么退回穩(wěn)定版要么用上一代穩(wěn)定版的 sxs 試著裝成功概率一般屬于“碰運(yùn)氣”。結(jié)論是Insider Preview 的機(jī)器不建議作為依賴 3.5 的生產(chǎn)設(shè)備這個(gè)坑先天存在。案例二x86 老機(jī)器裝 .NET 2.0~3.5 全量包有臺(tái) Windows 10 1909 的 32 位機(jī)器客戶要求 2.0、3.0、3.5 全裝。注意這里一個(gè)細(xì)節(jié)Windows 10/11 上的 NetFx3 功能其實(shí)同時(shí)覆蓋了 2.0、3.0、3.5 三個(gè)世代不需要單獨(dú)裝 2.0。客戶以為要裝三個(gè)包實(shí)際一條命令就夠了。另外 x86 機(jī)器的 sxs 目錄和 x64 不同鏡像必須是對(duì)應(yīng)架構(gòu)的。用 64 位 ISO 的 sxs 給 32 位機(jī)器裝DISM 會(huì)報(bào)找不到匹配的包。案例三裝完 NetFx3 但程序仍報(bào)錯(cuò)一個(gè)客戶的 ASP.NET 老系統(tǒng)裝完 3.5 之后IIS 里跑起來(lái)還是 500。排查發(fā)現(xiàn)是IIS 的應(yīng)用程序池沒(méi)有配置為 .NET CLR v2.0。3.5 的運(yùn)行時(shí)在 IIS 里對(duì)應(yīng)的是 v2.0 的應(yīng)用池默認(rèn)新版本 IIS 都建 v4.0 的池需要手動(dòng)改。這個(gè)坑很多人遇到因?yàn)樗粚儆凇鞍惭b”問(wèn)題而是“配置”問(wèn)題。6.3 一套可復(fù)用的排查思路我總結(jié)成四步遇到任何報(bào)錯(cuò)按這個(gè)順序過(guò)。第一步看錯(cuò)誤碼對(duì)照 6.1 的表定位大類(lèi)。第二步確認(rèn)源的三要素版本、語(yǔ)言、架構(gòu)是否和目標(biāo)機(jī)器一致。三項(xiàng)里任意一項(xiàng)不對(duì)先換源再說(shuō)。第三步檢查環(huán)境干擾是不是域機(jī)器、是不是有 WSUS、是不是有組策略限制、磁盤(pán)空間夠不夠。第四步如果前面都對(duì)還是不行跑組件存儲(chǔ)修復(fù)DISM /Online /Cleanup-Image /RestoreHealth sfc /scannow然后再重試安裝。實(shí)操心得我遇到過(guò)一次 0x800F081F所有人都說(shuō)是鏡像版本問(wèn)題換個(gè) ISO 還是報(bào)。最后發(fā)現(xiàn)是sxs目錄在拷貝到本地磁盤(pán)時(shí)被某個(gè)殺毒軟件攔截了部分.cab文件。所以如果你的源是從共享盤(pán)或者移動(dòng)硬盤(pán)拷過(guò)來(lái)的用dir /s數(shù)一下文件數(shù)量和原始 ISO 里對(duì)比一下。7. 幾個(gè)容易被忽略的細(xì)節(jié)和我的實(shí)操心得前面講了主線流程這一節(jié)說(shuō)說(shuō)那些“文檔里不寫(xiě)、但真正干活時(shí)會(huì)遇到”的東西。7.1 語(yǔ)言包和系統(tǒng)區(qū)域的隱性影響有一類(lèi)特別隱晦的問(wèn)題系統(tǒng)語(yǔ)言是中文ISO 也是中文但 sxs 裝不進(jìn)去。最后查出來(lái)是系統(tǒng)的區(qū)域設(shè)置被改成了別的地區(qū)同時(shí)“非 Unicode 程序的語(yǔ)言”被改成了英文。這種情況下 DISM 會(huì)認(rèn)為語(yǔ)言環(huán)境不匹配。處理方式控制面板 → 區(qū)域 → 管理 → 非 Unicode 程序的語(yǔ)言改回中文簡(jiǎn)體中國(guó)重啟后再裝。這個(gè)坑我遇到兩次每次都要找半天。7.2 關(guān)于“精簡(jiǎn)版系統(tǒng)”的現(xiàn)實(shí)提醒市面上流傳的一些“優(yōu)化版”“純凈版”Windows 鏡像為了壓縮體積會(huì)把sxs目錄、WinSxS緩存甚至整個(gè) FoD 組件刪掉。這種系統(tǒng)上你無(wú)論怎么操作都裝不上 3.5因?yàn)樵丛谙到y(tǒng)內(nèi)部就已經(jīng)不存在了。判斷方法DISM /Online /Get-FeatureInfo /FeatureName:NetFx3如果狀態(tài)顯示“已禁用”但顯示“刪除狀態(tài)已刪除”那就是被移除了。這種情況即使你指定外部源也可能失敗因?yàn)槿鄙俚氖窍到y(tǒng)內(nèi)部的清單。遇到這種機(jī)器我的建議是不要試圖搶救直接重裝一個(gè)完整版系統(tǒng)。浪費(fèi)時(shí)間不如換盤(pán)。7.3 ARM64 和特殊架構(gòu)的處理Windows on ARM 的設(shè)備比如某些驍龍本裝 3.5 時(shí)sxs 目錄的架構(gòu)是arm64。用 x64 的 ISO 裝不了。同時(shí)部分 x86 應(yīng)用在 ARM64 的 Windows 上需要 x86 的模擬層支持2.0/3.5 的運(yùn)行時(shí)也需要對(duì)應(yīng)架構(gòu)的版本。這類(lèi)設(shè)備目前在企業(yè)里不多但如果在處理先確認(rèn)PROCESSOR_ARCHITECTURE環(huán)境變量的值echo %PROCESSOR_ARCHITECTURE%返回ARM64就一定要找 ARM64 的 ISO。7.4 裝完之后別急著走這幾件事順手做掉第一重啟一次。雖然 DISM 不強(qiáng)制要求重啟但 3.5 的部分組件注冊(cè)在下次啟動(dòng)時(shí)才真正生效。我遇到過(guò)一次不重啟導(dǎo)致 CAD 插件加載失敗重啟后就好了。第二檢查 Windows Update 有沒(méi)有把 3.5 的安全補(bǔ)丁帶上。裝完 NetFx3 之后系統(tǒng)會(huì)多出幾個(gè)針對(duì) 2.0/3.5 的更新項(xiàng)如果機(jī)器能聯(lián)網(wǎng)讓它自己打完更穩(wěn)妥。第三如果這臺(tái)機(jī)器要做備份或者克隆現(xiàn)在就是做鏡像的最佳時(shí)機(jī)。裝好 3.5 的狀態(tài)是很多老軟件的“基線環(huán)境”克隆一份后面遇到新機(jī)器直接還原比每次重裝省事太多。第四記錄下你用的 ISO 版本號(hào)和文件名。半年后你在另一臺(tái)機(jī)器上遇到同樣的問(wèn)題翻出這個(gè)記錄直接復(fù)用不用再摸索一遍。我在團(tuán)隊(duì)里維護(hù)了一個(gè)小表格記錄每臺(tái)裝過(guò) 3.5 的機(jī)器對(duì)應(yīng)哪個(gè) ISO長(zhǎng)期下來(lái)省了很多重復(fù)勞動(dòng)。最后分享一個(gè)我自己常用的應(yīng)急思路。如果現(xiàn)場(chǎng)實(shí)在找不到任何匹配的 ISO而機(jī)器又不是完全斷網(wǎng)可以試試先臨時(shí)允許 Windows Update 幾分鐘讓系統(tǒng)自己把 FoD 拉下來(lái)裝完再斷開(kāi)。這個(gè)方法不違規(guī)也不依賴外部工具代價(jià)是需要網(wǎng)絡(luò)窗口適合作為最后的兜底方案。但如果是嚴(yán)格隔離的內(nèi)網(wǎng)機(jī)器還是老老實(shí)實(shí)準(zhǔn)備 ISO 和 CAB 包把源掌握在自己手里這才是最可控的做法。