
简介这份离线安装包面向需要在无外网环境中为 Windows Server 2012 R2 部署或更新 IIS 的 IT 管理员与运维人员解决内网、隔离机房或严格网络策略下无法在线拉取系统组件的问题。压缩包共 1568 个文件约 99.04MB以 dll 动态库、resx 资源文件、exe 可执行程序为主辅以 aspx 页面、config 配置、sql 脚本、browser 定义及 gif、ini、tlb 等配套文件完整覆盖 IIS 角色与 SxS 组件存储所需内容。已有 572 人学习关注。资源内含 Web 服务器、应用程序池、身份验证、URL 重写与 FTP 服务等模块的组件文件配合 DISM 命令即可离线添加角色并通过 Get-WindowsFeature 校验安装结果适合希望减少外网依赖、保证服务器稳定与安全的中高级运维人员参考使用。1. 内网机装 IIS 的最后一公里为什么离线包比在线安装更靠谱上周帮一个做政务内网项目的朋友处理一台 Windows Server 2012 R2 的机器需求很朴素把 IIS 装起来跑一个内部管理站点。结果服务器管理器 → 添加角色和功能 → Web 服务器(IIS)一路点下去卡在“正在安装”进度条上十几分钟最后弹出一个 0x800f0906 的报错。原因不复杂——这台机器完全断网而 Windows Server 2012 R2 的 IIS 角色安装本质上是走DISM从系统组件存储WinSxS或 Windows Update 拉取源文件源不可达就直接失败。这就是“iis离线”这个需求真实存在的场景内网、隔离网、无外网出口的服务器必须用离线源sxs 目录或 install.wim 挂载来喂给 DISM。这份 Windows Server 2012 R2 的 IIS 离线安装包解决的就是“角色装不上、报错看不懂、源路径配不对”这三件事。适合谁做内网交付的运维、需要给老系统补 IIS 的开发者、以及被 0x800f0906 折磨过一轮的人。下面按“先搞懂 DISM 怎么找源 → 再动手配 → 再排错”的顺序拆。2. 先搞懂 DISM 找源的逻辑IIS 角色到底从哪来2.1 角色安装不是“复制文件”是组件按需装配很多人以为装 IIS 就是把一堆文件拷到C:\Windows\System32\inetsrv其实不是。Windows Server 2012 R2 的角色和功能是**按需功能Features on Demand**模型系统里预置了组件的“清单”但实际二进制文件可能被剥离到install.wim的sxs目录里或者保留在本地WinSxS中。当你勾选“Web 服务器(IIS)”时服务器管理器底层调用的是# 服务器管理器图形界面背后实际执行的等价命令 dism /online /enable-feature /featurename:IIS-WebServerRole /all /source:D:\sxs /limitaccess这里三个参数是命门/featurename指定角色名/all表示连带启用所有父级依赖IIS 有一长串子功能漏一个站点就跑不起来/source指向离线源目录/limitaccess强制 DISM不要去 Windows Update 找文件——内网环境不加这个DISM 会先尝试联网、超时后再回落白白多等好几分钟甚至直接报错。所以离线包的本质不是“安装程序”而是一份与目标系统版本严格匹配的 sxs 源文件集合。版本对不上DISM 会报 0x800f081f源文件找不到或 0x800f0906源文件损坏/不匹配。2.2 为什么必须是“同版本同补丁级别”的源这是最容易翻车的地方。Windows Server 2012 R2 的组件存储和系统补丁级别绑定一台打了 2020 年累积更新的机器它的组件清单版本号比 RTM 原版高如果你拿 RTM 的 install.wim 去当源DISM 会认为“源里的组件版本低于系统当前版本”拒绝装配。常见做法是离线包的 sxs 目录要来自与目标机相同或更高补丁级别的镜像。实操上我一般会先查目标机的版本# 查看当前系统版本与安装日期判断补丁级别 systeminfo | findstr /B /C:OS 名称 /C:OS 版本 /C:系统制造商 # 更精确地看组件存储版本 dism /online /get-currentedition如果目标机是较新的累积更新级别而你手上只有 RTM 源有两个选择一是用目标机同批次的镜像重新提取 sxs二是先卸载高版本组件再装不推荐容易把系统搞坏。离线包的价值就在于它通常已经按常见补丁级别整理好了 sxs省去你自己挂载 wim 提取的步骤。2.3 离线包的目录结构该长什么样一份能直接用的 IIS 离线源目录结构大致是路径内容作用\sxs\组件 cab 文件如Microsoft-Windows-IIS-WebServer-*.cabDISM 的/source指向这里\sxs\manifests\组件清单.mum文件DISM 靠它匹配功能名\install.wim可选完整系统镜像需要时挂载后从\sxs提取\readme.txt版本与补丁级别说明核对源与目标机是否匹配拿到包后第一件事不是急着装而是核对 sxs 里的 cab 文件名前缀版本和systeminfo的输出是否对得上。对不上就先别装否则装到一半失败清理残留比重新装还麻烦。3. 动手装从挂载源到验证站点跑通3.1 用 DISM 命令行装别迷信图形界面图形界面在离线场景下反馈太差报错只有一个代码。直接用管理员权限的 PowerShell 或 CMD 走 DISM能看到每一步在干什么。假设离线包解压到了D:\iis-offline\# 第一步先只做“检查”不实际安装确认源能被识别 dism /online /enable-feature /featurename:IIS-WebServerRole /all ^ /source:D:\iis-offline\sxs /limitaccess # 如果上一步报错先用 /get-featureinfo 看这个功能依赖哪些子项 dism /online /get-featureinfo /featurename:IIS-WebServerRole/get-featureinfo会列出该角色的所有子功能IIS-WebServer、IIS-CommonHttpFeatures、IIS-StaticContent 等以及它们的当前状态已启用/已禁用/已禁用且带父级。这一步是排错的地基如果某个子项显示“已禁用且带父级”说明它的父功能没装/all就是用来一次性把依赖链拉齐的。装完主角色后再按需补子功能。比如要跑 ASP.NET 站点还得单独启用# 启用 ASP.NET 4.5 相关子功能注意功能名大小写不敏感但拼写要准 dism /online /enable-feature /featurename:IIS-ASPNET45 /all ^ /source:D:\iis-offline\sxs /limitaccess dism /online /enable-feature /featurename:IIS-NetFxExtensibility45 /all ^ /source:D:\iis-offline\sxs /limitaccess参数说明^是 CMD 的续行符PowerShell 里换成反引号/all一定要带否则子功能不会自动启用/limitaccess在内网必带。每装一个功能DISM 会输出进度百分比和最终结果码结果码 0 才是成功其他都要停下来查。3.2 用 PowerShell 批量启用适合一次配多台如果要在多台机器上重复这套动作写成脚本更稳。Enable-WindowsOptionalFeature是 DISM 的 PowerShell 封装# 批量启用 IIS 核心功能源路径统一走变量 $source D:\iis-offline\sxs $features ( IIS-WebServerRole, IIS-WebServer, IIS-CommonHttpFeatures, IIS-StaticContent, IIS-DefaultDocument, IIS-HttpErrors, IIS-ASPNET45 ) foreach ($f in $features) { Write-Host 正在启用: $f -ForegroundColor Cyan $r Enable-WindowsOptionalFeature -Online -FeatureName $f -All -Source $source -LimitAccess -ErrorAction Stop if ($r.RestartNeeded) { Write-Host $f 需要重启后生效 -ForegroundColor Yellow } }逻辑说明-All对应 DISM 的/all-LimitAccess对应/limitaccess-ErrorAction Stop让脚本在第一个失败处停下而不是静默跳过——批量场景下静默跳过最坑你以为装好了结果站点起不来。RestartNeeded为真时记下来最后统一重启一次别每装一个就重启。3.3 装完必须验证三个检查点装完不等于能用。我一般按这三步验# 检查点1功能状态是否为 Enabled dism /online /get-featureinfo /featurename:IIS-WebServerRole | findstr /C:状态 # 检查点2W3SVC 服务是否在跑 sc query W3SVC # 检查点3默认站点是否响应 curl -I http://localhostsc query W3SVC返回STATE : 4 RUNNING才算服务起来了curl -I返回HTTP/1.1 200 OK说明默认站点C:\inetpub\wwwroot能访问。如果服务没起先看事件查看器里System日志的W3SVC来源常见是端口 80 被占用或applicationHost.config损坏。三个检查点全过才算这份离线包真正落地成功。4. 避坑与排查0x800f0906 之外还有哪些雷4.1 报 0x800f0906源文件与系统版本不匹配现象DISM 跑到一半报0x800f0906提示“无法下载源文件”或“源文件损坏”。原因最常见的是离线包的 sxs 来自 RTM 原版而目标机已经打了较新的累积更新组件版本号对不上其次是 sxs 目录里缺了某个子功能的 cab/all拉依赖时找不到。解决先用dism /online /get-featureinfo确认缺的是哪个子功能再核对 sxs 里有没有对应 cab版本不匹配就换同补丁级别的源别硬装。我见过有人反复重试十几次其实换一份匹配的源一次就过。4.2 报 0x800f081f源路径写错或权限不足现象0x800f081f提示“找不到源文件”。原因/source路径写错比如多了一层目录、盘符不对或者 DISM 进程没有读取该目录的权限网络共享路径尤其常见。解决把源目录放到本地磁盘用绝对路径先手动dir D:\iis-offline\sxs确认能看到 cab 文件如果是共享路径先映射成本地盘符再试。DISM 对 UNC 路径的支持不稳定这是血泪经验。4.3 装完 IIS 管理器打不开提示 MMC 错误现象角色显示已安装但inetmgr启动报 MMC 管理单元错误。原因IIS-ManagementConsole子功能没启用——/all有时因为源里缺管理控制台的 cab 而跳过它但主角色仍显示成功。解决单独补装IIS-ManagementConsole和IIS-ManagementScriptingTools再重启 MMC。这个坑很隐蔽因为主角色状态是 Enabled容易误判。4.4 站点能访问但 ASP.NET 页面报 500.19现象静态页正常.aspx页面报HTTP 错误 500.19。原因IIS-ASPNET45或IIS-NetFxExtensibility45没装全或者装了但没注册到 IISaspnet_regiis -i没跑。解决先确认两个功能都是 Enabled再以管理员身份跑C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_regiis.exe -i。注意 2012 R2 上这个命令有时提示已弃用但注册动作仍然有效。4.5 离线装完重启后功能“回退”现象装完显示成功重启后部分子功能又变回 Disabled。原因安装过程中有功能标记了RestartNeeded但重启前又执行了其他 DISM 操作导致事务未提交完整。解决一次装完、一次重启中间不要穿插其他角色安装重启后再用get-featureinfo全量核对一遍状态。这个属于玄学范畴但按“装完即重启、重启即核对”的节奏走基本不会遇到。5. 进阶把离线包做成可复用的内网部署基线单台机器装完只是开始。真正省事的是把这份离线包 一套脚本固化成内网部署基线新机器到手跑一遍就齐活。我的做法是建一个deploy-iis.ps1把源路径、功能清单、验证步骤全写进去配合一个features.txt清单文件换机器只改源路径变量。# deploy-iis.ps1 核心片段读清单 装 验 $source $args[0] # 传入 sxs 路径如 D:\iis-offline\sxs $list Get-Content .\features.txt foreach ($f in $list) { if ([string]::IsNullOrWhiteSpace($f)) { continue } Enable-WindowsOptionalFeature -Online -FeatureName $f.Trim() -All -Source $source -LimitAccess -ErrorAction Stop | Out-Null } # 统一验证服务 端口 if ((Get-Service W3SVC).Status -ne Running) { Start-Service W3SVC } $probe Invoke-WebRequest -Uri http://localhost -UseBasicParsing -TimeoutSec 10 Write-Host 默认站点响应码: $($probe.StatusCode)features.txt里按行写功能名一行一个注释用#开头。这样换一台机器只要源版本对得上一条命令跑完验证也自动做了。参数上唯一要盯的是-Source必须指向本地绝对路径别传网络路径。还有一个容易被忽略的点离线包要跟着补丁级别走。内网机器如果后续打了累积更新原来的 sxs 可能又对不上了。我的习惯是每次给内网机器做补丁基线时同步更新一份对应级别的 sxs 源归档时在目录名里带上补丁级别比如sxs-2020-01下次装 IIS 直接按systeminfo的输出挑对应目录。从那以后我每次给内网机器装角色都强制先跑一遍systeminfo核对源版本、再跑get-featureinfo核对依赖最后才动手装——这三步走完0x800f0906 基本就绝迹了。希望帮到你。本文还有配套的精品资源点击获取