☰
Windows Server 2012 R2 IIS离线安装与DISM排错
2026/10/27 16:41:46 网站建设 项目流程

简介:面向企业 IT 管理员与 Windows 服务器运维人员的 IIS 离线部署素材,用于在 Windows Server 2012 R2 上无法连接外网时添加或更新 IIS Web 服务器角色。压缩包共 1568 个文件、约 99.04MB,其中 720 个 dll 运行库、180 个 resx 资源文件、84 个 exe 工具程序构成主体,辅以 66 个 aspx 管理页面、60 个 config 配置文件与 56 个 sql 脚本,另有 browser 定义、master 母版页、mui 多语言资源等,基本覆盖 IIS 管理控制台、应用程序池、身份验证、URL 重写、性能日志与 FTP 服务等组件的完整依赖。解压后可直接作为 DISM 命令的 Source 组件源完成离线安装,也便于用 Get-WindowsFeature 核对角色启用状态,适合内网封闭机房、批量服务器初始化与教学实验环境搭建,帮助读者省去逐台联网拉取 sxs 组件的重复劳动。目前已有 572 人学习下载。

1. 先别急着找 setup.exe:Windows Server 2012 R2 的 IIS 离线安装包长什么样

内网那台 Windows Server 2012 R2 要挂个内部站点,搜「IIS 离线安装包」下载回来解压,翻到底也没看见 setup.exe,只有一堆 .mum 和 .cab,文件名长得像IIS-WebServerRole-Package~31bf3856ad364e35~amd64~~6.3.9600.16384.mum。不少人到这一步就开始怀疑包是不是坏的。其实没坏——IIS 8.5 在这套系统里是服务器角色,从来不是独立安装程序,所谓 IIS 离线安装,本质是把安装镜像sources\sxs里的功能源喂给 DISM 或者 Install-WindowsFeature。装不对的后果很直接:0x800f0906、0x800F0954 轮着报,IIS 管理器点不开,站点起不来,最后只能重装系统。下面按我实际装过的顺序,把版本核对、源准备、命令、配置和报错处理记一遍。

2. 备料到什么程度才算够:sxs 目录、版本号和语言三样必须对上

离线安装最容易翻车的地方不是命令写错,而是源本身就有问题。我见过太多次「命令一模一样,换台机器就报 0x800f0906」,最后查出来是 sxs 目录从别的版本镜像里拷的,或者只拷了一半。所以动手之前,先把源摸清楚。

2.1 离线安装包的本质是 sources\sxs,不是 exe

把 Windows Server 2012 R2 的标准安装镜像挂载或解压,sources目录下有两样东西值得注意:install.wim和sxs文件夹。sxs里放的是系统所有可选功能的组件包,一堆.mum(描述文件)加对应的.cab(实际负载)。IIS 的每一个子功能,在这套目录里都有自己的一组文件。DISM 干的活就是读 .mum、解 .cab、注册到组件存储里。

所以「离线源」有两种形态,我都用过:

一种是直接把整个sources\sxs目录拷到目标机器的本地盘,比如D:\sources\sxs,然后/Source指向它。这种方式最省事,缺点是目录里包很多,复制慢,占空间,而且容易漏拷。

另一种是挂载install.wim,把挂载点下的Windows\WinSxS当作源。适合磁盘紧张或者要反复装多台机器的场景:

:: 先看镜像里有几个索引,Standard 和 Datacenter 的索引不一样 dism /Get-WimInfo /WimFile:D:\sources\install.wim :: 按索引挂载到本地目录,只读即可 dism /Mount-Wim /WimFile:D:\sources\install.wim /Index:1 /MountDir:C:\ws2012src

/Index要和目标机器实际版本对应,Standard 装 Standard 的索引,Datacenter 装 Datacenter 的。挂载完之后/Source写C:\ws2012src\Windows\WinSxS。用完记得卸载,不然挂载点会一直占着,下次再挂同一个 wim 会提示挂载冲突:

:: 装完就卸,/Discard 表示不保存改动 dism /Unmount-Wim /MountDir:C:\ws2012src /Discard

提示:挂载目录不要放在系统盘根目录下随便建的临时文件夹里,有些安全软件会锁目录导致卸载失败。我一般固定用C:\ws2012src,装完立刻卸。

2.2 三条命令核对版本、语言和镜像索引

