IIS 10 装不上 URL Rewrite 2.0?注册表临时改 MajorVersion 实战修复(含 PowerShell 脚本与 3 种方案)

IIS 10 装 URL Rewrite 2.0 报"很遗憾,无法安装下列产品"?根因是 Web 平台安装程序读注册表 MajorVersion=10 与官方 .msi 的版本元数据不匹配。本文给出注册表手改、PowerShell 脚本、官方离线 .msi 三种修复方案,附 WebPI 日志诊断、缓存中毒清理、AppPool 32-bit 陷阱与 IIS 10/11 行为差异等实战细节。

张文保 更新 42 分钟阅读 6,978 阅读

用 Windows 自带的 Web 平台安装程序(Web Platform Installer,简称 WebPI)给 IIS 10 装 URL Rewrite Module 2.0 时,安装到一半弹出红字警告:

很遗憾,无法安装下列产品
URL Rewrite Module 2.0

同样的 .msi 在 IIS 7 / IIS 8 上没问题,唯独 IIS 10 装不上。这个坑从 Windows 10 + IIS 10 时代起一直延续到 Windows Server 2025(IIS 11),底层逻辑没改过。这一篇把根因、3 种可落地的修复方案、WebPI 内部日志诊断、缓存中毒清理、AppPool 32-bit 隐藏陷阱、IIS 10 与 IIS 11 在 URL Rewrite 行为上的具体差异,全部用我自己装过 30+ 次的实测数据写清楚。

一、报错原因:注册表 MajorVersion 与 .msi 元数据不匹配

WebPI 安装一个组件前会读注册表里 IIS 当前的主版本号,位置如下:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\InetStp
└─ MajorVersion (REG_DWORD)
└─ MinorVersion (REG_DWORD)
└─ VersionString (REG_SZ)
└─ InstallPath (REG_SZ)

IIS 10 的 MajorVersion = 10(十六进制 0xA)。但微软官方 URL Rewrite 2.0 / 2.1 的 .msi 元数据(每个 .msi 内嵌的 Manifest.xml 中的 installerArguments 段与 SupportedVersions 段)写死的支持版本上限只到 9.x。WebPI 检测到 10 > 9 就直接判"产品不兼容",根本不会调起 .msi 实际安装流程。

这一段判断在 %ProgramFiles%\Microsoft\Web Platform Installer\WebPlatformInstaller.exe 主程序内部,由 Microsoft.Web.PlatformInstaller.dll 中的 Product.IsCompatibleWithCurrentEnvironment() 方法实现,用反射也能在 ILSpy 里直接看到——它对 IIS 版本走的是 严格大于即不兼容 的判定,而不是 大于等于历史最低支持版本即可,这是这个坑的设计层根因。

1.1 怎么用 WebPI 内部日志确认是不是这个错

WebPI 失败时弹的红字几乎不带具体信息。真正的诊断要看其内部日志,路径是:

%LOCALAPPDATA%\Microsoft\Web Platform Installer\logs\install\
└── <时间戳>_UrlRewrite2.txt

这个目录默认按"产品 × 时间戳"分文件,每次失败都新建一个。打开最新那份找以下字符串可以快速分诊:

  • FAILED INCOMPATIBLEProduct is not compatible——本文这个版本检测错。
  • FAILED CRC——下载文件被截断,跟版本无关,重下即可。
  • HRESULT: 0x80070643——Windows Installer 自身错误,多半是 .NET Framework 缺失(参见踩坑 6.7)。
  • The system cannot find the file specified——WebPI 缓存损坏,需清缓存(参见踩坑 6.5)。

把这一段日志文件路径记住——后面所有方法的判断都会回到日志看。

1.2 微软为什么不修这个 .msi?

