IIS10装不上URL Rewrite2.0?注册表临时改MajorVersion实战修复(含PowerShell脚本与3种方案)

IIS10装不上URL Rewrite2.0?注册表临时改MajorVersion实战修复(含PowerShell脚本与3种方案)
张文保 更新 42 分钟阅读 7,107 阅读
本文目录
  1. 报错原因:注册表 MajorVersion 与 .msi 元数据不匹配
  2. 怎么用 WebPI 内部日志确认是不是这个错
  3. 微软为什么不修这个 .msi?
  4. 注册表 MajorVersion 是怎么写进去的
  5. 修复方法 1:手改注册表 MajorVersion(最常用)
  6. 操作步骤
  7. 三个最容易看走眼的细节
  8. 手改方式不要做的事
  9. 修复方法 2:PowerShell 一键脚本
  10. 升级版:try/finally 兜底版本号回写
  11. 用 Ansible 部署的写法
  12. 修复方法 3:跳过 WebPI 直接装官方离线 .msi(推荐)
  13. WebPI 退役后 .msi 还能从哪里拿?
  14. 静默安装命令(适合脚本部署)
  15. .msi 文件指纹(验证下载未被篡改)
  16. 卸载/换版本
  17. 安装后验证:四种确认方式
  18. IIS 管理器界面
  19. 命令行查模块列表(最靠谱)
  20. 物理文件校验
  21. PowerShell 一键检测脚本
  22. 生产环境踩坑(实战汇总)
  23. 改完忘记把 MajorVersion 改回去
  24. 6.2 64 位系统装了 32 位包
  25. AppPool 启用了 32-bit 模式但 URL Rewrite 装的是 64 位(隐藏陷阱)
  26. iisreset 还是没生效
  27. WebPI 缓存中毒(重复尝试后即使方法对了也失败)
  28. 装好的模块在某些站点不生效(modules 段错配)
  29. .NET Framework 3.5 缺失(HRESULT 0x80070643)
  30. 杀毒软件拦截 .dll 写入
  31. 实测耗时基准
  32. IIS 10 与 IIS 11 在 URL Rewrite 行为上的差异
  33. 正则引擎默认从 ECMAScript 切到 .NET Regex
  34. 出站规则的内存上限
  35. RewriteCacheSize 默认值
  36. 与 ARR 模块的交互
  37. 适用范围与版本兼容矩阵
  38. 常见问题解答
  39. 装上 URL Rewrite 之后用 Web.config 写规则报 500.19,是什么问题?
  40. 修改 MajorVersion 注册表会不会影响其它已经装好的 IIS 组件?
  41. 方法 1 改注册表的方式被微软官方文档承认吗?
  42. 能不能不改 MajorVersion,直接禁用 WebPI 的版本检测?
  43. 装好之后 Web.config 写规则没生效,但 appcmd 查模块是有的,怎么办?
  44. URL Rewrite 装多次会不会冲突?
  45. 非 root 站点(虚拟目录、应用)下 URL Rewrite 规则怎么写?
  46. 用 PowerShell 脚本部署时,怎么判断 URL Rewrite 是否已经装过?
  47. IIS Express(开发机本地调试用的轻量 IIS)也有同款问题吗?
  48. WebPI 缓存清完之后还是装失败,应该怎么继续诊断?
  49. 权威参考资料
摘要:IIS 10通过Web Platform Installer装URL Rewrite总是中断,根因不是真不兼容,而是.msi声明的版本上限只到9.x,碰上MajorVersion等于10就被判违例。本文从WebPI日志拆解检测流程,给出三套方案——手改注册表MajorVersion、PowerShell一键脚本、跳过WebPI直装官方离线msi,再附四种安装后验证、实测耗时基准和IIS 10与11在URL Rewrite行为上的差异。

用 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 版本走的是 严格大于即不兼容 的判定,而不是 大于等于历史最低支持版本即可,这是这个坑的设计层根因。

怎么用 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)。

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

微软为什么不修这个 .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。

注册表 MajorVersion 是怎么写进去的

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

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

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

操作步骤

  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 服务。

三个最容易看走眼的细节

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

手改方式不要做的事

  • 不要把 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——避免一刀切对未来更高版本不适用。

升级版: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%,事后审计很方便。

用 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 版本检测逻辑被绕开,自然也就没有"很遗憾,无法安装"的提示。

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,避免再依赖外部链路。

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

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

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

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

.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 不一致的优先怀疑下载源被污染,换源重下。

卸载/换版本

用同一个 .msi 卸载:

msiexec /x rewrite_amd64_zh-CN.msi /quiet

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

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

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

IIS 管理器界面

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

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

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

装成功的输出:

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

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

(空——什么都不输出)

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

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

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

物理文件校验

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

%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 在 = 安装是"半完成"状态,需要重装。

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

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

改完忘记把 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 版。

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 位。

iisreset 还是没生效

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

net stop was /y && net start w3svc

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

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 次都可能失败,但根本原因从来不是注册表,而是缓存里那份残破包。

装好的模块在某些站点不生效(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>

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

.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

杀毒软件拦截 .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 的运行时,有几处不向后兼容的小差异,迁移老规则时要注意:

正则引擎默认从 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)保持原行为。

出站规则的内存上限

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

RewriteCacheSize 默认值

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

与 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 抛掉。

权威参考资料

分享到
标签
版权声明

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

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

版权声明:本文原创,转载与引用请注明作者与原文链接。许可协议: CC BY 4.0

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