版本对不上是离线装 IIS 最隐蔽的坑。Windows Server 2012 是 6.2.9200,2012 R2 是 6.3.9600,两者功能包完全不通用。机器上先确认:

:: 只看这三行,OS Version 必须是 6.3.9600 systeminfo | findstr /B /C:"OS Name" /C:"OS Version" /C:"System Type"

语言同样要对。中文系统配英文 sxs,装到一半就会报版本或语言不匹配。系统语言这么看:

:: 输出里 System Locale 和 UI Language 都要看一眼 dism /online /get-intl

再看源这边的语言标记和版本号,直接读文件名就行:

# 取前几个 mum 看命名规则,倒数第二段是语言,最后一段是版本 Get-ChildItem D:\sources\sxs -Filter *.mum | Select-Object -First 5 -ExpandProperty Name # 统计总数和语言分布,数量明显偏少说明目录没拷全 $mum = Get-ChildItem D:\sources\sxs -Filter *.mum $mum.Count $mum | Group-Object { ($_.Name -split '~')[-2] } | Select-Object Name, Count

正常的 2012 R2 中文源,语言段应该是zh-CN,版本段是6.3.9600.xxxxx。如果统计出来语言段混杂着en-US,或者版本段出现6.2.9200,这个源就不能用,别抱侥幸。

2.3 把功能名清单先列出来,别边装边猜

IIS 在 2012 R2 里拆得很细,一个「Web 服务器」背后是二三十个功能名。DISM 的功能名和 PowerShell 的功能名还不是同一套,写错了会直接返回 0x800f080c(功能名未知)。我习惯先把要装的列成表,对着表装,装完对着表核。

DISM 功能名PowerShell 功能名作用是否必装
IIS-WebServerRoleWeb-ServerIIS 角色根是
IIS-WebServerWeb-WebServerWeb 服务器核心是
IIS-CommonHttpFeaturesWeb-Common-Http常见 HTTP 功能父级是
IIS-StaticContentWeb-Static-Content静态文件是
IIS-DefaultDocumentWeb-Default-Doc默认文档是
IIS-DirectoryBrowsingWeb-Dir-Browsing目录浏览按需
IIS-HttpErrorsWeb-Http-Errors自定义错误页是
IIS-HttpLoggingWeb-Http-Logging访问日志是
IIS-RequestFilteringWeb-Filtering请求筛选是
IIS-HttpCompressionStaticWeb-Stat-Compression静态压缩按需
IIS-ASPNET45Web-Asp-Net45ASP.NET 4.5按需
IIS-NetFxExtensibility45Web-Net-Ext45.NET 扩展性按需
IIS-ISAPIExtensionsWeb-ISAPI-ExtISAPI 扩展按需
IIS-ManagementConsoleWeb-Mgmt-ConsoleIIS 管理器是
IIS-ManagementScriptingToolsWeb-Scripting-Toolsappcmd 命令行是

「按需」那几项别一股脑全上。目录浏览开了等于把文件列表暴露出去,ASP.NET 装了但没用到只是白白多占组件存储。反过来,表里标「是」的一个都不能少,少一个后面站点就跑不起来。

3. 用 DISM 启用 IIS 8.5:/Source 和 /LimitAccess 到底在管什么

命令本身不长,但参数的含义如果不清楚,出问题时就不知道从哪改。这一章把三个参数拆开讲,再给两套可直接抄的写法。

3.1 三个参数的职责:/Source、/LimitAccess、/All

/Source指定功能源路径,DISM 会去这个目录里找 .mum 和 .cab。注意它指到的是目录本身,不是 wim 文件,除非你用WIM:路径:索引那种内联写法。我一般还是先挂载成目录,出问题时能直接进目录看某个 cab 在不在。

/LimitAccess是离线场景的关键。不加它,DISM 在本地源里找不到文件时会回退去连 Windows 更新或内部的更新服务器,断网机器上就是干等超时,然后抛一个看着像源有问题的错误。加上之后它只用/Source指定的源,不再往外连。

/All启用指定功能的所有父功能。注意方向:启用子功能会自动带上父功能,反过来启用父功能不会自动装子功能。所以/All并不等于「把 IIS 全装」,它只是补齐父级依赖。真正要装哪些子功能,还是得显式列出来。

注意:/All和显式子功能列表一起写容易产生误解,我现在的习惯是显式列子功能,不写/All,清单可控,出了问题也容易定位是哪个包缺了。

3.2 一条命令装全核心功能

