
简介针对 Windows Server 2012 中 .NET Framework 3.5 默认未启用、在线安装易受网络与更新源影响而失败的问题这份 SxS 镜像资源包面向系统管理员、运维人员及需运行旧版 .NET 应用的用户提供可离线启用的组件集合兼顾 .NET 3.5 安装失败排查与服务开启场景。压缩包共 1569 个文件约 101.69MB以 dll、exe、config、aspx、resx 等为主涵盖框架运行库、配置模板与安装支撑文件目录保留 Sources\sxs 结构便于通过 DISM 指定源路径完成部署。已有 10501 人学习下载说明其在旧系统兼容与内网环境部署中具有较高参考价值。使用者可据此减少对 Windows Update 的依赖在断网或防火墙受限的服务器上完成 NetFx3 功能启用并借助包内说明梳理安装路径、权限要求与常见报错处理思路适合需要稳定复现安装流程的运维场景。1. 安装 .NET 3.5 卡在 0x800F0906离线服务器上最常见的那道坎刚装完的 Windows Server 2012服务器管理器里勾上“.NET Framework 3.5 功能”进度条走到一半弹出一行红字0x800F0906提示无法从 Windows 更新下载源文件。换成 DISM 命令行再敲一遍错误码一模一样有人让你去挂个 ISO挂上去路径一填报错又变成 0x800F081F。这类 .net3.5安装失败 在内网机器、隔离机房、默认不通外网的云主机上几乎是每周都会碰到的固定节目折腾程度不亚于排查一个偶发蓝屏。这篇记录围绕 window server 2012 安装 net3.5 时用 --sxs 镜像资源包 补源这条主线把几个高频错误码拆开给出可以直接抄的命令和判断顺序适合正被 .net 3.5安装 卡住、需要尽快让业务跑起来的人。2. 报错 0x800F0906 / 0x800F081F先弄明白「按需功能」为什么不肯自己下载报错码只是结果不是原因。同一个 0x800F0906可能是机器没网可能是组策略把下载源关了也可能是你挂的镜像根本不是同一个系统版本。不把这层关系理清就会陷入「换个 ISO 再试一次」的循环试到第四次还是同样的红字。2.1 从 Windows Server 2012 起.NET 3.5 的实体文件不再随系统落地2008 R2 及更早的系统上.NET 3.5 是系统自带组件文件实打实躺在 WinSxS 里勾选即用根本不需要源。2012 开始微软改了打包方式把 .NET 3.5 归入 Features on Demand按需功能系统盘里只保留一个几百 KB 的「存根」真正的负载文件被挪到了安装介质的\sources\sxs目录下形式是一堆 cab 包其中最关键的一个叫microsoft-windows-netfx3-ondemand-package.cab。这个设计带来的直接后果是系统知道自己「有这个功能」但手上没有「装这个功能的料」。默认行为是去 Windows 更新把料拉下来拉不到就抛 0x800F0906。所以很多人会困惑——我明明在C:\Windows\WinSxS下看到 netfx3 相关的目录怎么就装不上那些目录只是清单和存根不是负载。这个认知差是绝大多数 .net3.5安装失败 的起点。理解这一点--sxs 镜像资源包 的价值就清楚了它把安装介质里的sources\sxs单独抽出来按系统版本分好你不用每次去翻原版 ISO、不用挂载、不用担心盘符变化直接把 DISM 的/Source指过去就行。本质上是给「按需功能」补一份稳定的、版本对得上的料。2.2 四个高频错误码各自指向完全不同的故障面很多人把这几个码当成同一件事其实它们分布在链路的四个不同环节。先把对照关系摆出来后面排查时能省一大半时间。错误码字面含义真实卡点典型场景0x800F0906无法下载源文件没有可用源且未指定/Source内网机、云主机默认无外网0x800F0907组策略禁止可选组件安装策略被设为「从不尝试」域内机器被统一策略管控0x800F081F找不到源文件指定了/Source但路径下没有匹配的 cab路径写错、版本不匹配、sxs 被裁剪0x800F0922安装未完成系统分区或保留分区空间不足、事务中断小容量系统盘、长期未清理的机器看清楚这张表判断路径就出来了0906 和 0907 是「拿不到料」081F 是「料不对」0922 是「放不下」。前者去补源或改策略后者去看磁盘和日志方向完全不同。我在现场见过最典型的翻车是有人遇到 081F 还在拼命加网络权限实际上跟网络一点关系都没有。2.3 先判断缺的是「源」还是「权限」再决定动不动手动手之前先花两分钟查状态别上来就敲 DISM。三条命令分别看功能当前状态、功能详细信息、以及有没有策略在拦。# 查看 NetFx3 当前状态Available 表示未安装Installed 表示已装 Import-Module ServerManager Get-WindowsFeature -Name NetFx3 | Format-List Name, InstallState, DisplayNameGet-WindowsFeature是 2012 上判断功能状态最直接的方式。InstallState只有两种取值有意义Available说明负载不在本机需要外部源Installed说明已经装好了那你遇到的问题就是另一个方向比如程序仍然报缺少运行库那是应用池的 .NET 版本或 32/64 位问题。Removed状态比较少见通常是被人用Uninstall-WindowsFeature卸过。REM 查看功能详细信息重点看 State 和 Restart Required DISM /Online /Get-FeatureInfo /FeatureName:NetFx3DISM 的输出比 PowerShell 啰嗦但多了Restart Required字段。如果这里显示Possible说明系统里有挂起的事务得先重启再装否则后面无论怎么指定源都会失败。这个细节很容易被忽略尤其是在刚打完补丁就急着装 .NET 3.5 的机器上。REM 查可选组件安装策略RepairContentServerSource 为 0 时表示从不尝试联网 reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing /v RepairContentServerSource REM 查是否被 WSUS 接管UseWUServer 为 1 表示走内网更新服务器 reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU /v UseWUServer第一条注册表查询如果返回0x2找不到说明策略未配置走默认行为此时无外网必然 0906如果返回0说明被显式设成「从不尝试」这就是 0907 的来源。第二条返回1时DISM 的下载行为会被重定向到内网更新服务器如果那台服务器上没有批准 NetFx3 这个包表现同样是长时间卡住后失败。查到这一步你基本能确定该走「补源」还是「改策略」。3. 挂 --sxs 镜像资源包补源DISM 命令的四种写法和参数取舍确定是「缺料」之后剩下的就是把料喂进去。这一步命令不长但参数组合有好几种选错了会绕远路。下面四种写法按适用场景从常用到特殊排列每种都标清楚什么时候用。3.1 挂载介质并确认 sxs 目录的真实路径如果用原版 ISO先挂载再看盘符。服务器上盘符经常和你想的不一样尤其是已经有几个数据盘的生产机。# 挂载 ISO 并取出实际分配的盘符避免手写 E: 结果盘符是 F: $img Mount-DiskImage -ImagePath D:\iso\win2012r2.iso -PassThru $drive ($img | Get-Volume).DriveLetter Write-Output 挂载盘符: $drive Test-Path ${drive}:\sources\sxs\microsoft-windows-netfx3-ondemand-package.cabMount-DiskImage -PassThru是关键不加这个参数就拿不到对象后面取不到盘符。第三行直接去测试那个核心 cab 是否存在返回True才说明这个介质可用。这一步看着多余实际上能挡掉一半的 081F——很多 ISO 是被精简过的sources\sxs目录在但里面的 cab 被删了。如果用的是已经抽好的 --sxs 镜像资源包通常是一个按版本分好的目录直接Test-Path确认目标子目录里有 cab 即可省掉挂载这一步。这也是它在批量部署里更省事的地方不用每台机器都挂一次 ISO拷过去指个路径就完事。3.2 最常用的一条目录源 强制不走更新REM /Online 表示对当前运行的系统操作 REM /FeatureName:NetFx3 是 .NET 3.5 的功能名注意不是 NET-Framework-Features REM /All 连带安装所有父功能和依赖 REM /Source 指向 sxs 目录路径必须包含 cab 文件本身 REM /LimitAccess 强制只从本地源取不再尝试联网避免卡在下载阶段 DISM /Online /Enable-Feature /FeatureName:NetFx3 /All /Source:D:\sxs\2012R2 /LimitAccess六个参数里最容易漏的是/LimitAccess。不加它DISM 会先尝试联网无外网的机器会在这一步耗很久有时十几分钟才回落到本地源看起来像卡死。加了它DISM 直接从本地读几秒钟就出结果。/All也不能省NetFx3 下面挂着几个父功能不加的话可能出现「功能装了但依赖没装全」程序照样报错。/Source的值指向的必须是包含 cab 文件的目录本身不是它的上级。很多人写成D:\sxs而实际 cab 在D:\sxs\2012R2下就会得到 081F——DISM 不会递归找子目录。多个源路径可以用分号分隔常见做法是把资源包目录和备用目录一起写上提高一次成功的概率。3.3 不挂载 ISO直接把 WIM 当源用介质不方便挂载、或者手上只有 install.wim 的场景可以让 DISM 直接读 WIM 内部的索引省掉挂载。REM 先列出 install.wim 里有哪些索引确认哪个是目标版本 DISM /Get-WimInfo /WimFile:E:\sources\install.wim REM 直接指定 WIM 和索引号语法是 WIM:路径:索引 DISM /Online /Enable-Feature /FeatureName:NetFx3 /All /Source:WIM:E:\sources\install.wim:1 /LimitAccess/Get-WimInfo那一步不能跳。一个 install.wim 里常常打包了 Standard、Datacenter、Core 好几个版本索引号从 1 开始。索引选错不一定会立刻报错但装进去的负载和当前系统 build 不匹配后续可能出现功能异常这种更难受的问题。选索引的原则是看Edition和Version两行和winver显示的信息对上。WIM:这个前缀和后面的冒号索引是固定语法写成WIM:E:\sources\install.wim不带索引会直接报错。这条写法还有个好处WIM 是只读的不会被误改适合放在共享目录里给多台机器当统一源。3.4 用 PowerShell 封装方便批量执行单台机器用 DISM 就够要在几十台上重复做用 PowerShell 包一层更稳。# 依次尝试资源包目录和原版介质任一成功即停止 $sources (D:\sxs\2012R2, E:\sources\sxs) foreach ($src in $sources) { if (Test-Path $src\microsoft-windows-netfx3-ondemand-package.cab) { Write-Output 使用源: $src # -All 装齐依赖-LimitAccess 禁止联网-Source 指定本地路径 Install-WindowsFeature -Name NET-Framework-Features -Source $src -LimitAccess -All break } }Install-WindowsFeature是Enable-WindowsOptionalFeature在服务器端的等价物参数语义和 DISM 一一对应-Source对应/Source-LimitAccess对应/LimitAccess-All对应/All。功能名要用NET-Framework-Features这个 PowerShell 别名写错会提示功能不存在。这段脚本的价值在于先做存在性检查再执行避免在错的源上反复重试——排查时最耗时间的往往不是装不上而是不知道自己在拿一个坏源反复试。3.5 装完必须验证别只看命令返回 0命令返回 0 不等于功能真的上线了这条血泪经验值得单独强调。验证分三层功能状态、注册表、实际运行。# 第一层功能状态必须是 Installed Get-WindowsFeature -Name NetFx3 | Select-Object Name, InstallState # 第二层注册表里 Install 值为 1Version 显示 3.5.x reg query HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5 /v Install # 第三层跑一个 .NET 3.5 编译的小程序或看事件日志有无侧并加载记录 Get-EventLog -LogName Application -Source .NET Runtime -Newest 5第一层最常见的问题是显示Installed但Restart Required为Yes此时功能文件已落盘但没生效重启后才算真正完成 .net 3.5服务开启。第二层的Install值为1是最终判据比任何界面显示都可靠。第三层是给业务方确认用的尤其是老系统上跑 ASP.NET 2.0/3.5 站点的场景应用池的 .NET CLR 版本还要单独设成 v2.0.50727这两件事不能混为一谈——功能装好只是前提站点跑不起来还有应用池这一层。4. 组策略和 WSUS 挡住了安装命令返回成功但功能没上线的排查命令敲了没报错返回码 0结果Get-WindowsFeature一看还是Available。这种「看着成功实际没装」的情况八成是被策略层拦住了或者在事务层面没走完。这一章专治这类哑巴亏。4.1 可选组件安装策略的四个取值决定 DISM 去哪找料这条策略在「计算机配置 → 管理模板 → 系统 → 指定 Windows 功能安装和修复的设置」对应注册表HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing\RepairContentServerSource。它有四个状态含义差别很大取值策略状态DISM 行为未配置键不存在默认先尝试 Windows 更新失败才回落0从不尝试从 Windows 更新下载只认/Source没有源直接 09071从 WSUS 下载走内网更新服务器服务器上没有就失败2从 Windows 更新下载无外网时表现和未配置类似但不受本地缓存影响这张表解释了一个反直觉现象有些机器上/Source明明指对了还是报错就是因为策略被设成 0 且同时配置了LocalSourcePath指向一个失效路径策略里的路径优先级高于命令行。处理办法要么临时把策略改成「未配置」要么把LocalSourcePath指到资源包目录。REM 临时清掉策略级的源限制装完再恢复域环境请先跟管理员确认 reg delete HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing /v LocalSourcePath /f reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing /v RepairContentServerSource /t REG_DWORD /d 2 /f REM 刷新策略使其立即生效 gpupdate /forcereg delete那一行删的是策略里硬编码的源路径/f表示不再确认。第二条把下载源改回 Windows 更新这样命令行指定的/Source才能生效。gpupdate /force是为了让组策略立即应用不然要等下一次刷新周期排查时容易误判成「改了没用」。域环境下这几步要先走变更流程别直接在生产机上动。4.2 WSUS 接管时DISM 会停在某个百分比不动内网统一用 WSUS 的环境UseWUServer会被设成 1DISM 的下载请求全部重定向到内网更新服务器。如果那台服务器的产品列表里没有批准 NetFx3 对应的按需功能包表现就是进度条卡在 20% 或 60% 好几分钟最后抛 0906 或 0907。判断方法很直接看C:\Windows\Logs\DISM\dism.log里有没有WU或WSUS关键字的连接记录以及C:\Windows\Logs\CBS\CBS.log里失败前最后几行指向哪里。日志很长按时间倒序找Error就行。# 抓取 DISM 日志中最近的错误行定位失败环节 Select-String -Path C:\Windows\Logs\DISM\dism.log -Pattern Error|0x800f | Select-Object -Last 15 | ForEach-Object { $_.Line }Select-String比直接打开日志翻要快得多-Last 15只看最后十几条避免被大量无关记录淹没。看到Failed to find source就是源问题看到WU client相关就是走网络失败了。定位到这一层要么在 WSUS 里补批准要么干脆用本地源加/LimitAccess绕开——后者在生产机上更快不用等更新服务器那边排期。4.3 返回码是 0 但功能没上线通常是事务没走完还有一种情况DISM 输出「操作成功完成」日志里也没有 Error但功能状态就是不变。常见原因有三个。一是系统里有挂起的 CBS 事务Restart Required为Possible此时所有安装动作都会被排队而不执行解决办法只有重启。二是/All没加功能本体装了但依赖缺失状态可能显示异常。三是系统盘空间不足文件写了一半被截断这种情况往往伴随 0922。# 检查是否有挂起的重启标记 Test-Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending # 检查系统盘剩余空间NetFx3 解压后需要留出足够余量 Get-PSDrive C | Select-Object Used, Free第一个检查返回True就别再折腾了重启一次再装这是最省时间的做法。第二个检查留出至少 2 GB 余量比较稳妥系统盘快满的机器上装大功能失败方式往往很难看。这两条检查加起来不到十秒却能挡掉相当一部分「命令明明成功但就是没装」的玄学问题。5. 避坑清单sxs 源包在真实机房里翻了六次车这一节是踩坑记录五条每条按「现象 → 原因 → 解决」写。都是实际遇到过、且新手很容易重复踩的。5.1 现象命令报 081F原因拿 2012 R2 的 sxs 去装 2012现象很典型/Source路径明明存在cab 也在DISM 就是咬定「找不到源文件」。根因是版本不匹配2012 和 2012 R2 是两个不同的 build6.2 和 6.3sxs 目录里的 cab 做了版本签名校验跨版本喂过去会直接被拒报错还偏偏是「找不到」而不是「版本不对」很误导人。解决办法是核对 build 号再选目录。用winver或systeminfo看系统版本资源包目录按版本分开存放别图省事混用。核对命令如下# 取当前系统 build6.2 对应 20126.3 对应 2012 R2 [System.Environment]::OSVersion.Version | Select-Object Major, Minor, BuildMajor.Minor是6.2就用 2012 的源是6.3就用 2012 R2 的源。这个判断要在动手之前做装完再发现版本不对清理起来更麻烦——功能装了一半的状态下卸载有时需要额外处理。5.2 现象昨天能装今天报错原因镜像盘符在重启后变了挂载的 ISO 在重启后盘符可能从 E 变成 F脚本里硬编码的E:\sources\sxs就失效了。现象是同一份脚本、同一台机器前一天成功第二天失败很迷惑。解决办法是不要硬编码盘符每次挂载后动态取。或者更彻底一点把 sxs 目录直接拷到本地固定路径比如C:\sxs从此不再受挂载状态影响。批量部署场景下推荐后者一次拷贝长期有效也省掉了每台机器挂载 ISO 的步骤。5.3 现象cab 都在但装到一半失败原因源来自精简版镜像用第三方精简过、或者被各种「优化」工具处理过的系统镜像sources\sxs目录结构还在但里面少了几个依赖 cab。DISM 开始装的时候不报错装到某个依赖时突然失败日志里能看到具体缺哪个包。解决办法是换一份完整介质。判断方法是在装之前数一下 cab 数量完整的 sxs 目录有几十个文件只有零星几个基本可以判定被裁过。这也是抽好的 --sxs 镜像资源包比「随便找个 ISO」更可靠的原因它是从完整介质里提取的文件完整性有保证。5.4 现象装完程序还是报缺运行库原因只装了功能没设应用池功能状态是InstalledGet-WindowsFeature也没问题但老站点一访问就报「无法加载程序集」。根因不在功能在 IIS 应用池——默认应用池的 .NET CLR 版本是 v4.0跑 .NET 3.5 的站点必须改成 v2.0.50727。解决办法是单独设置应用池两步都要做# 加载 IIS 管理模块 Import-Module WebAdministration # 把目标应用池的 CLR 版本切到 v2.0.NET 3.5 站点必须走这个版本 Set-ItemProperty IIS:\AppPools\DefaultAppPool -Name managedRuntimeVersion -Value v2.0managedRuntimeVersion的合法值只有v2.0和v4.0两个写v3.5会直接报错——.NET 3.5 在运行时层面用的就是 2.0 的 CLR这一点经常被误解。改完应用池要回收一次才生效。5.5 现象加了/LimitAccess还是联网原因策略里的源优先级更高命令行参数不是最高的。组策略里的LocalSourcePath一旦配置会覆盖/SourceDISM 拿着策略里的路径去找料找不到就失败而你还在怀疑是自己路径写错了。解决办法是先确认策略状态再决定改哪一边。查法和改法在第 4 章已经给出核心就一句RepairContentServerSource和LocalSourcePath这两个键存在时命令行的/Source不一定是最终生效的那个。排查顺序上先查策略再查路径能少走很多弯路。6. 三分钟定位怎么快速判断卡住的是源、策略还是镜像这套判断顺序是我这几年养成的习惯遇到 .net3.5安装失败 先走一遍基本两三分钟就能锁定方向不用盲目试错。第一步看错误码。0907 直接去查RepairContentServerSource这条路径最短0906 看有没有配/Source没配就是没源配了还要看/LimitAccess加没加081F 一律先验路径下有没有microsoft-windows-netfx3-ondemand-package.cab有再往下查版本0922 别犹豫先看磁盘和挂起重启。第二步验版本。[System.Environment]::OSVersion.Version取 build和资源包目录对一遍。这一步只要十秒却能排掉最多的无效尝试。第三步查策略。RepairContentServerSource和UseWUServer两个键前者决定本地源能不能生效后者决定会不会被重定向去内网更新服务器。域内机器这两项几乎必然被配置过跳过这步等于白查。第四步翻日志。C:\Windows\Logs\DISM\dism.log找ErrorCBS.log找失败前最后几条。日志里的原话往往比错误码精确得多尤其是「Failed to find source」和「WU client」这两种一看就知道该往哪个方向走。把这几步整理成一张判断表现场排查时对着看观察到的信号优先怀疑第一个动作报 0x800F0907组策略禁止下载查RepairContentServerSource是否为 0报 0x800F0906 且无/Source缺源挂载介质或指向 sxs 目录报 0x800F0906 且加了/Source被 WSUS 接管或策略覆盖查UseWUServer加/LimitAccess报 0x800F081F路径或版本不对Test-Path验 cab比对 build返回 0 但状态未变事务未完成或有挂起重启查RebootPending重启后重装装完程序仍报错应用池 CLR 版本改managedRuntimeVersion为v2.0从那以后我每次上机做这类补功能的操作都会强制走一遍「验版本 → 验路径 → 查策略 → 看挂起重启」这四步哪怕那台机器看起来一切正常。血泪经验是跳过检查省下的两分钟通常会在后面以一个更莫名其妙的错误码还回来。希望这套顺序能帮你少折腾几次。本文还有配套的精品资源点击获取