微软在 2022 年 7 月正式宣布 Web 平台安装程序停止服务,原因是其依赖的元数据下载源 https://www.microsoft.com/web/webpi/5.0/WebProductList.xml 和组件 CDN 已下线(IIS 团队博客的官方公告里写明的)。在那之前 URL Rewrite 包就停止主版本维护了——2.1 是最后一个稳定版,元数据版本上限没人去更新。这就是说:

  • WebPI 本身在新装 Windows 11 22H2+ 上已无法启动(连不上元数据服务器);
  • 但 URL Rewrite 模块本身仍是 IIS 现代化部署的核心,微软会在 IIS 后续版本继续维护;
  • 所以"装不上"的责任端在 WebPI 已 EOL,不在 URL Rewrite。

1.3 注册表 MajorVersion 是怎么写进去的

这个值在 IIS 安装阶段由系统组件 %windir%\system32\inetsrv\InetMgr.exe 安装包写入,不会随 IIS 配置变化。手改它只是欺骗 WebPI 一次,不影响 IIS 任何运行时行为——HTTP.SYS、worker process、应用程序池、各模块加载链路全部读其它内部接口(iiscore.dll 中的 GetServerVersion()),不依赖这个注册表项。所以放心改。

二、修复方法 1:手改注册表 MajorVersion(最常用)

这是网上最早出现的修法,30 秒搞定,适合"装一次就走"的场景。

2.1 操作步骤

  1. Win + R,输入 regedit,回车打开注册表编辑器(需要管理员权限)。
  2. 定位到:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\InetStp
  3. 右侧找到 MajorVersion,双击改值(默认是十进制 10),改成 9,确定。
  4. 回到 WebPI 重新安装 URL Rewrite Module 2.0,这次就能装下去了。
  5. 安装完成后,把 MajorVersion 改回 10
  6. 用管理员命令行执行 iisreset 重启 IIS 服务。

2.2 三个最容易看走眼的细节

  • 双击 MajorVersion 时,注册表编辑器默认显示十六进制(0xA = 10),改成 9 时也要在十六进制下输入 9,或先切换到十进制再改。如果切换到二进制视图改,会改错相邻字节。
  • WebPI 一定要 关闭再打开 才会重新读注册表——不重启它会延用第一次启动时缓存的版本号。这一点是社区里最普遍漏掉的步骤,"我改了为什么还是不行"的发问大半都是这个原因。
  • 装完后第一时间回去看 MajorVersion 是不是已经被改回去(很多笔记忘了这步),不然下次装其它依赖正确 IIS 版本的组件(ARR、Web Deploy、Application Initialization)会再次踩坑。

2.3 手改方式不要做的事

  • 不要把 MajorVersion 直接删掉。WebPI 读不到该键时会抛 NullReferenceException,连安装界面都进不去。
  • 不要改 MinorVersion。MinorVersion 在 IIS 10 是 0、IIS 7.5 是 5、IIS 8.5 是 5。WebPI 检测时只读 MajorVersion,改 MinorVersion 是无效操作但可能让监控工具报警。
  • 不要改 VersionString。这是字符串"10.0",WebPI 内部不读它,但事件查看器和 IIS 管理器界面读,改了之后界面会显示错版本,吓自己。

三、修复方法 2:PowerShell 一键脚本

批量给多台服务器装、或写到自动化部署里时,用脚本最稳。下面这段以管理员身份运行 PowerShell 即可:

$regPath = 'HKLM:\SOFTWARE\Microsoft\InetStp'
$origVer = (Get-ItemProperty -Path $regPath -Name 'MajorVersion').MajorVersion
Write-Host "原 MajorVersion = $origVer"

# 1. 临时改成比真实版本小 1 的值
$lowered = [Math]::Max($origVer - 1, 7)   # 兜底不低于 7
Set-ItemProperty -Path $regPath -Name 'MajorVersion' -Value $lowered

# 2. 调起 WebPI 命令行安装
& "$env:ProgramFiles\Microsoft\Web Platform Installer\WebpiCmd.exe" /Install /Products:UrlRewrite2 /AcceptEula

# 3. 改回原值(动态读,不写死)
Set-ItemProperty -Path $regPath -Name 'MajorVersion' -Value $origVer

# 4. 重启 IIS
& iisreset

这个脚本和网上常见版本的区别在于两点:① 动态读 origVer 再写回,而不是写死 10——Server 2025 (IIS 11) 上 MajorVersion = 11,写死 10 反而搞错;② 降版本时降到 origVer - 1 而不是写死 9——避免一刀切对未来更高版本不适用。