Windows Server 2012 R2 的 cmd 里,功能名重复写多个/featurename是合法的,一行装完:

dism /online /enable-feature ^ /featurename:IIS-WebServerRole ^ /featurename:IIS-WebServer ^ /featurename:IIS-CommonHttpFeatures ^ /featurename:IIS-StaticContent ^ /featurename:IIS-DefaultDocument ^ /featurename:IIS-HttpErrors ^ /featurename:IIS-HttpLogging ^ /featurename:IIS-RequestFiltering ^ /featurename:IIS-ManagementConsole ^ /featurename:IIS-ManagementScriptingTools ^ /source:D:\sources\sxs /limitaccess

^是 cmd 的续行符,复制到一行里去掉即可。执行过程中会逐个功能打进度,最后是「操作成功完成」。中途如果卡在某个功能超过几分钟不动,基本就是源里缺这个功能的 cab,别硬等,Ctrl+C 中断后去看日志。

加载了 ASP.NET 的站点再补两条:

:: 补 ASP.NET 4.5 和对应扩展性组件,源还是同一个 dism /online /enable-feature ^ /featurename:IIS-ASPNET45 ^ /featurename:IIS-NetFxExtensibility45 ^ /featurename:IIS-ISAPIExtensions ^ /featurename:IIS-ISAPIFilter ^ /source:D:\sources\sxs /limitaccess

这里有个容易忽略的点:IIS-ASPNET45依赖 .NET Framework 4.5 的运行时,2012 R2 自带 4.5,所以这条路是通的。但如果站点还依赖 .NET 3.5,那得另外单独装NetFx3,IIS 那边的IIS-ASPNET只是壳,运行时不在 IIS 的功能源里。这是两个不同的事,混在一起查很浪费时间。

3.3 PowerShell 等价写法与 Server Core 上的差异

有 PowerShell 就直接用Install-WindowsFeature,功能名是另一套(Web-Server 而不是 IIS-WebServerRole),写错会立刻报错,反而好排查:

# 功能名用数组列出,避免一行太长漏项 $features = @( 'Web-Server', 'Web-Common-Http', 'Web-Static-Content', 'Web-Default-Doc', 'Web-Http-Errors', 'Web-Http-Logging', 'Web-Filtering', 'Web-Mgmt-Console', 'Web-Scripting-Tools' ) # -Source 指向本地 sxs,-IncludeManagementTools 一并带上管理器 Install-WindowsFeature -Name $features ` -Source 'D:\sources\sxs' ` -IncludeManagementTools ` -Restart:$false

-Source只在需要时传,如果组件存储里已经有对应负载,不传也能装。-IncludeManagementTools是个快捷开关,等价于把Web-Mgmt-Console和Web-Scripting-Tools一起加上,用 DISM 的话没有这个参数,必须手动列。-Restart:$false表示不自动重启,因为装 IIS 一般不需要重启,重启反而是浪费。

Server Core 上差别不大,DISM 和 Install-WindowsFeature 都能用,但没有 inetmgr 图形界面,只能靠 appcmd 和远程管理。真要远程管,得额外装Web-Mgmt-Service,然后走 IIS 远程管理服务那条路,这部分不在离线包范围内,别指望 sxs 里能解决。

3.4 装完先看状态,别急着开站点

命令返回成功不等于功能真的装上了。装完立刻核一遍:

# InstallState 必须是 Installed Get-WindowsFeature -Name Web-Server, Web-Mgmt-Console, Web-Scripting-Tools | Select-Object Name, InstallState

DISM 侧也能查单个功能的详细信息:

:: 输出里 State 一行是 Enabled 才算装好 dism /online /get-featureinfo /featurename:IIS-WebServerRole

如果InstallState是Available而不是Installed,说明刚才那条命令其实没生效,多半是静默失败,去C:\Windows\Logs\DISM\dism.log搜失败的功能名。这一步别省,我吃过亏——命令返回「操作成功完成」但实际只装了一半,后面站点起不来查了一下午,最后发现是某个子功能根本没进组件存储。

4. 装完不等于能用:端口、应用池和日志目录的最小配置

角色装上了,http://localhost大概率还是打不开。这一步是做运行侧的最小可用配置,不是可选项。

4.1 防火墙放行 80 和目标端口

Windows Server 2012 R2 默认开着防火墙,IIS 装完并不会自动加规则。手动加一条:

