简介Windows Server 2012 R2 的 IIS 离线安装包面向企业 IT 管理员、系统集成人员与服务器运维学习者用于在断网机房、内网隔离或网络策略严格的环境中补齐 IIS Web 服务器角色及配套组件解决在线源不可达时角色安装失败、组件缺失的问题也适合作为了解 Windows 服务器功能组件构成的参考样本。压缩包共 1568 个文件、约 99.04MB以 720 个 dll 运行库、84 个 exe 可执行组件、66 个 aspx 管理页面、60 个 config 配置、56 个 sql 脚本与 50 个 browser 浏览器定义文件为主体另含 ascx、master 页面模板、tlb 类型库、mui 本地化资源及 targets、xml 等构建与配置素材覆盖 Web 服务、应用程序池、身份验证、SSL 证书、URL 重写、IP 限制、FTP 与 Web Deploy 等角色功能。已有 572 人学习下载。其目录按组件与功能分层组织便于按角色检索所需文件可作为离线组件源供系统角色安装调用也能帮助读者梳理 IIS 各功能模块的依赖关系为批量部署与故障排查提供完整素材。1. 内网里装 IIS卡住你的往往不是 IIS 本身半夜接到电话说内网一台 Windows Server 2012 R2 要上一个 ASP.NET 站点IIS 还没装。连上去点「添加角色和功能」进度条走到一半弹出 0x800f0906——这台机器连不上外网也没有 WSUS。折腾过几回的人都清楚2012 R2 上的 IIS 并没有一个能双击运行的 exe 安装包所谓「IIS 离线安装包」指的是从系统安装镜像里取出来的功能载荷源。这篇把源的取法、装法、验证和排错写透适合气隙环境、内网批量部署以及手上只剩一张旧 ISO 的运维。2. 先弄清「离线安装包」是什么2012 R2 上的 IIS 从来不是独立软件很多人第一次找这个包是带着桌面软件的思维去找的一个 exe、一个 msi、双击、下一步、完成。在 Windows Server 2012 R2 上这条路走不通而且不是「官方没提供第三方便宜卖」那种走不通是架构上就不存在这种东西。IIS 是操作系统的一个角色它的二进制文件在系统盘成型的那一刻就已经落在Windows\WinSxS里了安装动作只是把对应的功能包「标记为启用」并做一次组件注册。离线场景下缺的不是文件是那条告诉系统「载荷在哪儿、别去网上找」的参数。2.1 IIS 的载荷藏在 install.wim 的 Features 里把 Server 2012 R2 的 ISO 打开能看到\sources\install.wim和\sources\sxs两个关键位置。前者是整个系统的映像后者是功能载荷的侧载目录。IIS 在角色层面只有一个名字Web-Server但这个角色往下拆是几十个功能包每个包对应一组文件和一个注册动作。默认文档、静态内容、HTTP 日志、请求筛选、ASP.NET 4.5 支持、FTP 服务、管理控制台全都是独立的包。这解释了一个很常见的困惑为什么有的人装完 IIS浏览器能打开欢迎页但一部署站点就 500.21、404.17 满天飞因为他装的是那个「壳」没装Web-Asp-Net45、Web-Net-Ext45这些真正托管 ASP.NET 的功能包。角色名只是一个聚合入口真正决定能力边界的是下面那一串功能名。做离线源之前心里得有这张对照关系否则你会把整个 ISO 拷过去仍然装不出想要的东西。常见功能名和角色的对应关系写脚本的时候会反复用到角色/功能名提供的能力DISM 中的名字Web-ServerIIS 角色根节点IIS-WebServerRoleWeb-Common-Http默认文档、目录浏览、HTTP 错误IIS-CommonHttpFeaturesWeb-Static-Content静态文件处理IIS-StaticContentWeb-Http-Logging访问日志IIS-HttpLoggingWeb-Filtering请求筛选IIS-RequestFilteringWeb-Asp-Net45ASP.NET 4.5 托管IIS-ASPNET45Web-WebSocketsWebSocket 协议支持IIS-WebSocketsWeb-Mgmt-Console图形化 IIS 管理器IIS-ManagementConsoleWeb-Ftp-ServiceFTP 发布IIS-FTPServerPowerShell 侧用左边这一列DISM 侧用右边这一列两套名字不能混用。写文档的时候建议统一用 PowerShell 的功能名因为它同时能查状态、能装、能卸可读性也好一些。2.2 sources\sxs 和 install.wim 两条源路线怎么选离线源的取法有两种各有各的适用面。第一种是把 ISO 里的\sources\sxs整个目录复制到本地磁盘或文件共享。这是最省事的做法复制完就是一个普通目录Install-WindowsFeature -Source D:\sxs直接指过去就行。它的代价是占地方而且这份目录跟 ISO 的版本、语言严格绑定换一张不同来源的镜像就对不上。第二种是直接把install.wim挂成源用wim:路径:索引的写法。好处是不用解压一个几 GB 的 wim 文件放共享上就能服务所有机器副本管理简单。代价是每次安装都要从 wim 里读速度受磁盘和网络影响而且索引号必须写对——Server 2012 R2 的安装映像通常是多索引的选错了就是拿另一个版本的功能包装到当前系统上直接报 0x800f0906。对比项sources\sxs 目录install.wim 映像准备动作复制目录复制单个 wim无需解压引用写法-Source D:\sxs-Source wim:D:\install.wim:2索引依赖无必须与系统版本匹配共享部署目录权限要逐层配单文件授权简单安装速度较快稍慢受 wim 读取影响我一般会在文件服务器上同时放两种sxs 目录给人工排障用wim 给批量脚本用。人工排障时能直接dir看到缺哪个 cab比对着 wim 猜要快得多。2.3 用 DISM 读出当前系统的真实组件状态动手前先摸清底数别在不知道现状的机器上瞎装。两条命令足够一条看系统里已经有哪些 IIS 相关功能一条看某个功能的详细状态。:: 列出所有名字里带 IIS 的功能及其启用状态 dism /online /get-features /format:table | findstr /i IIS :: 看单个功能的详细信息包括依赖关系 dism /online /get-featureinfo /featurename:IIS-WebServerRole第一条命令的关键在/format:table不加这个参数输出是一大段竖排文本findstr筛完根本没法读。/online表示操作当前运行的系统如果是挂载的离线映像就换成/image:C:\mount。第二条的/get-featureinfo会打印出这个功能的父功能、依赖项和当前状态你能一眼看出IIS-WebServerRole是不是已经处于 Enable Pending 这种半吊子状态——这种状态最坑重装会报「已安装」用又用不了。PowerShell 侧的等价写法更贴近日常# 只看 IIS 相关的功能InstallState 是真正的判据 Get-WindowsFeature | Where-Object { $_.Name -like Web-* -or $_.Name -eq Web-Server } | Select-Object Name, DisplayName, InstallState | Format-Table -AutoSizeInstallState有四个值Available没装、Installed已装、Unavailable当前系统不支持、Removed被移除但载荷可能还在。看到Unavailable就别折腾了说明这个功能本身不适用于当前 SKU源再全也装不上。这一步花三十秒能省掉后面半小时对着错误码发呆。3. 制作一份能反复用的离线源从 ISO 到 D:\sxs目标很明确在一台能读 ISO 的机器上把功能载荷抽出来放到一个所有目标机都能访问的位置然后用一条命令把 IIS 装完。整个过程可以拆成三步——抽源、装、验。每一步都有具体的命令也都有具体的失败方式。3.1 挂载镜像、抽取 sxs 目录的完整命令不要用第三方解压工具去拆 ISO直接用系统自带的镜像挂载盘符干净、卸载干净也不会有文件属性丢失的问题。# 挂载 ISO拿到分配的盘符 $isoPath D:\ISO\WS2012R2.iso $volume Mount-DiskImage -ImagePath $isoPath -PassThru | Get-Volume $srcDir $($volume.DriveLetter):\sources\sxs # 校验源目录存在避免复制出个空壳 if (-not (Test-Path $srcDir)) { throw 镜像里没有 sources\sxs检查 ISO 是否为 Server 版 } # 复制到本地源目录保留目录结构 New-Item -Path D:\sxs -ItemType Directory -Force | Out-Null Copy-Item -Path $srcDir\* -Destination D:\sxs -Recurse -Force # 统计复制结果确认不是只拷了几个文件 (Get-ChildItem D:\sxs -Filter *.cab -Recurse).Count # 卸载镜像释放盘符 Dismount-DiskImage -ImagePath $isoPath逐段说明。Mount-DiskImage的-PassThru不能省不加它命令只返回空后面拿不到对象。Get-Volume从挂载结果里取盘符比硬编码E:可靠因为盘符会随环境变化。中间的Test-Path是一道保险Server 版镜像一定有sources\sxs但如果你手上是某些定制镜像或者误拿了客户端版这一步会直接拦住你好过后面装到一半报 0x800f081f。Copy-Item用$srcDir\*而不是$srcDir是为了把目录内容铺到D:\sxs下而不是套一层sxs\sxs。最后统计 cab 数量正常情况下应该是三位数如果只有个位数说明复制中断了。提示复制前先确认D:\sxs所在卷的剩余空间。整个目录铺开之后不算小中途空间不足会留下一个残缺的源而残缺的源报出来的错误码跟「源不存在」一模一样很难区分。3.2 用 Install-WindowsFeature 打通第一次安装源准备好之后第一条安装命令决定了你对这套流程的第一印象。我的建议是先在单机上跑通别一上来就批量。Import-Module ServerManager $result Install-WindowsFeature -Name Web-Server -IncludeManagementTools -Source D:\sxs -Restart:$false -LogPath C:\iis-install.log $result | Select-Object Success, ExitCode, RestartNeeded, FeatureResult参数逐个说。-Name Web-Server是角色名不是功能名写Web-WebServer也能装但语义上是子功能不推荐。-IncludeManagementTools会顺带装上 IIS 管理器不加的话装完在管理工具里找不到图标很多人第一次装完以为失败了就是这个原因。-Source指向刚才抽出来的目录也可以写成wim:D:\install.wim:2那种形式。-Restart:$false明确告诉它不要自动重启在一台正在跑业务的机器上这个参数能救你一命。-LogPath把本次操作单独记一份日志比事后翻CBS.log大海捞针强得多。返回值里Success是布尔判断ExitCode是结果枚举RestartNeeded告诉你需不需要重启才生效。看到Success : True且RestartNeeded : False就可以继续往下走RestartNeeded : True说明有文件被占用、已经排进重启队列这时候不重启就配置文件后面会出现一些莫名其妙的 500。习惯用命令行的DISM 的等价写法是这样:: 启用 IIS 角色/All 会连带父功能一起装 dism /online /enable-feature /featurename:IIS-WebServerRole /All /Source:D:\sxs /LimitAccess :: 补上 ASP.NET 4.5 与管理控制台 dism /online /enable-feature /featurename:IIS-ASPNET45 /All /Source:D:\sxs /LimitAccess dism /online /enable-feature /featurename:IIS-ManagementConsole /All /Source:D:\sxs /LimitAccess/LimitAccess是这几个命令里最容易被漏掉的开关。它的作用是明确禁止 DISM 去 Windows Update 拉载荷。在没有外网的机器上不加这个开关并不会让它「跳过网络」而是会先尝试联网、超时、然后才回落整个安装时间能拖到十几分钟最后还可能因为超时判定失败。加上它行为就变成纯粹从/Source里取快且确定。/All也不能省少了它只启用功能树的最顶层节点装出来的 IIS 连默认文档都没有。批量场景下把要装的功能列成一个数组循环调用每装一个记一次结果出错时能定位到具体是哪个包挂了$features ( Web-Server, # IIS 角色根 Web-Common-Http, # 默认文档、目录浏览、HTTP 错误 Web-Static-Content, # 静态内容处理 Web-Http-Logging, # 访问日志 Web-Filtering, # 请求筛选 Web-Asp-Net45, # ASP.NET 4.5 托管 Web-Mgmt-Console # IIS 管理器 ) foreach ($f in $features) { $r Install-WindowsFeature -Name $f -Source D:\sxs -LogPath C:\iis-$f.log {0,-24} {1,-10} {2} -f $f, $r.Success, $r.ExitCode }这段脚本的价值在于「可定位」。一次性装完再看总结果失败了只知道「没装上」逐个装逐个打失败会精确停在某个功能名上后面查日志的时候范围小了一个数量级。3.3 验证是不是「真装上了」而不是只有个空壳安装返回值是Success不等于服务真的在跑。三个层面的验证缺一不可。# 第一层功能状态 Get-WindowsFeature -Name Web-Server, Web-Asp-Net45, Web-Mgmt-Console | Select-Object Name, InstallState | Format-Table -AutoSize # 第二层服务状态 Get-Service W3SVC, WAS | Select-Object Name, Status, StartType # 第三层站点与端口 $env:windir\System32\inetsrv\appcmd.exe list site Invoke-WebRequest -Uri http://localhost -UseBasicParsing | Select-Object StatusCode第一层看InstallState是否都是Installed。第二层里W3SVC是万维网发布服务WAS是 Windows 进程激活服务后者是前者的依赖两个都得是RunningStartType得是Automatic。第三层用appcmd list site看默认站点在不在再用Invoke-WebRequest实际发一个 HTTP 请求拿状态码——这一步比看服务状态更实在因为它验证了监听、绑定、处理程序整条链路。如果前两层都对、第三层超时八成是防火墙。IIS 安装时会注册 World Wide Web Services 的防火墙规则组但如果这台机器的防火墙策略被集中管控过注册可能被覆盖得手动补一条放行 80 端口的入站规则。这个排查顺序要固定下来功能 → 服务 → 端口 → 防火墙一层层往下别跳。4. 静默与批量把离线安装写成可下发的脚本单机跑通之后真正耗时的部分是「还有二十台一样的机器」。这一步的关键不是把命令包一层循环而是把失败判断、源路径、重启策略这三件事做对。脚本写得糙批量执行的时候会同时产生二十个不同的失败原因你根本无从下手。4.1 一份带错误码判断的启用脚本先看脚本再讲为什么这么写。param( [string]$SourcePath D:\sxs, # 载荷源可以是本地目录或 wim:...:索引 [switch]$AllowRestart # 是否允许自动重启 ) $ErrorActionPreference Stop $logDir C:\Windows\Temp\iis-deploy New-Item -Path $logDir -ItemType Directory -Force | Out-Null # 源可用性前置检查避免带着坏源去装 if ($SourcePath -like wim:*) { if (-not (Test-Path ($SourcePath -replace ^wim:, -replace :\d$, ))) { throw wim 源不存在$SourcePath } } elseif (-not (Test-Path $SourcePath)) { throw 源目录不存在$SourcePath } $targets (Web-Server, Web-Common-Http, Web-Static-Content, Web-Asp-Net45) foreach ($name in $targets) { try { $r Install-WindowsFeature -Name $name -Source $SourcePath -LogPath $logDir\$name.log -Restart:$AllowRestart.IsPresent switch ($r.ExitCode) { Success { Write-Output $name 安装成功 } NoChangeNeeded { Write-Output $name 已存在跳过 } default { Write-Output $name 失败代码$($r.ExitCode) } } } catch { # 异常里通常带着真正的错误码别吞掉 Write-Output $name 抛出异常$($_.Exception.Message) throw } } # 输出总体是否需要重启 $pending Get-WindowsFeature -Name $targets | Where-Object { $_.InstallState -ne Installed } if ($pending) { Write-Output 以下功能尚未生效需重启后复查$($pending.Name -join , ) }param块把源路径和重启策略外置同一份脚本在开发和生产的机器上不用改代码。前置检查那段判断 wim 路径的写法看着绕其实就两件事把wim:前缀去掉把结尾的:索引去掉剩下的部分拿去Test-Path。这个检查很有必要Install-WindowsFeature在源不存在时的报错信息非常含糊经常是一句「无法下载源文件」直接误导你去查网络。switch里只处理三种情况是因为ExitCode的实际取值就集中在成功、无需变更、失败三类上。NoChangeNeeded单独拎出来是为了让日志可读——批量跑的时候大部分机器的返回都是这个值混在一起会淹没真正的失败。catch里重新throw是刻意的。批量脚本最忌讳「出了异常打个日志继续跑」那样最后你只知道「有些机器失败了」不知道失败在哪一步。宁可中断让人工介入也别把错误吞掉。4.2 UNC 源与远程批量Invoke-Command 的正确姿势源放在文件共享上是最省磁盘的做法但也是坑最多的做法。核心问题只有一个远程执行时谁在访问这个共享。$computers Get-Content C:\list\servers.txt $block { param($src) Install-WindowsFeature -Name Web-Server -IncludeManagementTools -Source $src -LogPath C:\Windows\Temp\iis-batch.log } Invoke-Command -ComputerName $computers -ScriptBlock $block -ArgumentList \\fileserver\sources\sxs -ThrottleLimit 5-ArgumentList传参比在ScriptBlock里硬编码共享路径好同一段代码换个源就能复用。-ThrottleLimit 5限制并发数是血泪经验默认值是 32二十台机器同时从同一个共享拉几百兆的载荷网络直接打满每台都超时最后全部失败而且失败原因看起来像「源不可用」实际上是带宽不够。真正需要注意的是权限模型。Invoke-Command默认在目标机上以调用者的凭据访问网络资源但这一跳常常不通表现是「本地能访问共享远程执行就报找不到路径」。最省事的规避方式不是去折腾凭据委派而是先复制再安装$block { param($share) # 先落到本地盘安装过程不再依赖网络 Copy-Item -Path $share -Destination C:\sxs -Recurse -Force Install-WindowsFeature -Name Web-Server -IncludeManagementTools -Source C:\sxs } Invoke-Command -ComputerName $computers -ScriptBlock $block -ArgumentList \\fileserver\sources\sxs多花一次复制的时间换掉一整类「权限时好时坏」的问题我觉得值。而且本地留一份源后面这台机器再装别的角色、或者做组件修复的时候还能直接复用不用再走网络。4.3 装完之后的基线核对清单批量部署做完需要一份能快速过一遍的核对表。把它写成脚本输出一张表比逐台远程桌面点开看快得多。检查项验证命令期望结果角色已启用Get-WindowsFeature Web-ServerInstallState 为 InstalledASP.NET 已注册Get-WindowsFeature Web-Asp-Net45InstallState 为 Installed服务在跑Get-Service W3SVCStatus 为 Running默认站点存在appcmd list site输出含 Default Web Site管理控制台可用Get-WindowsFeature Web-Mgmt-ConsoleInstalled且 inetsrv 下有 inetmgr80 端口监听Get-NetTCPConnection -LocalPort 80State 为 Listen本机可访问Invoke-WebRequest http://localhostStatusCode 为 200# 一次性输出核对结果适合贴到变更记录里 $checks [ordered]{ Web-Server (Get-WindowsFeature Web-Server).InstallState Web-Asp-Net45 (Get-WindowsFeature Web-Asp-Net45).InstallState W3SVC (Get-Service W3SVC).Status Port80 (Get-NetTCPConnection -LocalPort 80 -ErrorAction SilentlyContinue).State HttpStatus try { (Invoke-WebRequest http://localhost -UseBasicParsing -TimeoutSec 10).StatusCode } catch { FAIL } } $checks.GetEnumerator() | ForEach-Object { {0,-16} {1} -f $_.Key, $_.Value }-ErrorAction SilentlyContinue加在Get-NetTCPConnection上是因为端口没起来时它会抛异常而不是返回空加上这句才能拿到$null继续往下跑。Invoke-WebRequest外面套try/catch也是同理默认站点没起来的时候它会直接中断脚本后面几项就查不了了。这类地方不处理核对脚本本身就变成了故障源。5. 踩坑排查离线装 IIS 的五个翻车现场离线安装的失败模式高度集中翻来覆去就那么几种。与其每次从零开始猜不如把日志入口和几个典型现象记牢。这一章按「先看什么 → 五个具体案例 → 兜底路线」的顺序来。5.1 先看日志CBS.log 与 dism.log 该搜什么任何一次功能安装失败真正的答案都在两个地方C:\Windows\Logs\CBS\CBS.log和C:\Windows\Logs\DISM\dism.log。前者是组件服务的大脑后者是 DISM 工具自己的执行记录。别去看事件查看器里那条「Windows 无法安装以下功能」的摘要它除了告诉你失败了什么也没说。:: 在 CBS 日志里定位最近的错误行 findstr /i 0x800f C:\Windows\Logs\CBS\CBS.log :: 看 DISM 日志尾部的载荷查找记录 powershell -Command Get-Content C:\Windows\Logs\DISM\dism.log -Tail 80 | Select-String Source|payload|errorfindstr那一条会把所有带0x800f前缀的行筛出来这类错误码是组件存储专用的一眼就能定位到出问题的时间点。第二条用-Tail 80只看尾部是因为dism.log会随着使用不断追加从头看没有意义。关键字里Source和payload是最有价值的它们会明确写出「我尝试从哪个路径找文件、没找到」。如果安装了多次日志会很长建议按时间过滤# 只看最近半小时的组件错误 Get-WinEvent -LogName Setup -MaxEvents 50 | Where-Object { $_.TimeCreated -gt (Get-Date).AddMinutes(-30) } | Select-Object TimeCreated, Id, Message | Format-ListSetup日志里记录的是角色安装的整体流程事件配合 CBS 的细节基本能把问题钉死。5.2 五个典型现象的原因与解法现象一执行安装立刻返回 0x800f0906提示「无法下载源文件」。原因-Source指向的目录存在但里面缺了当前要装的功能对应的 cab。最常见的情形是从别人那里拷了一份「精简版」sxs或者复制过程被中断过。还有一种隐蔽情况ISO 的语言版本和系统不一致英文镜像的载荷喂给中文系统文件在但签名对不上。解决回到 ISO 重新完整抽一次sources\sxs别用别人给的目录。抽完统计 cab 数量和镜像里的原始目录比对一次。语言问题看系统Get-WinSystemLocale的输出与镜像语言对照不一致就换镜像。现象二报 0x800f081f提示「找不到源文件」但路径明明是对的。原因源放在共享上远程执行时目标机的计算机账户没有共享读权限或者路径里带了空格没加引号被截断了。解决先把源复制到目标机本地盘再装这一步能同时排除权限和路径两类问题。如果必须用共享授权对象是计算机账户域名\机器名$而不是用户账户这一点和日常的文件共享授权习惯不一样最容易搞错。现象三装完提示成功但管理工具里找不到 IIS 管理器。原因只装了Web-Server没加-IncludeManagementTools或者单独装的时候漏了Web-Mgmt-Console。返回Success是真的管理器确实不在两者不矛盾。解决补一句Install-WindowsFeature Web-Mgmt-Console -Source D:\sxs。补装的时候不用重启装完刷新管理工具列表就出来了。现象四站点部署上去报 500.21 或 404.17处理程序找不到。原因Web-Asp-Net45和Web-Net-Ext45没装或者装了但没注册。2012 R2 上已经不用aspnet_regiis -i那套了注册动作由功能包自己完成所以问题通常出在「压根没装」而不是「装了没注册」。解决先Get-WindowsFeature Web-Asp-Net45确认状态Available就补装。补装完iisreset再访问。还不行就查applicationHost.config里system.webServerhandlers段看 4.0 处理程序有没有被手工删过。现象五跑了几个月的机器某天想加个 FTP又报 0x800f0906。原因当初那份D:\sxs装完就被清理掉了。功能载荷不是装一次就永久驻留的后续再启用别的功能、或者系统做组件修复仍然需要源。解决源目录不要装完就删。要么留着要么在组策略里指定一个固定的本地源路径让系统自己知道去哪儿找。这一条其实是最值钱的经验——它把「一次性操作」变成了「长期资产」。5.3 装不上时的两条降级路线第一条换 DISM 直接上。PowerShell 的Install-WindowsFeature本质上是 DISM 的封装某些错误在封装层会被简化成一句含糊的话直接用dism /online /enable-feature /featurename:IIS-WebServerRole /All /Source:D:\sxs /LimitAccess能看到更原始的返回码。这一步的意义是「换个入口看错误」不是换个方法解决问题。第二条换整份 wim 做源。如果 sxs 目录怎么弄都不对直接把 ISO 里的install.wim复制过来用wim:D:\install.wim:索引指过去。索引号用dism /get-wiminfo /wimfile:D:\install.wim查认准Version : 6.3那一项——6.3 是 Server 2012 R2 的内核版本选到 6.2 就是 2012装上去必错。这条路慢一些但绕开了整个目录复制的完整性问题是很好的对照实验sxs 失败、wim 成功说明源目录本身有问题两个都失败问题在系统侧。6. 让离线源变成长期资产版本对齐与增量维护一次装完就完事的思路在这类环境里迟早要还回来。真正省事的做法是把源当成一项基础设施维护重点是三个对齐点。版本对齐。系统内核版本是 6.3.9600源就必须来自同一版本。手上如果同时有 Server 2012 和 2012 R2 的镜像文件名又很像很容易拿错。装之前用dism /get-wiminfo看一眼Version字段比事后查错误码快得多。已经打过补丁的系统功能载荷版本可能比原始 ISO 新这时候用旧源装某些功能会失败——遇到这种情况优先从系统自身的WinSxS里修复而不是硬塞旧载荷。语言对齐。中文系统的功能载荷里带lp.cab这类语言包文件英文镜像里没有对应项。跨语言用源表现是主功能装上了但界面语言错乱或者某些依赖语言的包直接失败。判断方法很简单Get-WinSystemLocale看系统区域和镜像的语言版本对一遍。源路径对齐。别指望每台机器的 D 盘都有那份目录。用组策略把源固定下来计算机配置 → 管理模板 → 系统 → 指定可选组件安装和组件修复的设置勾选「从不尝试从 Windows 更新下载载荷」把「备用源文件路径」填成共享路径。这个策略对应注册表HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing下的LocalSourcePath和UseWindowsUpdate用组策略下发比逐台改注册表可靠。配好之后即使某个操作没有显式指定-Source系统也知道去哪儿找不会再往网上撞。还有一个技巧值得单独说把源目录和一份features.txt放在一起文件里记录这份源来自哪个镜像、内核版本、语言、抽取日期。半年后你或者别人再动这台机器看到这份说明就知道能不能用。我吃过一次亏——两份不同来源的 sxs 目录并排放在共享上目录名一个叫sxs一个叫sxs_new谁也不知道哪个是哪个最后靠比对文件哈希才理清。从那以后我养成了一个习惯源目录的父目录名里必须带内核版本和语言比如sxs-6.3-zh-cn宁可名字长一点也别让自己半年后猜。验证这套东西是否真的可用最直接的办法是找一台干净的同版本机器断网从零跑一遍完整流程抽源、装角色、装 ASP.NET、起站点、访问。全程不联网还能出 200这套源才算立住了。跑通一次之后把脚本和源一起归档下次同类需求直接复用剩下的时间可以用来干别的。希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
PIC18F46K80与DRV8818步进电机驱动方案:从选型到固件实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 22:14:46
基于Python的离散数学图论可视化认知系统源码解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 14:42:39
基于STM32G431与DRV8818的紧凑型双极步进电机驱动设计 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 9:59:50
深海数据中心:极端环境下的硬件防护与软件优化实践 1. 项目背景与核心挑战去年夏天,我参与了一个听起来像科幻小说的项目——在深海高压腐蚀环境下测试数据中心的运行稳定性。这个项目源于一个简单但极具挑战性的问题:当我们将服务器浸入数百米深的海水中,代码还能正常运行吗?深海环… · 2026/11/4 20:27:18
无人机三维路径规划:五种优化算法对比与实践 1. 项目背景与核心挑战无人机三维路径规划是当前智能巡检领域的前沿课题,尤其在电力巡线、管道检测等复杂场景中,传统二维规划方法已无法满足实际需求。2024年IEEE国际机器人与自动化会议(ICRA)公布的数据显示,三维环境… · 2026/11/4 20:27:18
高二数学知识点总结PPT的公式修正与python-pptx索引化 简介:这是一份面向高二学生及数学教师的复习课件,围绕函数与导数、三角函数、解析几何、概率与统计、数列与数学归纳法、排列与组合等模块组织内容,可用于章节回顾、课堂串讲和考前查漏补缺。整包共1个PPTX文件,约64.9MBÿ… · 2026/11/4 20:27:18
中国月度部门用水量高分辨率网格数据集:降尺度方法与部门拆分逻辑解析 1. 这个数据集到底在解决什么问题第一次看到“中国月度部门用水量的高分辨率网格数据集(1965.1-2022.12)”这个标题,我脑子里冒出来的第一个念头是:这东西的颗粒度也太细了。时间上覆盖将近六十年,而且是逐月;空间上是网格化&… · 2026/11/4 20:27:18
视频本地备份实战:从链接到可播放文件的完整指南 视频收藏夹里躺着几百个"稍后再看",某天点开发现一片灰色,这种经历我猜不少人都遇到过。UP主删稿、账号注销、版权下架、区域调整,任何一个原因都能让一个你反复回看的视频突然消失。在线观看这件事,本质上是你把内容的… · 2026/11/4 20:27:18
鲲鹏服务器上部署TiDB数据库的完整实战指南 1. 环境准备与前置检查 在国产鲲鹏服务器上部署TiDB数据库前,需要做好充分的环境准备。我最近在Kylin Linux Advanced Server V10(ARM64架构)上完成了TiDB v8.5.5的部署,这里分享完整的实战经验。
1.1 硬件配置要求 TiDB作为分布… · 2026/11/4 20:26:16
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
AI辅助技术栈评估:提升研发决策效率60% 1. 项目背景与核心价值技术决策一直是研发团队面临的重大挑战。随着技术生态的快速演进,技术栈的选择、维护和迭代变得愈发复杂。我们团队在过去两年里,先后经历了三次重大技术栈迁移,每次都需要投入大量人力进行技术评估和风险分析。直到去年… · 2026/11/4 0:00:17
从生成Token到直接决策:Jev如何重塑AI Agent工程实践 1. 从"生成文字"到"拍板决策":Jev 到底在解决什么问题大多数人第一次接触大模型,脑子里建立的模型是"输入问题、输出文字"。你问它今天天气怎么样,它给你一段描述;你让它写个周报,它给你… · 2026/11/4 0:00:17
32G统一内存跑大模型:内存账、TPS实测与端云分流 想在一台 32G 统一内存的小主机上把大模型跑成"日常可用",这件事我前后折腾了小半年。标题里说的这台 Mac mini M6,是我们这次讨论的目标平台,具体到手规格以实物为准;但下面这套推算方法和实测思路,对任何统… · 2026/11/4 0:00:17
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38