0x800F0906 排错:2012 R2 用 SXS 离线装 .NET 3.5
简介:这份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 才说明是 2012R2,9200 是 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 # 第二层:注册表标记,Install=1、SP=1 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 去补 2012R2,100% 是这个结果。
4.2 DISM 不认的几种路径写法
/Source对路径的挑剔程度超出很多人预期,下面三种写法我都见过翻车:
第一,UNC 路径。\\fileserver\share\sxs这种写法 DISM 基本不接受,即使当前账户有权限也不行,因为 CBS 是以 SYSTEM 身份去读源的,网络凭据不会带过去。正确做法是把整个 sxs 目录复制到本地磁盘,几十 MB 的事,别省这一步。
第二,路径带空格没加引号。D:\Server ISO\sources\sxs不加引号会被截断成D:\Server,DISM 会报 0x800F081F 或者干脆报参数无效。加上英文双引号即可。
第三,路径末尾多加了反斜杠或者写成了正斜杠。E:\sources\sxs\这种带尾斜杠的写法在部分版本上会被判定为非法,去掉尾斜杠最保险。
还有一个隐蔽的:镜像已经Dismount-DiskImage卸载了,但命令里的盘符还留着,此时路径不存在,报错同样是 081F。执行前用Test-Path "E:\sources\sxs"确认一次,两秒钟的事。
4.3 组策略和 WSUS 把修复源劫走了
如果加了/LimitAccess还是失败,或者报的是 0907、0954,那就要怀疑策略层。检查两个位置:
# WSUS 是否接管了更新源,UseWUServer=1 表示被接管 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。这时候不用先挂载再找 sxs,DISM 支持直接用 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。原因是没有加/LimitAccess,DISM 在源里没找齐东西之后尝试回退到 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与/LimitAccess | sxs 目录里有没有 netfx3 的 cab |
| 报 0x800F081F,源已指定 | 对比日志里的包名与目录里的包名 | 版本号、架构是否与 CurrentBuild 对齐 |
| 报 0x800F0907 | 查 Servicing 策略项与gpresult | 「从不尝试从 Windows Update 下载负载」是否被勾选 |
| 报 0x800F0954 | 查UseWUServer与 WSUS 审批状态 | 是否被组策略指到了内网更新服务 |
| 命令长时间无输出 | 中断后加/LimitAccess重跑 | 是否在尝试回退到外网 |
这套顺序的价值在于:它把「猜」变成了「读」。报错码只告诉你断在哪一段,日志才告诉你断在哪个文件上。
血泪经验是,我早期排查这类问题,习惯先改命令参数试三五遍,试到没脾气了才去翻日志,结果日志第一屏就写着期望的包版本。从那以后我每次碰 2012R2 装 .NET 3.5,都强制走一遍「先读状态、再读日志、最后才动手」的流程,前后不超过五分钟,比乱试快得多。这份 2012R2 的 sxs 源文件和配套的排查命令我都整理在了一起,遇到同类报错直接照着对表执行就行。希望帮到你。
本文还有配套的精品资源,点击获取