简介这份SXS组件包面向Windows Server 2012 R2 Standard系统管理员与运维人员针对.NET Framework 3.5安装失败、需要指定备用源路径的常见问题整理亲测可用适用于离线部署、老系统兼容修复及服务器环境补装等场景。压缩包为rar格式共含1568个文件约85.45MB覆盖720个dll、84个exe、60个config、56个sql、66个aspx、180个resx以及browser、ini、tlb、targets等类型兼顾运行库、配置文件、Web组件与部署辅助素材目录组织较完整便于按组件检索和匹配。已有1808人学习下载说明该系统版本下的.NET 3.5补装需求较为普遍。读者可获取可用于DISM指定源路径的SXS目录素材并参考组件匹配与排错思路在无法联网或更新源不可用时完成功能补装提升服务器搭建与故障处理效率。1. 0x800F0906装个 .NET 3.5 装到怀疑人生一台 windows_server_2012_r2 standard 的机器业务侧要跑一套很多年前的老系统前置条件写着 .NET Framework 3.5。打开服务器管理器勾上「.NET Framework 3.5 功能」进度条走两下就弹窗安装一个或多个角色、角色服务或功能失败错误代码 0x800F0906。换成命令行 DISM 也一样跑到一半停住日志里只有一句找不到源文件。这故障让人难受的地方在于它不说自己缺哪个文件、该放哪儿只说连不上网而机房里的服务器恰恰是连不出去的。下面就是我拿着 2012R2 安装镜像里的 sxs 文件把这串报错一层层拆开的完整过程从错误码含义、命令参数到日志定位都可以照着复现。2. 0x800F0906 的根因2012R2 把 .NET 3.5 的安装源从系统里搬走了先把结论摆出来这个报错与网络配置无关与防火墙也无关。真正的原因是这台机器上根本没有 .NET Framework 3.5 的安装文件而系统又没找到可以顶替的来源。很多人第一次遇到会本能地怀疑 DNS、代理、出口策略查半天网络其实方向从一开始就偏了。2.1 「按需功能」四个字就是这串报错的开关从 Windows 8 / Server 2012 这一代开始.NET Framework 3.5 被改成了 Feature on Demand也就是按需功能。它的二进制包不再预置进本机的组件存储 WinSxS只在安装介质里保留一份压缩过的 cab放在 ISO 的sources\sxs目录下。这也是为什么所有人搜这个问题最后都会搜到「sxs 文件」这几个字——sxs 就是 side-by-side指的就是这套并列组件存储。启用这个功能时组件服务会按固定顺序找源先看本机 WinSxS 里有没有现成的包没有就看组策略指定的组件修复源再没有才去 Windows Update 拉。三条路全断才会抛出 0x800F0906。所以这个错误码本质上是「三条路都走不通」的合并报错不是某一条路的具体故障。理解了这一点后面的操作就很自然了既然本机没有、外网又不通那就手工把 ISO 里那份 cab 指给它。命令行里的/Source参数干的就是这件事而/LimitAccess是告诉它「别再往 Windows Update 跑了我给你的就是唯一来源」。2.2 四个错误码指向四种不同的断点同样是装不上 .NET 3.5错误码不同根因差得很远。把这几个码分清能省掉一半的试错时间。错误码界面上的说法实际断在哪0x800F0906无法连接到 Internet 下载所需文件本机没有包也没指定源去 Windows Update 的路又不通0x800F081F找不到源文件源路径给了但目录里没有对应的包或包版本与本机不匹配0x800F0907组策略不允许此操作组策略里把「从 Windows Update 下载负载」关掉了源里又没包0x800F0954无法从 WSUS 下载机器被组策略指到内网 WSUS而 WSUS 没批准这个按需功能我在现场见到最多的是 0906 和 081F。前者是压根没给源后者是给了源但给错了——看着都是「找不到文件」处理手法完全相反一个要补源一个要换源。分不清这两个就很容易在同一个坑里来回折腾。2.3 为什么「先联网再装」在机房里基本行不通网上很多答案第一句都是「确保服务器能上网」。这话在实验环境成立在生产环境里往往是最难满足的条件生产网段通常只放行必要的业务端口服务器本身没有默认路由即使有运维规范也不允许一台业务服务器随随便便去公网拉组件。还有一个更隐蔽的情况机器能出网但组策略把 Windows Update 指向了内网 WSUS。这时候系统不会去公网只会问 WSUS而 WSUS 上大概率没批准 NetFx3 这个按需功能于是照样失败报的还可能是 0954 而不是 0906让人以为是两个不同的问题。所以对 2012R2 这类还在跑老业务的机器正确姿势从一开始就不是「想办法让它联网」而是「把安装介质里的 sxs 目录喂给它」。安装介质是现成的、版本是确定的、不依赖任何网络策略这才是可复制、可交付的做法。3. 挂载 ISO 指定 SXS一条 DISM 命令把 .NET 3.5 装回去思路定下来之后剩下的全是细节。这一章按顺序走一遍对齐版本、挂载镜像、执行命令、验证结果。每一步失败会看到什么我也一并写清楚。3.1 先对齐版本源必须是 2012 R2 的同架构介质这是最容易忽略、又最致命的一步。sources\sxs里的那个 cab 不是通用包它和 CBS 里登记的组件版本是强绑定的。用 Windows Server 2012非 R2的镜像去喂 2012R2用 Windows 8.1 的镜像去喂 2012R2甚至用 Server 2016 的镜像去喂命令都会执行下去然后在最后阶段报 0x800F081F。我一般会先在目标机上确认三件事系统版本、内部版本号、架构。三条命令几十秒的事。# 系统版本与内部版本号2012R2 应该是 6.3.9600 Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion | Select-Object ProductName, CurrentBuild, CurrentBuildNumber # 架构服务器基本都是 x64但要确认不是 Itanium 之类的特殊版本 $env:PROCESSOR_ARCHITECTURE # 当前功能状态确认是未安装而不是半装状态 Get-WindowsFeature -Name NET-Framework-Core | Select-Object Name, InstallStateCurrentBuild是 9600 才说明是 2012R29200 是 2012这两者绝不能混用。InstallState如果既不是Installed也不是Available而是卡在中间态那要先处理挂起的安装再谈装功能否则后面全是误导性的报错。提示ISO 的介质名里通常带 Standard 或 Datacenter 字样但 sxs 目录里的按需功能包与这两个版本是通用的真正必须对齐的是「大版本号 架构」不是这两个版本名。3.2 挂载镜像确认 sources\sxs 里到底有什么把 ISO 传到服务器本地磁盘不建议放在网络共享上原因在 4.2 会讲。挂载用 PowerShell 一条命令注意要拿-PassThru否则拿不到对象、也取不到盘符。# 挂载 ISO把返回对象接住后面取盘符要用 $iso Mount-DiskImage -ImagePath D:\iso\server2012r2_x64.iso -PassThru # 从挂载对象反查卷取到实际分配的盘符 $drive ($iso | Get-Volume).DriveLetter Write-Host 挂载到: $drive # 确认 sxs 目录里确实有 NetFx3 的按需功能包 Get-ChildItem ${drive}:\sources\sxs -Filter *netfx3* | Select-Object Name, Length最后那条命令的输出是关键判断依据。正常应该能看到一个microsoft-windows-netfx3-ondemand-package.cab之类的文件大小在几十 MB 量级。如果这个目录是空的、或者只有一堆名字完全不相干的 cab那就说明这份介质本身不含按需功能负载换一份完整的安装 ISO 再来别在命令上继续纠结。盘符每次挂载都可能变所以不要凭记忆写E:\一定要用Get-Volume现场取。我在机房见过不止一次因为前一次挂载的 E 盘还没卸载新镜像被分到 F 盘命令里却仍写着 E结果指到了上一份旧镜像上报的正是 081F。3.3 DISM 命令逐段拆解以及每个开关到底在干什么源确认无误就可以装了。命令行和 PowerShell 两种写法等价任选其一。DISM 写法的好处是不依赖 PowerShell 版本在 Server Core 上更稳。# 离线启用 .NET Framework 3.5源指向挂载盘里的 sxs 目录 DISM /Online /Enable-Feature /FeatureName:NetFx3 /All /LimitAccess /Source:E:\sources\sxs六个部分拆开看/Online操作当前正在运行的系统。如果写成/Image:C:\mount那就变成了给离线镜像打补丁是完全不同的一件事。/Enable-Feature启用功能与之对应的是/Disable-Feature。/FeatureName:NetFx3这是 DISM 侧的功能名注意它和 PowerShell 里的NET-Framework-Core不是同一个字符串写错了会直接报「功能名称未知」。/All把该功能下的父功能、子组件一并启用。.NET 3.5 下面还挂着 WCF 之类的子项不加这个参数可能只装了一半业务程序照样跑不起来。/LimitAccess禁止 DISM 回退到 Windows Update 或 WSUS 找源。这条最容易被漏掉漏掉的后果是命令会卡在某个百分比上很久最后再给你一个 0906白等十几分钟。/Source:源路径必须是目标机自己能访问到的本地路径末尾不要带引号以外的多余字符。PowerShell 侧的等价写法功能名换成NET-Framework-Core# 加 -Restart 会在需要时自动重启先不加装完自己判断 Install-WindowsFeature -Name NET-Framework-Core -Source E:\sources\sxs -Restart这里有个版本差异值得记一下Install-WindowsFeature的-Source参数是 2012R2 才有的在 2012非 R2上根本没有这个参数只能退回 DISM 写法。如果你在 2012 上照抄某篇教程报「找不到接受参数 Source 的位置形式参数」原因就在这儿不是语法写错。另外-Source除了接目录还支持直接接 WIM写法是-Source WIM:D:\sources\install.wim:2冒号后面那个数字是映像索引。这条路在 4.4 展开。3.4 装完怎么验证功能状态、注册表、目录三个层面命令返回「操作成功完成」不等于装好了。CBS 的收尾是异步的有时候返回成功但功能状态还没落盘直接去跑业务程序会得到一个莫名奇妙的程序集加载失败。我一般从三个层面各查一次全绿才算过。# 第一层功能状态InstallState 必须是 Installed Get-WindowsFeature -Name NET-Framework-Core | Select-Object Name, InstallState, FeatureType # 第二层注册表标记Install1、SP1 Get-ItemProperty HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5 | Select-Object Install, SP, Version # 第三层运行时文件是否真的落地 Test-Path $env:windir\Microsoft.NET\Framework64\v3.5\mscorwks.dll Test-Path $env:windir\Microsoft.NET\Framework\v3.5\mscorwks.dll第一层看的是「系统认为它装没装」第二层看的是「.NET 运行时登记的版本」第三层看的是「文件在不在」。三层里任意一层不一致都说明这次安装没真正完成多数是 CBS 还在后台收尾等几分钟重查即可如果十分钟后仍然不一致去看C:\Windows\Logs\CBS\CBS.log的尾部那里会写明哪一步回滚了。装完之后如果这台机器还跑 IIS别急着交付。IIS 的应用池里能不能选到 .NET CLR v2.0取决于有没有装 ASP.NET 3.5 这个功能跟 .NET 3.5 本体是两回事这一点放到第 5 章说。4. 源指定了还失败0x800F081F 和路径相关的四类翻车命令写对了、源也挂上了还是失败这是最耗心态的阶段。下面四类是我遇到过频次最高的基本能覆盖 081F 的绝大多数情况。4.1 0x800F081F目录在包不对081F 的字面意思是「找不到源文件」但它最常见的成因不是路径写错而是路径对了、里面的包不对。CBS 会拿着自己内部登记的组件版本去源目录里比对比对不上就报这个错日志里的原话通常是「源文件版本与需要安装的版本不匹配」。判断方法很直接把源目录里的包名和日志里 CBS 要找的包名对一遍。# 看源目录里都有什么 Get-ChildItem E:\sources\sxs | Select-Object Name, Length # 看 CBS 日志里到底在找哪个包先复制一份避免被占用 Copy-Item $env:windir\Logs\CBS\CBS.log C:\temp\cbs_copy.log Select-String -Path C:\temp\cbs_copy.log -Pattern NetFx3|0x800f081f | Select-Object -Last 20两边的名字对不上就换介质不要在命令参数上继续试。用 2016/2019 的 sxs 去补 2012R2100% 是这个结果。4.2 DISM 不认的几种路径写法/Source对路径的挑剔程度超出很多人预期下面三种写法我都见过翻车第一UNC 路径。\\fileserver\share\sxs这种写法 DISM 基本不接受即使当前账户有权限也不行因为 CBS 是以 SYSTEM 身份去读源的网络凭据不会带过去。正确做法是把整个 sxs 目录复制到本地磁盘几十 MB 的事别省这一步。第二路径带空格没加引号。D:\Server ISO\sources\sxs不加引号会被截断成D:\ServerDISM 会报 0x800F081F 或者干脆报参数无效。加上英文双引号即可。第三路径末尾多加了反斜杠或者写成了正斜杠。E:\sources\sxs\这种带尾斜杠的写法在部分版本上会被判定为非法去掉尾斜杠最保险。还有一个隐蔽的镜像已经Dismount-DiskImage卸载了但命令里的盘符还留着此时路径不存在报错同样是 081F。执行前用Test-Path E:\sources\sxs确认一次两秒钟的事。4.3 组策略和 WSUS 把修复源劫走了如果加了/LimitAccess还是失败或者报的是 0907、0954那就要怀疑策略层。检查两个位置# WSUS 是否接管了更新源UseWUServer1 表示被接管 Get-ItemProperty HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU -Name UseWUServer -ErrorAction SilentlyContinue # 「可选组件安装和组件修复」这条策略是否被显式配置过 Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing -ErrorAction SilentlyContinue第二条对应的组策略路径是「计算机配置 → 管理模板 → 系统 → 指定可选组件安装和组件修复的设置」。如果这一项被配成「从不尝试从 Windows Update 下载负载」那么在源里找不到包时系统会立刻失败不会再去任何地方找表现就是 0907。处理方式临时把这条策略改成「未配置」gpupdate /force之后重试装完再把策略改回去。临时变更一定要留记录、装完复原否则下次别人在同样机器上排查会被这条策略再坑一次。用gpresult /h C:\temp\gp.html可以一次性看清楚这台机器上生效的所有策略比逐条翻注册表快。4.4 没有 ISO 时直接拿 install.wim 当源有些环境里拿不到完整 ISO只有别人拷过来的install.wim。这时候不用先挂载再找 sxsDISM 支持直接用 WIM 作为源代价是要指定正确的映像索引。# 先看这个 wim 里有几个映像各自的版本描述 DISM /Get-WIMInfo /WIMFile:D:\sources\install.wim # 用指定索引的映像作为源索引必须与当前系统版本一致 DISM /Online /Enable-Feature /FeatureName:NetFx3 /All /LimitAccess /Source:WIM:D:\sources\install.wim:2WIM:前缀后面的写法是「文件路径 冒号 索引」中间不能再有空格。索引选错是这条路上唯一的坑选到 Datacenter 而本机是 Standard或者选到旧版本映像结果都是 081F。/Get-WIMInfo的输出里每一项都有Name和Description照着当前系统版本挑别猜。5. 避坑清单五个反复出现的问题下面这五条是我在不同机器上反复见到的每一条都按「看到什么 → 为什么 → 怎么处理」写遇到对得上的直接照做。第一条命令卡在 20% 左右很久最后报 0x800F0906。原因是没有加/LimitAccessDISM 在源里没找齐东西之后尝试回退到 Windows Update而机器出不去于是卡到超时。处理方式是中断命令加上/LimitAccess重跑把回退路径彻底堵死让它在源里找不齐就立刻报错节省时间。第二条服务器管理器里显示 .NET 3.5 已安装IIS 应用池的 .NET CLR 版本下拉框里却只有 v4.0。原因是 IIS 要跑 .NET 3.5 的程序光有运行时不够还得装 ASP.NET 3.5 这个 Web 功能它才会往 IIS 里注册 v2.0 的 CLR。处理方式是补装对应功能Install-WindowsFeature -Name Web-Asp-Net装完iisreset一次下拉框里就出现了。第三条远程 PowerShell 会话里执行Install-WindowsFeature -Source报路径不存在。原因是路径写成了网络共享或者远程会话里发生了凭据双跳SYSTEM 身份读不到那个位置。处理方式是把 sxs 目录复制到目标机本地磁盘用本地路径重新执行实在要用共享就先在目标机上开一个本地会话跑命令。第四条重跑命令报 0x800F081F但上次明明成功过。原因是机器上同时挂载了多份镜像旧的那份没卸载新镜像被分到了另一个盘符命令里的盘符指到了旧镜像的 sxs 上。处理方式是用Get-DiskImage -ImagePath 路径逐个确认挂载状态Dismount-DiskImage卸载多余的再用Get-Volume重新取盘符把命令里的路径改对。第五条装完当场能用重启后业务程序又报找不到 3.5 运行时。原因是安装过程中系统处于挂起状态CBS 的收尾没跑完就被重启打断了。处理方式是重启前先查HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending这个键是否存在存在就说明有挂起操作等它清空再重启已经打断的重新执行一次启用命令它会自动修复半装状态。6. 快速定位三条命令锁定到底缺哪个源真到了现场别急着敲安装命令先花两分钟把「现在处于什么状态」问清楚。我的固定顺序是三步。第一步确认功能当前状态和目标版本。Get-WindowsFeature -Name NET-Framework-Core看InstallState(Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion).CurrentBuild看是不是 9600。这两条决定了后面所有命令的写法版本不对齐写什么都没用。第二步从日志里读出 CBS 到底在找什么。这是最有效的一步也是最多人跳过的一步。# 复制一份再搜CBS.log 经常被组件服务占用 Copy-Item $env:windir\Logs\CBS\CBS.log C:\temp\cbs.log -Force Select-String -Path C:\temp\cbs.log -Pattern NetFx3|0x800f | Select-Object -Last 30日志里会明确写出「正在尝试的源路径」和「期望的包版本」把这两条和实际源目录对比081F 一类的问题基本当场就能定位。第三步按症状对表处置。现场症状第一时间执行主要看什么报 0x800F0906没指定过源挂载同版本 ISO加/Source与/LimitAccesssxs 目录里有没有 netfx3 的 cab报 0x800F081F源已指定对比日志里的包名与目录里的包名版本号、架构是否与 CurrentBuild 对齐报 0x800F0907查 Servicing 策略项与gpresult「从不尝试从 Windows Update 下载负载」是否被勾选报 0x800F0954查UseWUServer与 WSUS 审批状态是否被组策略指到了内网更新服务命令长时间无输出中断后加/LimitAccess重跑是否在尝试回退到外网这套顺序的价值在于它把「猜」变成了「读」。报错码只告诉你断在哪一段日志才告诉你断在哪个文件上。血泪经验是我早期排查这类问题习惯先改命令参数试三五遍试到没脾气了才去翻日志结果日志第一屏就写着期望的包版本。从那以后我每次碰 2012R2 装 .NET 3.5都强制走一遍「先读状态、再读日志、最后才动手」的流程前后不超过五分钟比乱试快得多。这份 2012R2 的 sxs 源文件和配套的排查命令我都整理在了一起遇到同类报错直接照着对表执行就行。希望帮到你。本文还有配套的精品资源点击获取