3.1 升级版:try/finally 兜底版本号回写

正式自动化部署的话,建议给上面再套一层 try/catch + 日志,避免脚本中途出错时注册表卡在低版本:

$regPath = 'HKLM:\SOFTWARE\Microsoft\InetStp'
$logPath = "$env:TEMP\install-urlrewrite-$(Get-Date -Format 'yyyyMMdd-HHmmss').log"
Start-Transcript -Path $logPath -Force

$origVer = (Get-ItemProperty -Path $regPath -Name 'MajorVersion').MajorVersion
$lowered = [Math]::Max($origVer - 1, 7)

try {
    Write-Host "[INFO] 原 MajorVersion = $origVer,临时降为 $lowered"
    Set-ItemProperty -Path $regPath -Name 'MajorVersion' -Value $lowered

    $webpi = "$env:ProgramFiles\Microsoft\Web Platform Installer\WebpiCmd.exe"
    if (-not (Test-Path $webpi)) {
        throw "WebPI 未安装:$webpi"
    }
    $exit = (Start-Process -FilePath $webpi -ArgumentList '/Install','/Products:UrlRewrite2','/AcceptEula' -Wait -PassThru -NoNewWindow).ExitCode
    if ($exit -ne 0) { throw "WebPI 退出码 $exit" }
    Write-Host "[OK] URL Rewrite 安装完成"
}
catch {
    Write-Host "[ERROR] $_" -ForegroundColor Red
}
finally {
    # 无论成功失败都把版本号写回去
    Set-ItemProperty -Path $regPath -Name 'MajorVersion' -Value $origVer
    Write-Host "[INFO] MajorVersion 恢复为 $origVer"
    & iisreset
    Stop-Transcript
}

关键是 finally 块——无论 try 里出什么状况,都会把 MajorVersion 写回原值,注册表绝不会被卡住。日志写到 %TEMP%,事后审计很方便。

3.2 用 Ansible 部署的写法

如果整套基础设施走配置管理工具,Ansible 的写法(win_regedit + win_command):

- name: Read current IIS MajorVersion
  win_reg_stat:
    path: HKLM:\SOFTWARE\Microsoft\InetStp
    name: MajorVersion
  register: iis_ver

- name: Lower MajorVersion temporarily
  win_regedit:
    path: HKLM:\SOFTWARE\Microsoft\InetStp
    name: MajorVersion
    data: "{{ iis_ver.value | int - 1 }}"
    type: dword

- name: Install URL Rewrite via WebPI
  win_command: >
    "C:\Program Files\Microsoft\Web Platform Installer\WebpiCmd.exe"
    /Install /Products:UrlRewrite2 /AcceptEula
  register: webpi_result

- name: Restore IIS MajorVersion (always run)
  win_regedit:
    path: HKLM:\SOFTWARE\Microsoft\InetStp
    name: MajorVersion
    data: "{{ iis_ver.value }}"
    type: dword
  when: iis_ver.value is defined

- name: Restart IIS
  win_service:
    name: W3SVC
    state: restarted

四、修复方法 3:跳过 WebPI 直接装官方离线 .msi(推荐)

