ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Win10/11 离线安装 .NET 3.5:DISM 与 sxs 实战

Win10/11 离线安装 .NET 3.5:DISM 与 sxs 实战 1. 为什么 2024 年了还在跟 .NET Framework 3.5 死磕如果你手上有一台刚装好的 Windows 10 或者 Windows 11兴冲冲地准备装某个行业软件、老版 CAD 插件、财务客户端、金蝶用友的某个模块结果安装程序弹出一句“需要 .NET Framework 3.5包括 .NET 2.0 和 3.0”然后系统自带的在线安装转了半天进度条最后报 0x800F0906 或者 0x800F081F这事儿就算正式开始了。Windows 10/11 离线安装 .NET Framework 3.5看着像是个上古话题实际上到今天依然是运维、装机、企业 IT 桌面支持最常被问到的操作之一尤其是内网机器、生产车间电脑、隔离网络里的工控终端根本连不上 Windows Update。这篇文章我打算把这块彻底讲透。适合看的人包括企业 IT 运维、给客户装机的技术支持、经常折腾开发环境的人、以及被某个软件逼着装 3.5 的普通用户。核心内容围绕三件事展开——为什么在线装不上、离线包的源从哪里来、DISM 到底该怎么敲。我会把每一步的参数含义、报错代码的根因、镜像版本对不上的坑还有我自己踩过的几次翻车经历都写进去。读完你应该能做到手里只有一个 Windows ISO在没有外网的环境下把 .NET 3.5 稳稳装上。先说一个容易混淆的概念。.NET Framework 3.5 不是一个单独的东西它是个“叠加包”——里面包含了 2.0、3.0 和 3.5 三个世代的运行时还有一堆 WCF、WF、LINQ 相关的程序集。Windows 10 和 Windows 11 的内核里其实一直保留着这套运行时的按需功能Feature on Demand简称 FoD文件放在系统镜像的sources\sxs目录里只是默认不激活。所以离线安装的本质不是“下载安装包”而是“告诉系统去本地找那堆已经躺在镜像里的组件把它们注册进系统”。想通这一点后面所有命令就好理解了。1.1 到底哪些软件还在依赖它很多人以为 3.5 早就该淘汰了实际上依赖它的东西比想象中多。我整理了一下这几年实际遇到的场景大概分这么几类。第一类是行业专用软件。制造业的 MES 客户端、老版本的 SolidWorks 和 AutoCAD 插件、某些数控机床的配套上位机软件这些软件的开发年代集中在 2008 到 2014 年底层就是 .NET 2.0/3.5 写的。厂商早就停止更新了但设备还在跑你就得给它把环境配齐。第二类是财务和 ERP 客户端。不少国内财务软件的旧版本、报表工具、税务申报客户端安装时明确检查 .NET 3.5 是否存在缺了就直接拒绝安装。第三类是某些开发工具和历史项目。Visual Studio 的老版本项目、用 ASP.NET WebForms 写的遗留系统、还有一些基于 WPF 3.5 的内部工具。第四类比较隐蔽——某些驱动安装程序、打印机工具、甚至部分游戏的启动器会在后台静默依赖 3.5 的组件缺了之后表现为莫名其妙的崩溃日志里才看得到FileNotFoundException: System.Web。所以判断标准很简单只要安装程序明确提示要 3.5或者你查事件日志看到加载mscorlib 2.0.0.0失败那就是它。1.2 Windows 8 之后系统为什么默认不装从 Windows 8 开始微软把 .NET 3.5 从“默认安装”改成了“按需功能”。原因有两个层面。技术上的原因是体积和依赖。3.5 这套运行时的完整文件大概几百 MB而且它和 .NET 4.x 是并行的两套 CLR互不替代。微软希望新软件都迁移到 4.x所以把 3.5 做成可选用得到再装。分发上的原因是安全更新。默认不启用意味着不需要为它持续打补丁减少了系统的攻击面。问题就出在这个“按需”的取件方式上。Windows 默认的策略是去 Windows Update 上拉取 FoD 包。这就导致了两个致命场景一是机器没有外网或者被防火墙拦了 Windows Update 域名直接超时或者报错二是企业内网有 WSUS 服务器但 WSUS 没有同步 FoD 内容客户端会傻乎乎地去找 WSUS 要然后拿到 0x800F0954。这两种情况在我们实际运维里占了绝大多数。1.3 在线安装为什么会失败先把在线安装的两种方式摆出来方便你对照自己的情况。第一种是图形界面控制面板 → 程序和功能 → 启用或关闭 Windows 功能 → 勾选“.NET Framework 3.5包括 .NET 2.0 和 3.0”。这个操作背后其实调用的也是 DISM只是套了个壳。第二种是命令行DISM /Online /Enable-Feature /FeatureName:NetFx3 /All。两者失败的原因高度一致我列个对照表你自己对号入座。报错代码触发条件本质原因0x800F0906无外网直连 Windows Update找不到下载源DNS 或连接超时0x800F081F指定了错误的本地源路径源目录里没有匹配版本的 sxs 文件0x800F0954域环境走 WSUSWSUS 未同步 FoD 内容或策略强制只从 WSUS 取0x800F0907组策略限制“指定可选组件安装和组件修复的设置”被配置为禁用0x800F0922磁盘空间不足或组件存储损坏系统分区预留空间不够或 WinSxS 异常看清楚这张表后面的操作就有了方向要么给系统一个靠谱的本地源要么把拦路的策略改掉。2. 离线安装的三条路线和选型逻辑离线装 3.5 不是只有一种方法我把它归纳成三条路线。每条路线的原理、优劣、适用场景都不一样选错了会在某个环节卡半天。2.1 官方源路线DISM 搭配 ISO 里的 sxs 目录这是最正统的做法。你手上有和当前系统版本号、语言、架构三者完全一致的 Windows ISO挂载之后把sources\sxs目录作为源传给 DISM。DISM /Online /Enable-Feature /FeatureName:NetFx3 /All /Source:D:\sources\sxs /LimitAccess参数逐个解释/Online表示操作当前运行的系统/Enable-Feature是启用功能/FeatureName:NetFx3指定功能名/All表示把该功能的父功能也一并启用/Source:后面跟本地源路径/LimitAccess是关键它告诉 DISM不要回头去找 Windows Update只用本地源。这条路线最大的优点是干净、官方、可复现。缺点也明显你必须有匹配的 ISO。这里说的匹配不只是“都是 Windows 10”而是要精确到内部版本号和语言。用 Windows 10 21H2 的 ISO 给一台 22H2 的机器装很大概率报 0x800F081F。2.2 本地缓存路线从已装好的同版本机器复制如果你手上有另一台完全相同版本、已经装好 3.5 的机器可以把它C:\Windows\WinSxS里相关的组件目录拷出来当作源。这个方法在应急时很好使但我不太推荐作为常规手段原因是 WinSxS 里的文件是有硬链接和权限保护的直接拷容易拷不全而且不同补丁级别的机器文件版本会有细微差异。比较稳妥的做法是用dism /online /cleanup-image /analyzecomponentstore之类的手段确认或者更干脆地直接在已装好的机器上用Export-WindowsDriver的思路导出——不过这个操作复杂度高应急价值大于日常价值。真要跨机器复用我更倾向下面第三条路。2.3 部署包路线独立 CAB 文件微软在 FoD 的 ISO 里其实单独提供了 CAB 包命名大致是Microsoft-Windows-NetFx3-OnDemand-Package~31bf3856ad364e35~amd64~~.cab这种格式。你可以直接对 CAB 执行安装。DISM /Online /Add-Package /PackagePath:C:\packages\Microsoft-Windows-NetFx3-OnDemand-Package.cab这条路线适合做标准化分发——把 CAB 提取出来放进你的软件分发库配合 SCCM 或者自研的部署脚本一台台推下去。缺点同样是包必须和系统版本严格匹配且部分系统上 CAB 安装后还需要补一次/Enable-Feature才能真正激活。2.4 三条路线的对比和我的选型建议维度ISO sxs 路线本机缓存路线CAB 包路线成功率高版本匹配时中高版本匹配时版本要求严格匹配严格匹配严格匹配可脚本化好差最好适合场景单机、现场装机应急批量部署我的推荐度首选备选批量时首选我个人的经验是单台机器现场处理用 ISO sxs 路线最省心如果是给一个部门几十台机器统一处理就提前把 CAB 包和脚本准备好走软件分发。缓存路线只在“手上实在没有 ISO但旁边有一台好机器”的极端情况下用。3. 动手前的准备工作镜像、权限、校验磨刀不误砍柴工。这一步做扎实后面能省掉大量排查时间。3.1 找到匹配版本的 Windows 镜像先确认目标机器的准确版本。打开“运行”输入winver你会看到类似“版本 22H2OS 内部版本 22621.3155”的信息。这里要抓两个东西版本号22H2和内部版本号22621。然后去获取对应的 ISO。企业环境里通常从微软的批量许可服务中心VLSC下载或者用 Media Creation Tool 生成。个人用户可以走微软官网的下载页面。拿到 ISO 之后右键“属性”确认真实性别用来源不明的镜像。提示内部版本号的前五位是关键。22621 和 22631 虽然是同一代 Windows 11但严格来说 sxs 内容会有差异尽量找内部版本号一致的。3.2 校验镜像的语言和版本一致性被忽略最多的就是语言。中文系统的机器配英文 ISOsxs 里的组件语言标记对不上一样报 0x800F081F。确认方法ISO 里sources\sxs目录下的文件夹名会带语言代码中文版通常是zh-cn英文版是en-us。另一个容易翻车的是版本类型。Windows 10 家庭版、专业版、企业版的 sxs 内容在大部分情况下是通用的但从 LTSC 版本拿来的 ISO 给普通版本用或者反过来偶尔会出现组件清单对不上的情况。我的建议是尽量找同 SKU、同语言、同内部版本的 ISO。3.3 挂载 ISO 并定位 sxs 目录挂载很简单双击 ISO 文件Windows 会自动挂载成一个虚拟光驱盘符比如D:。然后确认 sxs 目录存在dir D:\sources\sxs正常的话你会看到一堆.cab文件还有几个.mum清单文件。如果这个目录不存在或者为空说明你拿到的镜像不完整——尤其是从某些渠道拿到的“精简版”镜像sxs 目录经常被删掉。这种情况直接换镜像别浪费时间。另外一个技巧如果不想挂载 ISO可以用wimlib或者 DISM 从install.wim里把内容挂出来。不过对于 3.5 这个需求挂 ISO 已经足够没必要绕远路。3.4 权限与执行环境的坑DISM 操作需要管理员权限。普通的 CMD 窗口敲下去会报“错误 740请求的操作需要提升”这种情况右键 CMD 选“以管理员身份运行”即可。还有一个坑很多人栽过在 32 位进程里调用 DISM。如果你是从某个安装程序内部触发的或者用了一个 32 位的终端工具DISM 会去找SysWOW64下的版本可能行为不一致。稳妥的做法是直接用系统自带的cmd.exe在管理员模式下执行。最后确认系统分区至少有 3~5 GB 的可用空间。3.5 装完之后 WinSxS 会膨胀空间不够会直接报 0x800F0922。4. 命令行实操DISM 安装全流程到这一步假设你已经挂好了 ISO管理员 CMD 也开好了。下面按步骤走。4.1 标准流程与参数逐条拆解先执行这条命令DISM /Online /Enable-Feature /FeatureName:NetFx3 /All /Source:D:\sources\sxs /LimitAccess执行后你会看到进度条正常的话最后输出操作成功完成。这里我把参数再拆细一点因为很多人复制命令时不理解为什么这么写。/Online—— 针对正在运行的操作系统。如果是在 WinPE 或者离线镜像上操作就要改成/Image:加挂载路径。这是两码事别搞混。/All—— 3.5 在功能树里是个有父节点的拓扑结构/All保证父功能比如 .NET 2.0/3.0 的支撑功能一起启用。少了它装完之后可能某些老程序还是报错。/Source:D:\sources\sxs—— 这里有个细节。路径必须是sxs这一级而不是它的上级sources。DISM 会在你给的目录里递归查找清单但给的层级不对会直接判失败。/LimitAccess—— 加了这个参数DISM 就会“死心”只用本地源不会因为本地缺了某几个文件就偷偷连网。在断网环境下加不加都一样但在半联网环境下这个参数能保证行为可预测。4.2 用 install.wim 直接当源的高级玩法如果你手里没有 ISO但有一个install.wim文件比如从 WDS 或者 MDT 的部署共享里拿到的也能当源用只是要先挂载出来。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要选对。一个 install.wim 里可能有家庭版、专业版、企业版多个索引你要选和目标机器 SKU 对应的那个。可以先跑DISM /Get-WimInfo /WimFile:D:\sources\install.wim看清单。/ReadOnly挂载是个好习惯避免误改到镜像。卸载时用/Discard保证不改动原 WIM。这个玩法的好处是不需要虚拟光驱适合在服务器上批处理坏处是步骤多挂载和卸载都要时间。4.3 批量部署时的脚本封装给多台机器处理我一般写成这样一段批处理放在共享目录里推下去执行echo off setlocal set SRC\\fileserver\deploy\win11_22h2\sources\sxs ver | findstr /i 10\. nul if %errorlevel%0 ( echo 检测到 Windows 10/11 ) dism /online /get-featureinfo /featurename:NetFx3 | findstr /i 状态: 已启用 nul if %errorlevel%0 ( echo NetFx3 已启用跳过 goto :end ) dism /online /enable-feature /featurename:NetFx3 /all /source:%SRC% /limitaccess if %errorlevel% neq 0 ( echo 安装失败错误码 %errorlevel% exit /b %errorlevel% ) echo 安装完成 :end endlocal注意里面做了幂等检查——先用get-featureinfo判断是不是已经启用避免重复装导致无谓的等待。共享路径\\fileserver\...需要执行账户有读取权限域环境里通常用计算机账户或者一个有权限的服务账户跑。脚本里我没加语言判断和版本校验因为实际部署时这些应该在前置环节就保证。如果你要做得更严可以在脚本开头用wmic os get version比对内部版本号。4.4 安装完成后的验证方法装完不要只看 DISM 输出“操作成功完成”就完事要实际验证。第一层验证查功能状态DISM /Online /Get-FeatureInfo /FeatureName:NetFx3输出里“状态”应该是“已启用”。第二层验证查注册表reg query HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5 /v InstallInstall值应该是0x1。第三层验证实际跑一下老程序。最直接的办法是打开 PowerShell 之外的 CMD输入%SystemRoot%\Microsoft.NET\Framework\v2.0.50727\csc.exe如果没报“找不到文件”而是弹出版本信息说明 2.0 的编译器已经在位了。三层都过了才算真正装好。5. 组策略与 WSUS 环境下的特殊处理这一节专门给企业域环境。前面说过域机器报 0x800F0954 的概率极高根因就在组策略。5.1 0x800F0954 的根因组策略里有这么一条路径计算机配置 → 管理模板 → 系统 → 指定可选组件安装和组件修复的设置英文路径是Computer Configuration → Administrative Templates → System → Specify settings for optional component installation and component repair如果这条策略被设成“已启用”并且勾了“仅从 Windows Server Update Services (WSUS) 下载修复内容”那客户端的 DISM 就会强制走 WSUS。WSUS 默认不同步 FoD 的Microsoft-Windows-NetFx3-OnDemand-Package这类包于是客户端请求不到报 0x800F0954。还有一种情况是策略没启用这项但环境里有 WSUS 且客户端已经通过wuauclt注册过DISM 仍然会优先问 WSUS。5.2 临时修改策略的正确姿势注意我说的是“临时”。生产环境中不该为了装一个组件就把全局策略改掉。正确的做法是在目标机器上临时加一条覆盖性注册表装完删掉。策略对应的注册表键是HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU相关值包括UseWUServer。把这个值临时设为0然后重启 Windows Update 服务再执行 DISM 命令装完把值改回去。具体操作reg add HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU /v UseWUServer /t REG_DWORD /d 0 /f net stop wuauserv net start wuauserv装完恢复reg add HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU /v UseWUServer /t REG_DWORD /d 1 /f net stop wuauserv net start wuauserv注意这个方法在大部分域环境有效但如果你的组策略是每 90 分钟刷新一次临时改的注册表可能在你操作期间被刷回。稳妥做法是操作间隔尽量短或者和域管理员协调在维护窗口做。5.3 企业域环境下的取舍从长期来看域环境更优雅的方案有两个。一是让 WSUS 管理员启用“功能和语言包”的同步。在 WSUS 控制台的“选项 → 产品和分类”里勾上“Windows 10, version 1903 and later”以及对应的“功能和语言包”分类FoD 内容就会同步到 WSUS客户端走正常通道即可装 3.5。这个方案一次配置长期受益代价是 WSUS 存储会涨不少。二是走“旁加载”路线。把 sxs 目录或者 CAB 包放到内网文件服务器用组策略登录脚本统一检测安装。这就是我前面 4.3 节的脚本思路只是把它挂到组策略的计算机启动脚本上。我个人的取舍机器数量少10 台以内现场手动处理几十台以上推动 WSUS 同步上百台上脚本分发。6. 常见报错速查与排查实录这一节是这篇文章的干货分量最重的部分。我把这几年实际处理过的典型问题整理出来。6.1 错误代码对照与定位路径报错代码优先排查方向快速修复动作0x800F0906网络、Windows Update 服务加/LimitAccess和本地源0x800F081F源路径、镜像版本、语言匹配换匹配的 ISO确认 sxs 有内容0x800F0954WSUS、组策略临时改UseWUServer0x800F0907组策略“指定可选组件安装”设置检查策略是否配置为禁用0x800F0922磁盘空间、组件存储清理 WinSxS或扩容0x80073712组件存储损坏先跑DISM /Online /Cleanup-Image /RestoreHealth0x80070005权限不足用管理员 CMD6.2 几个真实案例的排查过程案例一Windows 11 专业版 Insider Preview 29667.1000 无法安装 .NET Framework 3.5 SP1这个场景挺典型。用户装的是 Insider Preview 的某个预发布版本机器联网但拿不到匹配的 FoD 包。原因有两个一是 Insider 版本的 FoD 内容在 Windows Update 上分发是滞后的很多时候预览版刚发布时对应的按需包还没上线二是用户手上没有和 29667 这个内部版本匹配的 ISO。我的处理思路是先确认是不是版本匹配问题用winver看内部版本再去 Windows Update 上跑一次完整更新如果还是不行说明 FoD 通道没放内容这时候要么退回稳定版要么用上一代稳定版的 sxs 试着装成功概率一般属于“碰运气”。结论是Insider Preview 的机器不建议作为依赖 3.5 的生产设备这个坑先天存在。案例二x86 老机器装 .NET 2.0~3.5 全量包有台 Windows 10 1909 的 32 位机器客户要求 2.0、3.0、3.5 全装。注意这里一个细节Windows 10/11 上的 NetFx3 功能其实同时覆盖了 2.0、3.0、3.5 三个世代不需要单独装 2.0。客户以为要装三个包实际一条命令就够了。另外 x86 机器的 sxs 目录和 x64 不同镜像必须是对应架构的。用 64 位 ISO 的 sxs 给 32 位机器装DISM 会报找不到匹配的包。案例三装完 NetFx3 但程序仍报错一个客户的 ASP.NET 老系统装完 3.5 之后IIS 里跑起来还是 500。排查发现是IIS 的应用程序池没有配置为 .NET CLR v2.0。3.5 的运行时在 IIS 里对应的是 v2.0 的应用池默认新版本 IIS 都建 v4.0 的池需要手动改。这个坑很多人遇到因为它不属于“安装”问题而是“配置”问题。6.3 一套可复用的排查思路我总结成四步遇到任何报错按这个顺序过。第一步看错误码对照 6.1 的表定位大类。第二步确认源的三要素版本、语言、架构是否和目标机器一致。三项里任意一项不对先换源再说。第三步检查环境干扰是不是域机器、是不是有 WSUS、是不是有组策略限制、磁盘空间够不够。第四步如果前面都对还是不行跑组件存储修复DISM /Online /Cleanup-Image /RestoreHealth sfc /scannow然后再重试安装。实操心得我遇到过一次 0x800F081F所有人都说是镜像版本问题换个 ISO 还是报。最后发现是sxs目录在拷贝到本地磁盘时被某个杀毒软件拦截了部分.cab文件。所以如果你的源是从共享盘或者移动硬盘拷过来的用dir /s数一下文件数量和原始 ISO 里对比一下。7. 几个容易被忽略的细节和我的实操心得前面讲了主线流程这一节说说那些“文档里不写、但真正干活时会遇到”的东西。7.1 语言包和系统区域的隐性影响有一类特别隐晦的问题系统语言是中文ISO 也是中文但 sxs 装不进去。最后查出来是系统的区域设置被改成了别的地区同时“非 Unicode 程序的语言”被改成了英文。这种情况下 DISM 会认为语言环境不匹配。处理方式控制面板 → 区域 → 管理 → 非 Unicode 程序的语言改回中文简体中国重启后再装。这个坑我遇到两次每次都要找半天。7.2 关于“精简版系统”的现实提醒市面上流传的一些“优化版”“纯净版”Windows 镜像为了压缩体积会把sxs目录、WinSxS缓存甚至整个 FoD 组件删掉。这种系统上你无论怎么操作都装不上 3.5因为源在系统内部就已经不存在了。判断方法DISM /Online /Get-FeatureInfo /FeatureName:NetFx3如果状态显示“已禁用”但显示“删除状态已删除”那就是被移除了。这种情况即使你指定外部源也可能失败因为缺少的是系统内部的清单。遇到这种机器我的建议是不要试图抢救直接重装一个完整版系统。浪费时间不如换盘。7.3 ARM64 和特殊架构的处理Windows on ARM 的设备比如某些骁龙本装 3.5 时sxs 目录的架构是arm64。用 x64 的 ISO 装不了。同时部分 x86 应用在 ARM64 的 Windows 上需要 x86 的模拟层支持2.0/3.5 的运行时也需要对应架构的版本。这类设备目前在企业里不多但如果在处理先确认PROCESSOR_ARCHITECTURE环境变量的值echo %PROCESSOR_ARCHITECTURE%返回ARM64就一定要找 ARM64 的 ISO。7.4 装完之后别急着走这几件事顺手做掉第一重启一次。虽然 DISM 不强制要求重启但 3.5 的部分组件注册在下次启动时才真正生效。我遇到过一次不重启导致 CAD 插件加载失败重启后就好了。第二检查 Windows Update 有没有把 3.5 的安全补丁带上。装完 NetFx3 之后系统会多出几个针对 2.0/3.5 的更新项如果机器能联网让它自己打完更稳妥。第三如果这台机器要做备份或者克隆现在就是做镜像的最佳时机。装好 3.5 的状态是很多老软件的“基线环境”克隆一份后面遇到新机器直接还原比每次重装省事太多。第四记录下你用的 ISO 版本号和文件名。半年后你在另一台机器上遇到同样的问题翻出这个记录直接复用不用再摸索一遍。我在团队里维护了一个小表格记录每台装过 3.5 的机器对应哪个 ISO长期下来省了很多重复劳动。最后分享一个我自己常用的应急思路。如果现场实在找不到任何匹配的 ISO而机器又不是完全断网可以试试先临时允许 Windows Update 几分钟让系统自己把 FoD 拉下来装完再断开。这个方法不违规也不依赖外部工具代价是需要网络窗口适合作为最后的兜底方案。但如果是严格隔离的内网机器还是老老实实准备 ISO 和 CAB 包把源掌握在自己手里这才是最可控的做法。
返回列表