:: 只对域和专用配置文件放行 80,公网配置文件保持关闭 netsh advfirewall firewall add rule name="IIS-HTTP-80" dir=in action=allow protocol=TCP localport=80 profile=domain,private :: 确认规则存在 netsh advfirewall firewall show rule name="IIS-HTTP-80"

profile这个参数值得说。不加的话规则会应用到所有配置文件,包括公网那个,等于把自己暴露出去。内网机器一般写domain,private就够。改动过端口的话,localport跟着改,别只改 IIS 不改防火墙。

放行之前先确认 80 没被别人占着:

:: 看 80 端口的占用情况,PID 4 通常是系统进程占的 HTTP.sys netstat -ano | findstr :80 :: 如果是 HTTP.sys 占用,看具体是谁注册的 URL netsh http show servicestate | findstr /I ":80"

PID 4 占 80 但站点起不来,多半是 WSUS 或者某个服务先在 HTTP.sys 上注册了 URL 前缀,这种情况要么挪端口,要么把那个服务停掉,光改 IIS 绑定解决不了。

4.2 应用池与站点绑定的三行 appcmd

默认站点用的是 DefaultAppPool,生产上不建议直接用。建一个独立的池:

:: 新建应用池,.NET 4.0 + 集成模式,不开 32 位兼容 appcmd add apppool /name:"DemoPool" /managedRuntimeVersion:"v4.0" /managedPipelineMode:"Integrated" /enable32BitAppOnWin64:"false" :: 把默认站点切到新池 appcmd set app "Default Web Site/" /applicationPool:"DemoPool" :: 追加一个 8080 的绑定,原来的 80 保留 appcmd set site /site.name:"Default Web Site" /+bindings.[protocol='http',bindingInformation='*:8080:']

managedRuntimeVersion这里填v4.0,即使装的是 .NET 4.5,池的版本标识还是 v4.0,这是历史遗留,别填 v4.5 找不到。managedPipelineMode选 Integrated 还是 Classic 取决于应用,老系统迁移过来的多半要 Classic,这个改错了表现是静态页能打开、动态页 500。enable32BitAppOnWin64只有当站点真的加载 32 位组件时才开,开了之后内存占用翻倍,能不开就不开。

改完用appcmd list apppool和appcmd list site确认,绑定追加的语法比较绕,/+后面跟的是整个bindings集合元素的属性表达式,少一个引号就报语法错误。

4.3 默认文档、目录浏览和静态压缩

默认文档列表 2012 R2 自带Default.htm、index.html、iisstart.htm这几项。如果站点的入口文件名不在列表里,访问根路径就是 403.14。追加一条:

:: 把 home.html 追加进默认文档列表 appcmd set config "Default Web Site" /section:defaultDocument /+"files.[value='home.html']" :: 目录浏览只给上传目录开,不要整站开 appcmd set config "Default Web Site/uploads" /section:directoryBrowse /enabled:true

目录浏览是血泪经验:整站开等于把目录结构全暴露,做静态资源下载站可以,做业务系统千万别。静态压缩如果装了IIS-HttpCompressionStatic,还要在配置里确认staticCompression的doStaticCompression是 true,光装功能不会自动生效。

4.4 日志目录与 IIS_IUSRS 权限

默认日志在C:\inetpub\logs\LogFiles,系统盘紧张的话挪走:

:: 全站默认日志目录改到 D 盘 appcmd set config /section:system.applicationHost/sites /siteDefaults.logFile.directory:"D:\iislogs"

挪完必须给权限,否则日志写不进去,站点本身不报错,但排查问题时没日志可看,等于黑匣子:

:: 站点根目录给读和执行权限 icacls D:\wwwroot /grant "IIS_IUSRS:(OI)(CI)(RX)" /T :: 日志目录给修改权限,IIS 要往里写 icacls D:\iislogs /grant "IIS_IUSRS:(OI)(CI)(M)" /T

(OI)(CI)表示对象继承和容器继承,(RX)是读加执行,(M)是修改。应用池标识是ApplicationPoolIdentity,它属于IIS_IUSRS组,所以给组授权就够了,不用单独给虚拟账户授权。如果站点要写文件,再把写入目录单独给(M),别图省事整个站点目录给完全控制。

5. 常见问题排查:五个把离线装 IIS 卡死的坑

下面这五条是我在不同机器上真踩过的,按「现象、原因、解决」记,方便对照。

5.1 报 0x800f0906:源目录里的 cab 不全

