简介面向在 Windows Server 2012 R2 等服务器环境中部署 .NET Framework 3.5 受阻的运维与开发人员这份压缩包提供一套离线源与安装组件集合针对系统提示“找不到源文件”或要求指定还原功能文件位置等典型报错可作为本地修复的参考材料。包内共 1568 个文件以 720 个 DLL、180 个 RESX 资源、84 个 EXE、66 个 ASPX 页面及 60 个配置文件为主另含 SQL 脚本、浏览器配置、注册表与清单文件等整体约 99.19MB覆盖运行库、管理界面与安装支撑文件结构完整便于按需定位所需组件。已有 10328 人学习下载说明该方案在同类故障场景中具有较高参考价值。读者可据此理解 .NET 3.5 功能还原的文件组成排查源路径配置、组件缺失与安装源不匹配等问题并借助现成文件快速补齐离线安装所需内容减少在云服务器上反复尝试的时间成本。1. 一台离网服务器卡在 NetFx3这个 zip 到底解决哪一步SQL Server 安装程序跑到一半弹出一句「需要启用 Microsoft .NET Framework 3.5」点「下载并安装」转了两分钟回一个 0x800F0906换台机器干脆连进度条都不给。在 Windows Server 2012 上装 .NET 3.5被卡住的人远比想象中多尤其在机房、客户现场、内网隔离环境里——机器能连内网补丁服务器就是连不上公网。settled_.net3.5install.zip解决的就是这一步它不是安装程序而是从系统安装介质里取出来的 sxs 源文件包配合系统自带的 DISM把 NetFx3 这个「按需功能」从本地源启用起来全程不访问外网。适合手上有一台 2012 或 2012 R2、要装 SQL Server 或跑老业务系统、又拿不到公网出口的人。顺序是先把机制搞明白再动手敲命令最后看别人翻过的车。2. 先把机制搞清NetFx3 为什么不能像普通软件那样装2.1 按需功能与「源文件不在本机」的设计Windows Server 2012 里.NET Framework 3.5 不是一份可以双击安装的 exe而是一个叫 NetFx3 的可选功能Optional Feature。系统镜像里只留了一个状态位和一小部分元数据真正的组件包被抽走了启用时才去取——默认取的地方就是 Windows Update。这个设计在联网机器上很省事在机房里就是灾难机器没有公网出口系统跑到一半发现拿不到包吐一个 0x800F0906 就退出。对比一下就清楚了.NET Framework 4.5 在 2012 里是内置的核心功能Net-Framework-45-Core镜像里自带完整组件装上系统就能用3.5 走的是 side-by-side 路线为兼容老应用保留组件按需取。所以「4.5 装得上、3.5 装不上」不是系统坏了是两者机制不一样。DISM 的/Source参数就是干一件事告诉系统别去网上找去我指定的目录拿。离线包的价值全部落在这个参数上。2.2 sxs 目录里究竟是什么cab 清单与匹配规则系统安装介质的sources\sxs目录里躺着 NetFx3 的组件包主包名形如microsoft-windows-netfx3-ondemand-package.cab不同语言、不同版本的介质命名会有细微差异体积在几十 MB 量级。zip 离线包通常就是这一层内容原样打进去的或者在外面多包一层sxs目录。文件作用判断方式microsoft-windows-netfx3-ondemand-package.cab3.5 的核心组件负载存在即说明源可用语言资源类 cab本地化的错误消息、资源串命名带语言标识缺失通常不致命*.mum/ 清单文件描述包的身份、版本、依赖决定 DISM 能不能匹配上关键在于匹配规则DISM 不是「有 cab 就装」它会比对包的身份——版本号2012 和 2012 R2 不是一套、语言、架构。任何一项对不上就报 0x800F081F「找不到源文件」。所以从别的机器随手抓一个 sxs 目录过来十有八九是白忙。注意x86 客户端介质里的 sxs 不能拿去装 x64 服务器服务器只有 x64架构这一项最容易在跨机器拷贝时踩中。2.3 三种装法的取舍在线、挂 ISO、用现成离线包服务器管理器里勾选「.NET Framework 3.5 功能」点下一步这个动作背后默认走 Windows Update。机器能出公网这条路最省事出不去就必然失败而且失败信息不讲人话。方式前提耗时风险点服务器管理器在线安装机器能访问 Windows Update315 分钟看网速内网必失败被 WSUS 接管后还会报 0x800F0954挂载同版本 ISO指向sources\sxs手上有对应版本、对应语言的 ISO5 分钟左右挂载盘符变动、ISO 语言不符用现成 zip 离线包包与目标系统版本语言一致25 分钟解压层级多套一层、包被改过/Source:wim:...install.wim:1只有 WIM没有展开的 sxs510 分钟索引号写错、WIM 被拆分我一般的取舍是单台机器、手边正好有 ISO就直接挂 ISO批量部署或者远程只拿到一个 zip就用离线包。两者的命令完全一样区别只在/Source后面那串路径。3. 照着做从 zip 到 NetFx3 启用成功3.1 解压后先核对目录层级这一步很多人跳过然后卡在 0x800F0906 上怀疑人生。/Source必须指向 cab 文件所在的那一层目录本身不是它的上一层也不是它的下一层。# 以管理员身份打开 PowerShell # 解压到一个短路径别放在桌面或含中文的目录里 Expand-Archive -Path .\settled_.net3.5install.zip -DestinationPath D:\sxs_src -Force # 看清楚 cab 到底在第几层 Get-ChildItem -Path D:\sxs_src -Recurse -Filter *.cab | Select-Object FullName, {nMB;e{[math]::Round($_.Length/1MB,1)}}输出里如果看到D:\sxs_src\sxs\microsoft-windows-netfx3-ondemand-package.cab那么/Source就写D:\sxs_src\sxs如果看到的是D:\sxs_src\microsoft-windows-netfx3-ondemand-package.cab就写D:\sxs_src。判断标准只有一条cab 文件必须直接躺在这个目录下。-Force是为了覆盖已有解压结果避免上次残留的半截文件混进去-Recurse是必须的因为多套一层目录是这类 zip 包最常见的形态。这一步顺手记下 cab 的大小后面排查版本不匹配时能当证据用。3.2 DISM 三行命令与参数逐个拆:: 管理员权限的 CMD路径按上一步的实际结果替换 dism.exe /online /enable-feature /featurename:NetFx3 /all /Source:D:\sxs_src\sxs /LimitAccess参数含义什么时候要改/online操作当前运行的系统离线改 VHD 时换成/image:C:\mount/enable-feature启用功能卸载用/disable-feature/featurename:NetFx3功能名就是 3.5大小写不敏感别写成 NetFx35/all连同父功能、依赖一起启用建议始终带上否则核心装了组件仍缺/Source:本地组件源路径本次操作的核心指向 cab 所在目录/LimitAccess禁止向 Windows Update 请求内网必带省掉一段超时等待PowerShell 里有两种等价写法按习惯挑一种# 写法一面向可选功能和 DISM 参数一一对应 Enable-WindowsOptionalFeature -Online -FeatureName NetFx3 -All -Source D:\sxs_src\sxs -LimitAccess -NoRestart # 写法二面向服务器功能返回对象里带 RestartNeeded便于脚本判断 Install-WindowsFeature -Name Net-Framework-Core -Source D:\sxs_src\sxs-NoRestart的意义是把重启决策权留给自己而不是让命令中途把机器拉起来批量脚本里这个参数必须加否则装到第三台机器时你正在等的那台突然重启了。返回码 3010 表示成功但需要重启不是失败脚本里要单独判断别当成错误直接退出。命令跑起来后进度条会停在某个百分比一小会儿属于正常现象它在解 cab、注册组件。看到「操作成功完成」再动下一步。3.3 装完怎么验注册表、DISM、程序集三条路「操作成功完成」不等于真的能用三条路交叉验证最省心。:: 1) 功能状态期望 State : Enabled dism.exe /online /get-featureinfo /featurename:NetFx3 :: 2) 注册表期望 Install 0x1 reg query HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5 /v Install :: 3) 程序集与工具链是否存在期望直接出版本号 %windir%\Microsoft.NET\Framework64\v3.5\MSBuild.exe -version版本号形如3.5.30729.xxxx能打出来说明不只注册表项写上了实际的程序集也落盘了。64 位系统上 32 位程序走的是Framework目录、注册表在WOW6432Node下如果老应用是 32 位的把上面两处路径里的Framework64、SOFTWARE相应替换再查一遍。PowerShell 侧还有一条更快的Get-WindowsFeature -Name Net-Framework-Core | Select-Object Name, InstallStateInstallState是Installed就收工。如果显示Removed说明负载被清过得靠/Source重新装显示Available则是压根没启用。3.4 SQL Server 装之前的连带检查3.5 只是第一关。真到装 SQL Server 那一步还有几个东西会连着报错提前查完能少跑一轮。第一是 IIS 相关组件。要用 Reporting Services 的话IIS-ASPNET对应 3.5 时代的 ASP.NET 注册和IIS-NetFxExtensibility得一起上单独装 3.5 不会自动帮你打开这些。命令可以合并成一条# 一次性把 Web 服务器、ASP.NET 扩展和 3.5 都指到同一份源 Install-WindowsFeature -Name Web-Server, Web-Asp-Net, Web-Asp-Net45, Net-Framework-Core -Source D:\sxs_src\sxs第二是安装顺序带来的注册问题。先开 IIS 后装 .NET 4.xASP.NET 的 ISAPI 注册可能没做全表现为站点一访问就 500.21。这种时候补一次注册%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_regiis.exe -i。3.5 这一侧在 2012 上不用 aspnet_regiis那个工具在新系统里已经不被推荐走功能开关即可。第三是环境项安装账户要有本地管理员权限、系统盘和临时目录留够空间、机器名不要太长、%TEMP%路径别指向网络位置。这几项和 3.5 无关但报错信息经常被误读成 3.5 的问题。4. 避坑记录五类翻车与排查顺序4.1 报 0x800F0906源指向了上一级目录现象命令回车后进度条走一点报 0x800F0906「无法下载源文件」但目录里明明有 cab。原因/Source指到了 cab 的上一层。DISM 只在指定目录的第一层找包不会往下钻。zip 包里多套一层sxs目录是最常见的成因。解决回到 3.1 那一步用Get-ChildItem -Recurse -Filter *.cab看清实际层级把/Source调整到 cab 直接所在的那一层。别试图靠..\或长路径绕过直接写绝对路径最省事。4.2 报 0x800F081F版本或语言对不上现象目录层级没错依旧报 0x800F081F「找不到源文件」。原因包的身份和目标系统不匹配。2012 与 2012 R2 的组件版本不是一套英文介质里的 sxs 拿到中文系统上语言资源对不上同样会被拒。跨机器拷来的包尤其容易出这个问题。解决换用与目标系统版本、语言一致的介质。判断系统版本用systeminfo | findstr /B /C:OS Name /C:OS Version把结果和包的来源对一遍。实在拿不准就挂载同版本 ISO直接指向sources\sxs。4.3 组策略与 WSUS 把源开关关掉现象加了/LimitAccess还是失败错误码是 0x800F0954 或 0x800F0907换台机器同样的命令却能过。原因域环境里「指定可选组件安装和组件修复的设置」这条策略被配成了从 WSUS 取包或者干脆禁用了 Windows Update 作为源。系统宁可从被指定的位置拿也不认你给的本地路径。解决先在本地策略里看一眼这条设置gpedit.msc→ 计算机配置 → 管理模板 → 系统。临时排障可以把它改成「未配置」装完再恢复长期方案是让管理员把这份 sxs 发布到内网源上。改完策略执行gpupdate /force再重试。4.4 路径、盘符与权限的隐形问题现象命令语法完全正确返回「拒绝访问」或者干脆没反应。原因CMD 不是管理员权限或者/Source写的是映射的网络盘符——DISM 在提升后的上下文里看不到当前用户映射的盘又或者路径里有中文、空格没加引号。解决确认窗口标题带「管理员」网络位置改用 UNC 路径\\主机\共享\sxs并保证计算机账户对该共享有读权限路径尽量用D:\sxs这种短的纯英文目录含空格的路径整体加英文双引号。4.5 3.5 装上了SQL Server 还是报错现象三条验证命令全过SQL Server 安装程序依旧提示缺少 .NET 3.5或者装到一半回滚。原因多为一台机器上装过再卸载留下的残留状态或者安装程序读的是 32 位视图下的注册表键而当前只验证了 64 位那一份。也有可能是安装介质本身被拦截比如从网络位置直接运行 setup.exe。解决先查WOW6432Node下对应的NDP\v3.5键再确认%windir%\Microsoft.NET\Framework\v3.5和Framework64\v3.5两个目录都在。仍不行就把安装介质复制到本地磁盘再运行别从共享路径直接执行。5. 进阶把它固化成可复用的离线源与一键脚本单台机器装完就完事了机房场景往往是一批机器。我习惯把 sxs 目录放到一台内网文件服务器上共享权限给「Domain Computers」读之后所有机器统一指向 UNC 路径省掉反复拷贝。共享路径在 DISM 下要按计算机账户鉴权这也是很多人用映射盘符失败、换 UNC 就通的原因。如果手上只有 ISO连解压都懒得做可以直接让/Source指向 WIM 里的索引:: 不需要挂载或展开直接读 install.wim 的第 1 个索引 dism.exe /online /enable-feature /featurename:NetFx3 /all ^ /Source:wim:E:\sources\install.wim:1 /LimitAccess索引号写错会直接报找不到源先用dism /get-wiminfo /wimfile:E:\sources\install.wim确认。这个写法的好处是介质保持只读不怕被人误改。批量场景我一般用带前置校验的脚本先判断再动手避免在已经装好的机器上白跑一遍# 管理员权限运行先校验源再判断状态最后安装 $Source \\fileserver\sxs\2012r2 $cab Join-Path $Source microsoft-windows-netfx3-ondemand-package.cab if (-not (Test-Path $cab)) { throw 源不可用$cab 不存在检查共享权限或目录层级 } $state (Get-WindowsFeature -Name Net-Framework-Core).InstallState if ($state -eq Installed) { Write-Host 已启用跳过; return } $r Install-WindowsFeature -Name Net-Framework-Core -Source $Source if ($r.Success -and $r.RestartNeeded -eq Yes) { Write-Host 安装成功需重启 } elseif ($r.Success) { Write-Host 安装成功 } else { Write-Host 失败退出码 $($r.ExitCode) }脚本里三处判断各有分工Test-Path把源问题挡在最前面比装到一半失败好排查InstallState避免重复安装RestartNeeded单独判是因为返回 3010 常被误当成错误。退出码对照可以贴在脚本注释里排障时不用现查退出码含义处理0成功继续后续步骤3010成功需重启安排重启窗口别立即重启生产机0x800F0906找不到/无法获取源文件查/Source层级0x800F081F源里没有匹配的包查版本、语言、架构0x800F0954策略禁止从 Windows Update 取源查组策略与 WSUS 配置0x800F0922系统保留分区空间不足清理或扩容后再试有一个细节值得单独提装完之后别急着删源目录。后续打补丁、做组件修复dism /online /cleanup-image /restorehealth /source:...时还会用到同一份源删了就得重新找介质。我吃过一次亏客户现场没网、源被清掉为了修一个组件损坏的机器硬是让人从机房送了一趟 U 盘过去。从那以后我每次做这类离线部署都强制走一遍「校验源、判断状态、安装、三条命令验证、保留源目录」这套动作一步不省。上面这些命令和坑都是这么攒下来的希望帮到你。本文还有配套的精品资源点击获取