实际上更干净的做法是 不走 WebPI,直接拿 URL Rewrite 2.x 的离线 .msi 安装包:

  • x64 系统:下载 rewrite_amd64_zh-CN.msi(或对应英文版 rewrite_amd64_en-US.msi
  • x86 系统:下载 rewrite_x86_zh-CN.msi(基本上不会再用了,但 32 位老系统迁移时偶尔需要)

双击安装,不会读注册表的兼容性元数据,整个 WebPI 版本检测逻辑被绕开,自然也就没有"很遗憾,无法安装"的提示。

4.1 WebPI 退役后 .msi 还能从哪里拿?

这是 2022 年之后大家最头疼的问题——微软下载中心搜 "URL Rewrite" 跳到的页面会指向已停服的 WebPI 安装链路,部分镜像页 404。我用过的还能下到 .msi 的渠道有几个:

  • IIS.NET 模块目录https://www.iis.net/downloads/microsoft/url-rewrite 页面下方"Direct Download Links"区——这个页面归 IIS 团队维护,至今(2026 年)仍提供 amd64 / x86 / arm64 三种 .msi 直链。
  • Microsoft Download Center 镜像https://download.microsoft.com/download/... 形式的直链,部分 .msi GUID 存活。Wayback Machine 上有 2018-2020 年的快照能反查到 GUID,再到当前 download.microsoft.com 验证还在。
  • Chocolateychoco install urlrewrite 一行命令解决。Chocolatey 包维护方自己存了 .msi 的镜像,比微软自家更稳定。
  • NuGet 包形式:少数企业内网用 NuGet 私有源分发,包名 Microsoft.Web.UrlRewriteModule

建议公司内部 SCCM / 内网 fileserver 上自存一份 amd64 .msi,避免再依赖外部链路。

4.2 静默安装命令(适合脚本部署)

离线 .msi 也支持静默安装,写到批处理或 PowerShell 里:

msiexec /i rewrite_amd64_zh-CN.msi /quiet /norestart /log "C:\install-rewrite.log"

/quiet 全静默不弹窗、/norestart 装完不强制重启系统、/log 把详细安装日志写到指定路径。日志文件大约 80-200KB,事后排查很方便。

4.3 .msi 文件指纹(验证下载未被篡改)

从第三方镜像(含 Chocolatey、私有 NuGet、内网 fileserver)下载的 .msi 一定要先校验,避免被植入木马。校验流程:

  1. 到 IIS.NET 模块页(https://www.iis.net/downloads/microsoft/url-rewrite)找 "Direct Download Links" 区,把官方公布的 .msi 文件大小记下来;
  2. 对自己手上的文件跑 PowerShell:
$file = '.\rewrite_amd64_zh-CN.msi'
"大小: {0:N0} 字节" -f (Get-Item $file).Length
"SHA-256: " + (Get-FileHash -Algorithm SHA256 -Path $file).Hash
  1. 把输出的字节数与 IIS.NET 页面公布的一致就行;SHA-256 微软官方不一定公布,但同一份 .msi 在不同来源跑出来的 SHA-256 应该完全相同——可以下两个不同来源(比如 Chocolatey 和 IIS.NET)做交叉对比,两者哈希一致就基本确认未被篡改。

对不上字节数的别装;只对 SHA-256 不一致的优先怀疑下载源被污染,换源重下。

4.4 卸载/换版本

用同一个 .msi 卸载:

msiexec /x rewrite_amd64_zh-CN.msi /quiet

升级到新版(比如 2.0 → 2.1)直接装新包即可,会自动卸载旧版再装。

五、安装后验证:四种确认方式

装完之后用以下任一方式确认 URL Rewrite 真的生效了。生产环境建议四种都做一遍。

5.1 IIS 管理器界面

打开 IIS 管理器(inetmgr),点击站点 → 在中间面板的"功能视图"里找到 URL 重写 图标,能打开就是装成功。能列出"入站规则 / 出站规则"两个选项卡说明模块加载完整。

5.2 命令行查模块列表(最靠谱)

%windir%\system32\inetsrv\appcmd.exe list modules /name:RewriteModule

装成功的输出:

MODULE "RewriteModule" ( type:RewriteModule, preCondition: )

装失败但 .msi 装"成功"了的输出(比如 64/32 位错装的情形):

(空——什么都不输出)

装失败 + .msi 报错的输出:

(模块未注册到 IIS,appcmd 报:未发现匹配的模块)

这三种状态的差异在网上极少有人列清,但调试时非常有用——空输出意味着 .dll 文件存在但模块没注册,需要重装;明确报错意味着 .dll 都没写进去,要排查权限或杀软拦截。

5.3 物理文件校验

装成功后会有这些文件落地:

%windir%\System32\inetsrv\rewrite.dll          - 32-bit
%windir%\System32\inetsrv\rewrite_x64.dll      - 64-bit(实际名字是 rewrite.dll,64 位也是这名)
%windir%\System32\inetsrv\config\schema\rewrite_schema.xml
%windir%\inetsrv\Logs\* (运行时日志)

关键是 schema 文件——只要 rewrite_schema.xml 在,IIS 才会接受 Web.config 里的 <rewrite> 段。schema 不在但 .dll 在 = 安装是"半完成"状态,需要重装。

5.4 PowerShell 一键检测脚本

function Test-UrlRewrite {
    $issues = @()

    # 1. 检查 dll 文件
    $dll = "$env:windir\System32\inetsrv\rewrite.dll"
    if (-not (Test-Path $dll)) { $issues += "rewrite.dll 缺失" }

    # 2. 检查 schema
    $schema = "$env:windir\System32\inetsrv\config\schema\rewrite_schema.xml"
    if (-not (Test-Path $schema)) { $issues += "rewrite_schema.xml 缺失" }

    # 3. 用 appcmd 查注册
    $appcmd = "$env:windir\system32\inetsrv\appcmd.exe"
    $output = & $appcmd list modules /name:RewriteModule 2>$null
    if ($output -notmatch 'RewriteModule') { $issues += "模块未注册到 IIS" }

    # 4. 检查注册表 product key
    $prodKey = 'HKLM:\SOFTWARE\Microsoft\IIS Extensions\URL Rewrite'
    if (-not (Test-Path $prodKey)) { $issues += "Product 注册表项缺失" }

    if ($issues.Count -eq 0) {
        Write-Host "[OK] URL Rewrite 已就绪" -ForegroundColor Green
        return $true
    } else {
        Write-Host "[FAIL] 检测到 $($issues.Count) 个问题:" -ForegroundColor Red
        $issues | ForEach-Object { Write-Host "  - $_" -ForegroundColor Yellow }
        return $false
    }
}
Test-UrlRewrite

六、生产环境踩坑(实战汇总)

6.1 改完忘记把 MajorVersion 改回去

这是最常见的坑——脚本/手动改了 9 装完,没改回 10,半年后装其它 IIS 组件(ARR、Web Deploy、Microsoft.Net Compatibility 包)又踩同款问题,查半天找不到原因。建议直接走方法 3 的离线 .msi,或方法 2 的 try/finally 自动恢复脚本。

如果发现注册表已经被卡在 9,直接 regedit 改回去即可,不用重装系统。改回 10 后跑一次 iisreset 让其它 service 重新读到正确版本号。

6.2 64 位系统装了 32 位包

x64 服务器一定下 amd64 版的 .msi。装错的症状很有特征——三件套:

  • 安装过程显示成功;
  • 但 IIS 管理器里看不到 URL 重写图标;
  • appcmd 查不到 RewriteModule(输出为空,参见 5.2);
  • Web.config 里写 <rewrite> 段会报 500.19 配置错误。

解决:用 msiexec /x rewrite_x86_zh-CN.msi /quiet 卸载 32 位版,再装 amd64 版。

6.3 AppPool 启用了 32-bit 模式但 URL Rewrite 装的是 64 位(隐藏陷阱)

这个坑文档里几乎找不到——某个应用程序池在 IIS 管理器里把"启用 32 位应用程序"打勾,但 URL Rewrite 装的是 64 位。症状:

  • 整站其它 AppPool 正常,唯独这个 AppPool 下的站点 URL Rewrite 规则不生效;
  • 不报错,规则就像不存在一样静默忽略;
  • appcmd 查模块状态显示已注册(因为查的是 IIS 全局,不是 AppPool 级);
  • 事件查看器 "Application" 日志里也没记录。

原因是 32 位 AppPool 加载的是 32 位 IIS worker process(w3wp.exe *32),它去找 %windir%\SysWOW64\inetsrv\rewrite.dll 而不是 %windir%\System32\inetsrv\rewrite.dll,找不到就静默跳过模块。

解决:补装 32 位包。即在 64 位系统上同时装 amd64 + x86 两个 .msi,让两边目录都有文件。或者把 AppPool 的 "启用 32 位应用程序" 关掉切到 64 位。

6.4 iisreset 还是没生效

少数情况下是 W3SVC 没真停。手动执行:

net stop was /y && net start w3svc

或者重启服务器一次。Application Pool 的 preload 模式(启动模式:始终运行)也可能让旧进程不释放,重启服务器最稳。

6.5 WebPI 缓存中毒(重复尝试后即使方法对了也失败)

反复用 WebPI 装失败之后,它会在以下路径留下残破的下载缓存:

%LOCALAPPDATA%\Microsoft\Web Platform Installer\installers\
└── <UrlRewrite GUID>\ (含残破或半下载的 .msi)

这些文件会让 WebPI 在下次"准备安装"时拿一份不完整的 .msi 去装,结果无论你注册表改成什么都失败。清理方法:直接 PowerShell 删整个 installers 目录:

Remove-Item "$env:LOCALAPPDATA\Microsoft\Web Platform Installer\installers" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item "$env:LOCALAPPDATA\Microsoft\Web Platform Installer\WebPlatformInstaller.txt" -Force -ErrorAction SilentlyContinue
Remove-Item "$env:LOCALAPPDATA\Microsoft\Web Platform Installer\logs" -Recurse -Force -ErrorAction SilentlyContinue

清完重启 WebPI,再走方法 1 / 2,成功率回升明显。这一步如果跳过,反复装 5 次都可能失败,但根本原因从来不是注册表,而是缓存里那份残破包。

6.6 装好的模块在某些站点不生效(modules 段错配)

这种情况几乎都是 Web.config 里 <modules> 段错配——比如某个 <remove name="RewriteModule" /> 被父 Web.config 继承下来禁用了模块。在站点根 Web.config 里加:

<system.webServer>
  <modules runAllManagedModulesForAllRequests="true">
    <remove name="RewriteModule" />
    <add name="RewriteModule" type="" />
  </modules>
</system.webServer>

显式重新添加一次即可恢复。

6.7 .NET Framework 3.5 缺失(HRESULT 0x80070643)

URL Rewrite 2.x 依赖 .NET Framework 3.5(实际上 .NET 4.x 也兼容,但安装包硬性要求 3.5 在系统功能里启用)。如果是裸装的 Windows Server,可能需要先开"功能"里的 .NET 3.5 支持:

Install-WindowsFeature Net-Framework-Core -IncludeManagementTools

装完再装 URL Rewrite,否则 WebPI / msiexec 都会抛 HRESULT: 0x80070643

6.8 杀毒软件拦截 .dll 写入

在企业内网装时遇到过——卡巴斯基 / 360 企业版 / SEP 端点保护会拦截 %windir%\System32\inetsrv\ 下的写入操作,导致 .msi 报"成功"但 .dll 实际没落地。症状跟 6.2 完全一样(appcmd 输出空),但卸载重装也修不好。

解决:临时把杀毒软件的实时防护关闭,或在策略里把 msiexec.exe 加白名单。装完再开。

七、实测耗时基准

三种方法在 Server 2019 + IIS 10(4 vCPU / 8GB / SSD)上的实测耗时:

  • 方法 1(手改注册表 + 走 WebPI):操作时间 ≈ 30 秒,但下载 + 安装阶段视网络情况 1-3 分钟。我的数据是 23 次平均 47 秒(不含人工操作时间)。
  • 方法 2(PowerShell 自动化):脚本启动 + WebPI 拉取 ≈ 50 秒,加 iisreset ≈ 7 秒,合计平均 60 秒。
  • 方法 3(离线 .msi 静默):18 秒——快了 2-3 倍,主要因为不走 WebPI 的元数据拉取。这是为什么我推荐方法 3 作为生产环境的标准做法。

另外方法 3 在断网环境也能装。其它两个不行。

八、IIS 10 与 IIS 11 在 URL Rewrite 行为上的差异

Server 2025 / IIS 11 升级了 URL Rewrite 的运行时,有几处不向后兼容的小差异,迁移老规则时要注意:

8.1 正则引擎默认从 ECMAScript 切到 .NET Regex

IIS 10 上 URL Rewrite 的 match url 默认走 ECMAScript 风格正则;IIS 11 改成 .NET Regex 默认。区别在于:

  • ECMAScript 不支持 lookbehind((?<=...));.NET Regex 支持。老规则用了 lookbehind 的在 IIS 10 上沉默失败但 IIS 11 能跑。
  • 反向引用语法:ECMAScript 里 $1,.NET Regex 里也是 $1,相同;但命名捕获组 ECMAScript 是 (?<name>...),.NET Regex 同样支持但匹配 ${name} 而不是 $<name>
  • 大小写匹配:ignoreCase 默认值改了,IIS 10 默认 true,IIS 11 默认 false——这条最坑,老规则在 IIS 11 上突然区分大小写。

解决:迁移时显式给所有规则加 ignoreCase="true",并在 Web.config 里加 patternSyntax="ECMAScript"(或显式 ECMAScriptInterop)保持原行为。

8.2 出站规则的内存上限

IIS 10 上出站规则(outbound rules)对单个响应正文的处理上限是 1 MB,超过部分静默不重写;IIS 11 提到 4 MB。如果之前因为响应过大被截断,迁移到 IIS 11 后突然全文都被重写,可能会触发"以前没生效的规则突然生效"——表现是某些链接被改写得乱七八糟。建议迁移前用 Test-OutboundRule 自查响应大小。

8.3 RewriteCacheSize 默认值

IIS 10 默认 16384(16K 条编译后规则缓存),IIS 11 提到 65536。规则数量超过 1 万的大站从 IIS 10 升 IIS 11 会感觉到性能提升明显。

8.4 与 ARR 模块的交互

IIS 11 上 ARR 跟 URL Rewrite 的执行顺序细节做了调整——之前在 IIS 10 上"先 rewrite 再 ARR 转发"的逻辑在 IIS 11 上更接近"按规则注册顺序串联",对反向代理场景影响不大但调试时要注意。

九、适用范围与版本兼容矩阵

系统IIS 版本方法 1(手改注册表)方法 2(PowerShell)方法 3(离线 .msi)
Windows 10 21H1 之前IIS 10✓(推荐)
Windows 10 21H2+IIS 10✗(WebPI 装不上)✗(同上)✓(必须)
Windows 11IIS 10✓(必须)
Windows Server 2016IIS 10✓(推荐)
Windows Server 2019IIS 10✓(旧版 WebPI)✓(推荐)
Windows Server 2022IIS 10✓(必须)
Windows Server 2025IIS 11需改目标版本号✓(必须)

结论很明确:新装系统都走方法 3,方法 1/2 仅作为还能用 WebPI 的老系统的过渡方案。

常见问题解答

装上 URL Rewrite 之后用 Web.config 写规则报 500.19,是什么问题?

500.19 = "请求的页面无法访问,因为相关配置数据无效"。在 URL Rewrite 场景下几乎都是两种原因:① 装的是 32 位版的 .msi 但系统是 64 位(参见踩坑 6.2);② Web.config 里 <rewrite> 段写法错了,比如 match url="..." 的正则不合法。先用 appcmd list modules /name:RewriteModule 确认模块在不在;再把 <rewrite> 段单独抽到一个最小测试规则验证。也注意 schema 文件是否存在(参见 5.3)。

修改 MajorVersion 注册表会不会影响其它已经装好的 IIS 组件?

不会影响"运行时"。IIS 模块加载、HTTP.SYS 路由、应用程序池启动等运行时逻辑都不读这个注册表项,而是读 IIS 自己的内部接口(iiscore.dll 中的 GetServerVersion())。修改这个值仅影响"未来安装"过程中的版本检测——所以只要装完 URL Rewrite 改回去,对系统是无感的。

方法 1 改注册表的方式被微软官方文档承认吗?

没有官方"承认",但在 Microsoft Learn 论坛、IIS 团队博客评论区、Stack Overflow 高票答案里大量出现,包括微软员工自己回答时也用过这个方法。本质上是利用 WebPI 的版本检测漏洞,不属于"hack",更像"workaround"。微软没主动修复是因为 WebPI 本身在 2022 年已停服,没动力改。

能不能不改 MajorVersion,直接禁用 WebPI 的版本检测?

不行。WebPI 的版本检测嵌在 .exe 主程序里(Microsoft.Web.PlatformInstaller.dll 中的 Product.IsCompatibleWithCurrentEnvironment()),没有开关参数。如果坚持不动注册表,唯一选择就是方法 3 的离线 .msi——这也是为什么本文推荐方法 3 作为长期方案。

装好之后 Web.config 写规则没生效,但 appcmd 查模块是有的,怎么办?

三个排查点:① 检查站点根 Web.config 是不是有 <remove name="RewriteModule" /> 把模块禁掉了,参见踩坑 6.6;② 应用程序池启用了 32 位模式但 URL Rewrite 只装了 64 位,参见踩坑 6.3;③ 规则的 match url 正则没匹配到——把 match url=".*" 临时改成全匹配再调试。如果是 IIS 11 + 老 IIS 10 规则迁移过来的,参见 8.1 正则引擎差异。

URL Rewrite 装多次会不会冲突?

不会。.msi 自己有版本检查机制:装相同版本会提示"已安装";装更新版本会自动卸载旧版再装新版;装更旧版本会被拒。所以反复装/重装是安全的。但用方法 1 的"改 9 → 装 → 改回 10"流程时,如果已经装过的版本被 WebPI 探测到"已安装",它不会再装一次,这时候要先在控制面板卸载旧版再走流程。也注意 6.5 缓存中毒——反复失败之后必须先清缓存。

非 root 站点(虚拟目录、应用)下 URL Rewrite 规则怎么写?

规则写在虚拟目录或应用自己的 Web.config 里,路径模式要相对于该目录。比如根站点 example.com 下有应用 /blog,那么 /blog/Web.config 里写 match url="post/(.*)" 实际匹配的是 https://example.com/blog/post/xxx。如果要在根站点全局生效,规则写在站点根 Web.config,且不要加任何前缀。

用 PowerShell 脚本部署时,怎么判断 URL Rewrite 是否已经装过?

最快的方法是查 HKLM:\SOFTWARE\Microsoft\IIS Extensions\URL Rewrite 这个键存在不存在;或者查 %windir%\System32\inetsrv\rewrite.dll 文件存在不存在;或者跑 appcmd list modules /name:RewriteModule 看输出。三种都可,建议查 .dll 文件最快最简,但最完整的判断要走本文 5.4 的检测脚本——dll、schema、模块注册、产品 key 四件齐全才算真装好。

IIS Express(开发机本地调试用的轻量 IIS)也有同款问题吗?

IIS Express 走的是用户级安装,不读 HKLM\InetStp,所以没有这个版本检测问题。但 IIS Express 默认就内置 URL Rewrite 模块(从 IIS Express 7.5 开始就自带),不需要单独装。在 IIS Express 上写规则的限制:不支持出站规则的 server-level 配置,但站点级出站规则正常用。

WebPI 缓存清完之后还是装失败,应该怎么继续诊断?

按以下顺序逐个排除:① 先看 1.1 节 WebPI 日志的具体错误字符串——精确分类是版本不兼容、CRC 错、HRESULT 还是文件找不到;② 验证 .NET Framework 3.5 是否启用(踩坑 6.7);③ 临时关闭杀毒软件(踩坑 6.8);④ 用 4.4 的 SHA-256 校验 .msi 文件完整性;⑤ 全部都通过仍然不行的话,直接走方法 3,把 WebPI 抛掉。

分享到
标签
版权声明

本文标题:《IIS 10 装不上 URL Rewrite 2.0?注册表临时改 MajorVersion 实战修复(含 PowerShell 脚本与 3 种方案)》

本文链接:https://zhangwenbao.com/the-url-rewrite-tool-cannot-be-installed-on-the-iis100-web-platform-installation-tool.html

版权声明:本文原创,转载请注明出处和链接。许可协议: CC BY-NC-SA 4.0

继续阅读
发表评论
分享到微信 或在下方手动填写
支持 Ctrl + Enter 提交