现象:DISM 跑到某个功能停住,返回0x800f0906,提示无法下载源文件,但/Source路径明明是对的,目录里也有 mum 文件。

原因九成是 sxs 目录拷得不完整。有人在复制的时候中途断过,或者用某些工具做了「只复制 mum」的筛选,导致 .cab 缺失。DISM 读得到描述文件,解不开负载,就报这个错。还有一种情况是从别的机器直接拖了个sxs过来,那台机器的补丁级别和这台不一样,部分 cab 版本对不上。

解决:先把 mum 和 cab 的数量对一下,正常应该是成对出现,Get-ChildItem *.mum和*.cab的数量差太多就说明有问题。最稳的办法是重新从原始镜像里完整提取,别做任何筛选。提取完再执行一次同样的 DISM 命令,之前失败的功能会重新解包。如果还报,去C:\Windows\Logs\CBS\CBS.log搜0x800f0906附近的行,里面会写明具体缺哪个包的哪个版本。

5.2 报 0x800F0954:组策略把功能安装导去了内部更新服务器

现象:明明加了/LimitAccess,还是报0x800F0954,提示无法连接到更新服务。断网机器上这个错来得特别快,几乎瞬间返回。

原因不是网络,是组策略。计算机配置里「指定 Intranet Microsoft 更新服务位置」被启用了,系统认定功能安装也必须走那个内部源,/LimitAccess只约束 DISM 自己,约束不了组策略层面下发的配置。

解决:临时把这条策略禁用,gpupdate /force刷一次,再跑 DISM。如果机器不允许改组策略,就改注册表:

:: 关掉 WSUS 指向,改完重启 Windows Update 服务 reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" /v UseWUServer /t REG_DWORD /d 0 /f net stop wuauserv net start wuauserv

装完记得改回去,别把生产机器的更新策略一直关着。另一个更正规的做法是在组策略里启用「指定 Windows 功能安装和修复的设置」,把备用源路径直接写成D:\sources\sxs,这样系统层面就认这个源,比每次命令行传/Source稳。

5.3 报 0x800f081f 或「版本不匹配」:镜像拿错了

现象:报0x800f081f找不到源文件,或者直接提示源文件版本与目标版本不匹配。后一种更明显,前一种很容易误判成源路径写错。

原因是拿错了镜像。常见三种:用 Windows Server 2012(6.2.9200)的 sxs 装 2012 R2;用英文镜像的 sxs 装中文系统;用 Datacenter 的 wim 挂载给 Standard 的机器。这三种在文件名上都能看出来,语言段和版本段一眼就能分辨。

解决:先systeminfo确认目标机版本是 6.3.9600,再dism /online /get-intl确认 UI 语言,然后回到源目录核 mum 文件名倒数两段。三者对齐了再装。别用「先装报错再换源」的方式试,每次失败都会在组件存储里留垃圾状态,反复几次之后正常的源也会装不上,那时候就得先dism /online /cleanup-image /startcomponentcleanup清一遍。

5.4 IIS 管理器点不开:只装了 Web-Server

现象:服务器管理器里 IIS 那一项能展开,但「Internet Information Services (IIS) 管理器」点开报错或者点了没反应,开始菜单搜 inetmgr 也搜不到。

原因是只装了IIS-WebServer和几个子功能,漏了IIS-ManagementConsole。这两个是不同的功能,Web 服务器核心不带管理界面。另一种可能是装在了 Server Core 上,那本来就没有图形界面,不是装错。

解决:补装管理工具,源还是同一个:

dism /online /enable-feature ^ /featurename:IIS-ManagementConsole ^ /featurename:IIS-ManagementScriptingTools ^ /source:D:\sources\sxs /limitaccess

补完直接运行inetmgr验证。Server Core 上就死心用 appcmd,C:\Windows\System32\inetsrv\appcmd.exe默认在 PATH 里,appcmd list site能出结果就说明 IIS 本身正常,只是没有界面。

5.5 站点报 500.19 或 403.14:ASP.NET 和默认文档的问题

现象:http://localhost能出 IIS 欢迎页,换成自己的站点就 500.19,提示「配置错误,无法读取配置文件」;或者 403.14,提示「目录列表被拒绝」。

500.19 有两种来源:一是站点用了 ASP.NET,但IIS-ASPNET45没装,配置节解析不了;二是 web.config 里有被锁定的节,应用程序池身份没权限读。前者装功能,

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询