
简介面向 Windows Server 2012 R2 Standard 运维场景的 SXS 组件包主要用于解决 .NET Framework 3.5 安装失败时需要指定备用源路径的问题适合系统管理员、桌面运维及需要离线部署旧版 .NET 运行环境的用户参考使用。压缩包内共 1568 个文件以 dll、resx、exe、aspx、config、sql、browser 等类型为主涵盖组件库、资源文件、可执行程序、配置项及数据库脚本等安装支撑内容整体约 85.45MB。已有 1808 人学习或下载。其价值在于为 Server 2012 R2 Standard 的 .NET 3.5 功能安装提供可指定的 SXS 备用文件集合便于在离线或受限网络环境中完成组件补齐同时可通过包内配置与资源文件辅助排查安装失败原因、核对组件完整性。对于需要修复旧系统功能安装问题、构建离线部署介质或验证 SXS 源可用性的读者这份资源具有较明确的参考和实用价值。1. 一台 2012 R2 上没有 sxs 就装不上的 .NET 3.5接手一台 Windows Server 2012 R2 Standard 的旧业务机最先卡住的常常不是业务而是 .NET Framework 3.5。系统里明明装着 4.5跑老安装包却弹「需要 .NET Framework 3.5 功能」点「从 Windows 更新下载」转圈十几分钟最后甩出一个 0x800f0906。真正缺的不是安装包而是 sources\sxs 这份组件源——2012 R2 把 .NET 3.5 拆成了按需功能二进制文件躺在安装介质的 sxs 目录里系统自己不会变出来。内网无外网、WSUS 又管着更新策略的机器几乎都得手工把这份源喂给 DISM。这篇记录的就是这条链路版本怎么对齐、ISO 怎么挂、DISM 和 Install-WindowsFeature 怎么选、组策略怎么绕、报错码看哪个。手上有 2012 R2 镜像和 sxs 目录的人照着走一遍就能落地。2. 装前对齐2012 R2 的版本、SKU 与 sxs 源匹配装 .NET 3.5 失败的人里一半以上不是命令写错是源和系统对不上。sxs 目录不是通用补丁包它跟安装介质的版本、SKU、补丁级别绑在一起。拿 2016 的 sxs 往 2012 R2 上灌或者拿 Datacenter 的 install.wim 拆出来的 sxs 往 Standard 上灌DISM 会在校验阶段就退回来错误码看着像「文件找不到」实际是「文件不对」。2.1 先把系统版本、SKU 和功能状态摊开动手之前先把机器的底摸清楚三条命令就够。Server Core 没有图形界面同样能跑。# 系统版本与内部版本号2012 R2 应为 6.3.9600 wmic os get Caption,Version,BuildNumber /format:list # 当前 SKU确认是 Standard 还是 Datacenter DISM /Online /Get-CurrentEdition # .NET 3.5 当前状态Disabled 才需要装Enabled 说明已经装过了 DISM /Online /Get-FeatureInfo /FeatureName:NetFx3wmic os get Caption输出里带不带 R2 很关键2012 和 2012 R2 的 sxs 不通用内部版本一个 6.2 一个 6.3肉眼看着都是「Windows Server 2012」稍不注意就拿错镜像。Get-CurrentEdition则告诉你这台是 Standard 还是 Datacenter虽然同一张 install.wim 里各 SKU 共享大部分组件但为了少踩坑源最好取自同 SKU 同版本的介质。功能状态那一条最容易被忽略。有些机器上 .NET 3.5 是「装了一半」的状态向导点过、「下一步」按过、中途断了网功能停在 Disabled 但注册表里留了记录这时候直接再跑 DISM 可能报 0x80073712。碰到这种先/Disable-Feature清一遍再装比硬怼省时间。2.2 install.wim 的索引与 sources\sxs 的对应关系ISO 根目录下的sources\sxs是一个独立目录里面是一堆 cab 包典型文件名是microsoft-windows-netfx3-ondemand-package.cab。它和同目录的install.wim是同一次构建出来的所以最稳的取源方式永远是「从这张 ISO 里拿」。但有人会把 install.wim 单独拷出来用这时候要确认索引。2012 R2 的 install.wim 里通常有四到五个索引分别对应 Standard Core、Standard 带 GUI、Datacenter Core、Datacenter 带 GUI。别按索引号猜看 Name 字段# 列出 wim 内所有索引按 Name 找带 GUI 的 Standard DISM /Get-WimInfo /WimFile:D:\sources\install.wim # 需要精确对照时查指定索引的详细信息 DISM /Get-WimInfo /WimFile:D:\sources\install.wim /Index:2/Get-WimInfo输出的 Name 一般是Windows Server 2012 R2 SERVERSTANDARD这类全大写串Description 里会写明是不是 Server Core。如果/Source后面直接指 wim 文件索引号必须和当前系统对得上Standard 带 GUI 的机器拿 Core 的索引做源DISM 一样会报源文件不匹配。还有一个隐性变量是补丁级别。装过大量累积更新的机器组件版本号会比原版 ISO 高此时用原版 sxs 装 NetFx3 一般仍然成功因为 NetFx3 的 cab 本身没被累积更新替换但如果机器上装过某些 .NET 相关更新导致组件存储被改写原版源就可能对不上报错会落在 0x800f081f 上。这种情况的处理办法在后面排查章细说。2.3 三种取源方式的取舍ISO、解压目录、挂载 wim实际干活时能拿到的「源」有三种形态稳定性差别不小。第一种是挂载原始 ISO。最推荐因为路径干净、文件完整、不会中途被改。缺点是服务器上不一定有光驱得用 PowerShell 挂或者先把 ISO 传到本地磁盘。第二种是把 ISO 解压到某个目录比如D:\iso2012r2\然后指向D:\iso2012r2\sources\sxs。这种做法在批量部署里最常见一次解压多台机器共用。要注意两点解压工具别把 cab 文件名改成大写小写混合DISM 对大小写不敏感但有些同步工具会以及目录别放在网络共享上——/Source支持 UNC 路径但走 SMB 时权限和延迟都会让安装变慢甚至超时。第三种是从 install.wim 里挂载取源。适合手上只有 wim 没有 ISO 的场景# 建挂载点并只读挂载取完 sxs 立刻卸载 New-Item -Path C:\mount -ItemType Directory -Force DISM /Mount-Wim /WimFile:D:\sources\install.wim /Index:2 /MountDir:C:\mount /ReadOnly # 复制 sxs 到本地卸载并丢弃挂载 Copy-Item -Path C:\mount\sources\sxs -Destination D:\sxs2012r2 -Recurse DISM /Unmount-Wim /MountDir:C:\mount /Discard/ReadOnly保证挂载不会写坏 wim/Discard表示不保存任何改动。挂载点目录必须是空目录非空会直接失败用完一定要卸载残留的挂载状态会让后续 DISM 操作报「另一个进程正在使用」。绝对不推荐的做法是从一台已装好的同版本机器的C:\Windows\WinSxS里直接拷文件。那个目录里全是硬链接和版本化目录拷出来的东西看似齐全DISM 认不出来装上去也是各种 0x800f081f。3. 挂载与安装DISM 和 Install-WindowsFeature 两条路源准备好之后就是装。命令行有两条路DISM 和 PowerShell 的 Install-WindowsFeature。功能上等价参数风格不同Server Core 上两条都能跑图形界面的「添加角色和功能向导」在批量场景里反而最慢不推荐。3.1 挂 ISOMount-DiskImage 与盘符确认2012 R2 自带Mount-DiskImage不需要装任何虚拟光驱工具。# 挂载 ISO 并拿到盘符 $iso Mount-DiskImage -ImagePath D:\ISO\2012R2_STD.iso -PassThru $drive ($iso | Get-Volume).DriveLetter Write-Output 挂载盘符: $drive # 确认 sxs 目录存在且里面有 netfx3 的 cab Test-Path ${drive}:\sources\sxs Get-ChildItem ${drive}:\sources\sxs -Filter *netfx3*-PassThru让 cmdlet 返回对象而不是静默执行后面的Get-Volume才能取到盘符。这一步别用固定的E:硬编码机器上原有分区数量不同挂载出来的盘符每次可能不一样脚本里写死盘符是高频翻车点。Test-Path和Get-ChildItem两个校验看着多余其实是在确认「这张 ISO 真的带 sxs」——有些精简版或评估版介质里 sxs 目录是空的。用完记得卸载否则下次挂同一个 ISO 会提示已挂载Dismount-DiskImage -ImagePath D:\ISO\2012R2_STD.isoServer Core 上如果 PowerShell 版本较老不支持Mount-DiskImage退回到 diskpartdiskpart→select vdisk fileD:\ISO\x.iso→attach vdisk本质一样。3.2 DISM 启用 NetFx3 的命令与每个参数核心就一条命令参数一个都别省。# 从本地 sxs 源启用 .NET Framework 3.5禁止联网 DISM /Online /Enable-Feature /FeatureName:NetFx3 /All /LimitAccess /Source:E:\sources\sxs /NoRestart逐个解释因为每个人踩的坑基本都能对应到某个参数/Online表示操作当前运行的系统不是离线镜像。如果误写成/Image:C:\...DISM 会去改挂载的 wim装完重启发现功能没生效。/FeatureName:NetFx3是功能名不是NetFx3.5也不是NET-Framework-Core那是 PowerShell 侧的叫法。写成NetFx35会报 0x800f080c「功能名称未知」。/All会连带启用父功能。NetFx3 依赖 WCF 相关的几个子功能不加/All有时装完能查状态是 Enabled但某些老程序仍然报缺组件。/LimitAccess是断网机器的关键。它明确告诉 DISM 不要向 Windows 更新发出请求。不加这个参数即使给了/SourceDISM 在某些策略环境下仍会先尝试联网超时后才回落到本地源安装时间从两分钟变成二十分钟。/Source指向 sxs 目录本身不是 ISO 根目录也不是 sources 上一级。指错一级是最常见的错误报 0x800f081f。/NoRestart阻止自动重启。生产机上这一条基本必加重启时机要自己排。命令跑完正常输出是「操作成功完成」进度条走到 100%。如果卡在 20% 左右不动很久多半是在尝试联网检查/LimitAccess有没有加。3.3 Server Core 下的 Install-WindowsFeature 与差异PowerShell 侧的写法更「原生」返回对象也更好解析适合写进自动化脚本。# 用 ServerManager 模块安装 .NET 3.5指定本地源 Import-Module ServerManager Install-WindowsFeature -Name NET-Framework-Core -Source E:\sources\sxs -Restart:$false # 装完立刻回读状态Success 为 True 才算真的成功 Get-WindowsFeature -Name NET-Framework-Core | Select-Object Name, InstallState-Name NET-Framework-Core与 DISM 的NetFx3是同一个功能的两个名字别混着记。-Source参数在 2012 R2 上有效等价于 DISM 的/Source但Install-WindowsFeature没有直接对应/LimitAccess的开关它默认就走本地源优先如果机器上有 WSUS 策略行为由策略决定这一点第 4 章展开。-Restart:$false明确不重启。不写这个参数时某些情况下 cmdlet 会自动重启脚本跑到一半机器就断了。Get-WindowsFeature的输出里InstallState有三态Available、Installed、Removed。装成功是 Installed如果显示 Removed说明功能被显式移除过需要用-IncludeAllSubFeature或者先清掉移除状态。Server Core 与带 GUI 版本在这里没有本质差异差异在于带 GUI 的机器上有人习惯点向导而向导在遇到源问题时给的提示比命令行模糊得多只给一个「无法完成更改」反而不如直接跑命令看错误码。3.4 装完别急着清 WinSxS硬链接与组件存储功能装好后C 盘会涨几百 MB很多人第一反应是去清C:\Windows\WinSxS。这个目录不能手动删也不能用资源管理器改权限后删——里面的文件和 System32、.NET 目录之间是硬链接关系删掉表面上看释放了空间实际会让系统组件悄悄损坏症状是几周后某个服务起不来。清理要走 DISM命令是现成的# 先分析不改动任何东西 DISM /Online /Cleanup-Image /AnalyzeComponentStore # 确认可回收后再执行清理 DISM /Online /Cleanup-Image /StartComponentCleanup # 加上 /ResetBase 会清得更彻底但之后无法卸载任何已安装更新 DISM /Online /Cleanup-Image /StartComponentCleanup /ResetBaseAnalyzeComponentStore会给出「可回收的包数量」和「建议清理」两项。刚装完 NetFx3 时这个数字可能不为零但我不建议立刻清——刚装完的功能组件还在备份区/ResetBase之后再想回退 .NET 3.5 就只能重装。常见做法是等系统稳定运行一两周确认没有业务依赖回退再跑一次带/ResetBase的清理。还有一个细节sources\sxs目录用完别删留在本地磁盘上。以后装 .NET 3.5 的其他子功能、或者系统组件损坏需要修复时/Source还得指回这里。我一般把它放在非系统盘的固定目录D:\sxs\2012r2命名带上版本号避免和多代系统的源混在一起。4. 备用源策略组策略、WSUS 和 LimitAccess命令写对了、源也指对了仍然报错的情况九成出在策略层。2012 R2 的按需功能安装受一条组策略控制而这条策略在内网 WSUS 环境下的默认行为恰好和「用本地 sxs 装」的诉求相反。4.1 「指定可选组件安装和组件修复的设置」两处开关策略位置计算机配置 → 管理模板 → 系统 → 指定可选组件安装和组件修复的设置。这条策略有三个部分要一起看。第一处是启用开关。未配置时系统按默认逻辑走也就是允许向 Windows 更新请求组件一旦启用就能选「从不安装……」「从 Windows 更新下载修复内容」「联系 Windows 更新以检查是否有更新的修复内容」三档。内网机器要用手工 sxs应该选第一档或配置备用源路径否则 DISM 会先尝试联络更新服务器。第二处是「备用源文件路径」。填的就是 sxs 目录比如D:\sxs\2012r2。这里支持环境变量写%SystemDrive%\sxs也行。填完之后DISM 在不加/Source时也能找到本地源很多批量脚本就靠这一条省掉参数。第三处是「从 Windows 更新下载修复内容」的子选项控制组件损坏时是否允许联网修复。内网环境一般关掉避免每次修复都等超时。策略下发后注册表里能看到对应值位置在HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing下LocalSourcePath是字符串UseWindowsUpdate是 DWORD。不同版本、不同补丁级别下这几个值的语义有过调整所以最稳的核对方式不是背值而是改完策略后跑一条reg query看实际写进去什么再对照 DISM 的行为# 核对策略实际落地的注册表值 reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing /v LocalSourcePath reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing /v UseWindowsUpdate如果这两条查询返回「找不到指定的注册表项或值」说明策略没生效先跑gpupdate /force再确认这条策略是下在本地还是域级别——域策略会覆盖本地设置本地改了也没用。4.2 WSUS 内网里的路径放行与注册表兜底WSUS 管着更新的机器上/LimitAccess加得再对也可能撞上 0x800f0954。这个码的含义是「DISM 无法访问 Windows 更新」但在 WSUS 场景里它的真实含义是「策略把更新入口指向了 WSUS而 WSUS 上没有批准 .NET 3.5 的功能包」。两条路可以走。第一条是正规路在 WSUS 控制台里找到「Windows Server 2012 R2 的功能包」类目批准 .NET Framework 3.5 对应的功能更新客户端下次检测时能拉到。这条路干净但需要 WSUS 管理员配合节奏慢。第二条是临时绕开在目标机器上把更新入口临时指向空或者直接清掉HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate下的策略键装完再恢复。这一步风险明确——清了策略机器上的其他更新行为也会变所以我的习惯是先导出备份再动# 动策略前先备份装完原样导回 reg export HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate C:\temp\wu_backup.reg /y # 安装 .NET 3.5 DISM /Online /Enable-Feature /FeatureName:NetFx3 /All /LimitAccess /Source:D:\sxs\2012r2 /NoRestart # 导回策略并强制刷新组策略 reg import C:\temp\wu_backup.reg gpupdate /force顺序不能反。先备份再装再恢复中间如果安装失败也要恢复别把机器留在「策略被清空」的状态过夜。4.3 /LimitAccess 在断网机器上到底做了什么很多人把/LimitAccess理解成「只用本地源」这个理解不完整。它做的是「禁止 DISM 向 Windows 更新发出请求」但不会替你检查本地源是否有效。也就是说不加/LimitAccess且不给/SourceDISM 联网找断网机器等超时报 0x800f0906。 加/LimitAccess但不给/SourceDISM 直接不找报 0x800f0906速度很快。 加/LimitAccess且给对/Source从本地装正常成功。 加/LimitAccess且/Source指错报 0x800f081f。这四种组合覆盖了绝大多数人的报错。真断网的机器上/LimitAccess必加它把「等十分钟超时」变成「立刻报错」排错效率完全不同。还有一类机器是「半断网」能访问内网 WSUS不能访问外网。这种机器上/LimitAccess会阻止 DISM 找 WSUS反而让安装更可控所以内网环境我一律加。5. 安装翻车排查五个高频报错码逐条对报错码是这套流程里最有价值的东西因为它把「感觉装不上」变成「知道卡在哪一层」。下面五条是按我遇到的频率排的每条给出触发场景。5.1 源与路径类0x800f0906 与 0x800f081f现象执行 DISM 后进度条走到一小段就退出报「无法下载源文件」或「找不到源文件」。原因0x800f0906 多半是根本没给有效源DISM 尝试联网失败0x800f081f 是给了/Source但路径里没有系统要的文件。解决先确认/Source指到的是sources\sxs这一级而不是 ISO 根目录或 sources 目录。再确认这个 sxs 目录里真的有microsoft-windows-netfx3-ondemand-package.cab。最后确认源和系统版本一致——用DISM /Get-WimInfo看 install.wim 的版本和wmic os get Version的输出对一下。跨版本用源是这两个码的常见诱因。5.2 策略类0x800f0954 与 0x800f0907现象源路径完全正确文件也在但 DISM 仍然报「组策略不允许」或「无法联系更新服务器」。原因0x800f0954 是 WSUS 环境下更新入口被策略接管DISM 拿不到功能包0x800f0907 是组策略明确禁止了 Windows 更新参与组件安装同时又没配本地源。解决按第 4 章的流程走先看Policies\Servicing下的LocalSourcePath有没有配没配就配上再看Policies\Microsoft\Windows\WindowsUpdate有没有指向 WSUS。临时绕开的做法是备份后清空更新策略键装完导回。注意 0x800f0907 在域环境下改本地策略无效得让域管理员调整 OU 级别的策略这一点提前沟通能省很多时间。5.3 系统状态类0x80073712 与 0x800f0922现象所有参数都正确仍然失败报「组件存储已损坏」或「系统保留分区空间不足」。原因0x80073712 是 WinSxS 组件存储本身出了问题常见于强制断电、磁盘满、或者有人手动删过 WinSxS 里的文件0x800f0922 是系统保留分区或 C 盘空间不够安装过程需要向保留分区写引导相关文件。解决前者先跑修复再装功能。修复本身也缺源所以要把 wim 作为源一起给# 用 install.wim 作为修复源索引号要和当前系统对得上 DISM /Online /Cleanup-Image /RestoreHealth /Source:WIM:D:\sources\install.wim:2 /LimitAccess # 修复完成后重新尝试 DISM /Online /Enable-Feature /FeatureName:NetFx3 /All /LimitAccess /Source:D:\sxs\2012r2 /NoRestart/RestoreHealth跑完会给出「操作成功完成」或「组件存储可修复」两类结果。如果它自己也报找不到源说明 wim 索引号选错回到 2.2 节重新查。0x800f0922 的解决更直接查Get-Partition和Get-Volume看系统保留分区剩余空间2012 R2 上这个分区一般 350MB 到 500MB被日志或转储文件占满时会不够。清掉C:\Windows\Logs\CBS下的大文件别删目录、把页面文件临时挪走再装。6. 验证怎么确认 .NET 3.5 是真能跑而不是只显示已安装DISM 报「操作成功完成」只是第一步功能状态是 Enabled 也不代表能跑业务。真正的验收要落到「编译一个 .NET 3.5 程序并运行」这个层面。先看状态三个口径互相印证# 口径一DISM 的功能状态 DISM /Online /Get-FeatureInfo /FeatureName:NetFx3 # 口径二PowerShell 的模块状态 Get-WindowsFeature -Name NET-Framework-Core | Select-Object Name, InstallState # 口径三3.5 的编译器是否落地这个文件是判断真假的硬指标 Test-Path C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe Test-Path C:\Windows\Microsoft.NET\Framework\v3.5\mscorwks.dllv3.5目录下的csc.exe和mscorwks.dll是最实在的证据。有些机器上状态显示 Installed但这两个文件缺失说明安装中途被打断属于「假成功」。然后跑一次编译十行代码就够# 写一个最小的 C# 源文件只用到 3.5 的语法 using System; class Probe { static void Main() { Console.WriteLine(netfx35 ok: Environment.Version); } } | Out-File -FilePath C:\temp\probe.cs -Encoding ASCII # 用 3.5 自带的编译器编译并运行 C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe /out:C:\temp\probe.exe C:\temp\probe.cs C:\temp\probe.exeEnvironment.Version输出 2.0.50727 说明跑在 3.5 的运行时上3.5 的 CLR 版本号仍是 2.0这是正常现象别看到 2.0 就以为装错了。编译失败则说明引用程序集不全回到第 3 章重装不要试图手工往 GAC 里塞 dll。还有一条常被漏掉的检查事件日志。安装过程中的告警会落在系统日志里Get-EventLog -LogName System -Source Microsoft-Windows-Servicing -Newest 20能翻出来。如果里面出现「功能安装已回滚」说明安装过程后半段失败此时状态查询可能是 Available但重装前要先/Disable-Feature清状态。最后提醒一句空间装完 NetFx3 加上后续的组件清理C 盘至少要留 2GB 余量。我见过一台机器装完后磁盘剩 300MBWindows 更新一跑就蓝屏排查了两天才发现是空间问题。从那以后我每次装完 .NET 3.5都强制走一遍「状态 文件 编译运行」三步三步全过才允许业务上线宁可多花五分钟也不要在业务切换当天才发现功能是假的。希望帮到你。本文还有配套的精品资源点击获取