ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Advanced Installer 22.5 企业级 MSI 打包实战:从静默安装到回滚验证

Advanced Installer 22.5 企业级 MSI 打包实战:从静默安装到回滚验证 简介Advanced Installer 22.5 打包 Windows 安装包资源面向需要制作专业安装程序的软件开发者与运维人员帮助将应用程序、依赖文件及安装配置整合为可安装、可卸载、易管理的 Windows 安装包。压缩包共约 2000 个文件整体约 229.56MB涵盖 623 个 png、321 个 jpg、136 个 ico 等界面与图标素材419 个 aip 工程文件、47 个 ail 本地化脚本、75 个 xsd 与 61 个 xml 配置定义以及 8 个 msi、1 个 msm 等安装包样本另含 rtf、html、xaml、ps1、cmd 等文档与脚本便于直接参考工程结构与多语言配置。已有 1432 人学习下载。资源覆盖 GUI、静默与命令行安装模式包含安装条件检查、快捷方式与注册表项设置等实践素材适合对照官方发布说明研究 22.5 版本的新特性与打包选项快速掌握从工程配置到编译发布的完整流程。1. 从一份能过企业 IT 审核的安装包说起做过 To B 交付的同行大概都有过这种经历代码写完了功能测通了结果卡在最后一步——客户 IT 部门要求提供一个带数字签名、能静默安装、支持升级回滚、还得在 Windows Server 2016 上跑得起来的 MSI 包。用 Inno Setup 或 NSIS 硬扛脚本写到怀疑人生用 Visual Studio 自带的 Installer Projects功能又太单薄连个自定义安装路径的界面都做得磕磕绊绊。Advanced Installer 22.5 就是冲着这个场景来的它把 Windows InstallerMSI那套复杂到反人类的底层 API 封装成了可视化工程同时保留了直接编辑 MSI 表的能力。换句话说新手可以拖拽生成安装包熟手可以钻进 Table Editor 里改每一行数据。这份资源适合两类人一是需要给 Windows 桌面应用做正规安装包的开发者二是被 WiX 的 XML 语法折磨过、想找个折中方案的运维工程师。它解决的核心问题不是“怎么把文件拷到 Program Files”而是“怎么让安装包符合企业软件分发规范”。2. 工程结构与 MSI 数据库先搞懂它在替你做什么2.1 从 .aip 工程文件到 MSI 的编译链路Advanced Installer 的工程文件后缀是.aip本质是一个 XML 描述文件记录了你配置的所有安装逻辑。但最终交付物是.msi而 MSI 不是简单的压缩包——它是一个 OLE 复合文档内部嵌了一个关系型数据库表名固定为Feature、Component、File、Registry、CustomAction等。你每在图形界面点一次“添加文件”它就在File表和Component表里各插一行记录并自动生成 GUID。编译过程就是把这些表序列化进 MSI 流再附加 CAB 压缩包。理解这条链路的意义在于当安装行为不符合预期时你不需要瞎猜直接看表就行。比如某个文件死活装不进去打开 Table Editor 查Component表里该文件的Attributes字段如果值是 0 而不是 256说明它被标记为“本地仅安装”在按需安装模式下就不会释放。常见做法是编译前用“Validate”功能跑一遍 ICE 验证它会告诉你哪张表违反了 Windows Installer 规范。2.2 三种安装类型的选择逻辑Advanced Installer 22.5 新建工程时让你选架构类型这不是随便点的工程类型适用场景产物是否需要管理员权限Professional单机桌面应用无域环境MSI EXE 引导通常需要Enterprise需要 AD 组策略分发MSI含 MST 变换需要Architect多语言、多产品套件MSI 捆绑包按配置选 Professional 就够覆盖 80% 的交付场景。如果你的客户明确说“我们要用 SCCM 推送”那就必须选 Enterprise因为 SCCM 对 MSI 的静默参数和日志记录有额外要求Professional 生成的包在msiexec /qn下可能因为缺少ALLUSERS属性而装到当前用户目录而不是全局目录。2.3 用命令行编译替代 GUI 点击图形界面适合调试但持续集成必须走命令行。Advanced Installer 提供了AdvancedInstaller.com这个 CLI 工具路径通常在安装目录下。下面是一个典型的构建脚本:: build_installer.bat :: 设置 Advanced Installer 安装路径 set AI_PATHC:\Program Files (x86)\Caphyon\Advanced Installer 22.5\bin\x86\AdvancedInstaller.com :: 重新构建工程/rebuild 会先清理再编译 %AI_PATH% /rebuild D:\projects\MyApp\MyApp.aip :: 检查返回码非 0 表示编译失败 if %errorlevel% neq 0 ( echo Build failed with error code %errorlevel% exit /b %errorlevel% ) :: 对生成的 MSI 做数字签名需提前配置好证书 :: 注意signtool 来自 Windows SDK不是 Advanced Installer 自带 signtool sign /f D:\certs\mycert.pfx /p password /fd SHA256 D:\projects\MyApp\MyApp-SetupFiles\MyApp.msi echo Build and sign completed.这段脚本的逻辑是先调/rebuild参数让 Advanced Installer 以无界面模式重新编译工程然后判断errorlevel。这里有个血泪经验——AdvancedInstaller.com在编译失败时不一定返回非零值某些版本只会在日志里写错误但返回 0。稳妥做法是加一步检查 MSI 文件的时间戳是否更新或者解析它输出的日志文件。签名步骤必须放在编译之后因为任何对 MSI 的修改都会破坏已有签名。参数说明/rebuild等价于先 Clean 再 Build适合 CI 环境如果只想增量编译用/build。signtool的/fd SHA256指定文件摘要算法Windows 10 以后建议用 SHA256SHA1 签名的包在较新系统上会弹“未知发布者”。3. 自定义操作与安装界面把“下一步”变成可控流程3.1 用 Custom Action 在安装前后跑脚本很多应用安装完需要注册服务、写环境变量、或者初始化数据库。这些动作不能靠用户手动做得用 Custom Action 嵌进 MSI 执行序列。Advanced Installer 支持三种 Custom ActionEXE 调用、DLL 调用、JScript/VBScript 内嵌脚本。我一般优先用内嵌 JScript因为它不依赖外部文件编译进 MSI 后不会因为杀毒软件拦截外部 EXE 而失败。下面这段 JScript 放在“Custom Actions”页的“Install”阶段作用是安装完成后在桌面创建快捷方式并设置一个注册表标记// CustomAction_Install.js // 此脚本在 MSI 的 InstallFinalize 之后执行 // 参数通过 Session.Property 传入 var shell new ActiveXObject(WScript.Shell); var fso new ActiveXObject(Scripting.FileSystemObject); // 获取安装目录APPDIR 是 Advanced Installer 的内置属性 var installDir Session.Property(APPDIR); // 去掉末尾反斜杠 if (installDir.charAt(installDir.length - 1) \\) { installDir installDir.substring(0, installDir.length - 1); } // 创建桌面快捷方式 var desktop shell.SpecialFolders(Desktop); var shortcut shell.CreateShortcut(desktop \\MyApp.lnk); shortcut.TargetPath installDir \\MyApp.exe; shortcut.WorkingDirectory installDir; shortcut.Description MyApp Desktop Client; shortcut.Save(); // 写注册表标记供后续升级判断 var regPath HKCU\\Software\\MyCompany\\MyApp\\; shell.RegWrite(regPath InstalledVersion, Session.Property(ProductVersion), REG_SZ); // 返回 0 表示成功非 0 会导致安装回滚 return 0;逻辑说明Session.Property(APPDIR)拿到用户在界面选择的安装路径这是 Advanced Installer 预定义的属性。shell.SpecialFolders(Desktop)获取当前用户桌面路径注意这里用的是 HKCU 而不是 HKLM因为写 HKLM 需要管理员权限而 Custom Action 默认以模拟用户身份运行。如果一定要写 HKLM需要在 Custom Action 属性里勾选“Run under LocalSystem”。参数说明return 0是硬性要求返回非零值会让 MSI 认为自定义操作失败触发回滚用户会看到“安装程序被中断”的报错。调试阶段可以在脚本里加Session.Log(message)把信息写进 MSI 日志然后用msiexec /i MyApp.msi /l*v install.log查看。3.2 对话框序列的定制与属性传递Advanced Installer 默认的安装界面是“欢迎 → 许可 → 安装路径 → 安装 → 完成”。但企业客户经常要求加一个“服务器地址”输入框让安装时就能配置后端连接。这需要在 Dialog Editor 里新建一个对话框放一个 Edit 控件绑定到自定义属性比如SERVER_URL然后在“Custom Actions”里读取这个属性。操作步骤在“User Interface” → “Dialogs”里右键新建一个 Dialog设置其“Predecessor”为InstallDirDlg“Condition”留空表示总是显示。拖入一个 Edit 控件在属性面板的“Property Name”填SERVER_URL。接着在“Custom Actions”里加一个“Set installer property”动作把SERVER_URL的值写进配置文件。常见做法是用“Text File Update”功能直接替换配置文件里的占位符比写脚本更稳。这里有个容易翻车的地方属性名必须全大写且不能和 MSI 保留属性冲突比如INSTALLDIR、TARGETDIR是系统保留的。如果你自定义了SERVER_URL在脚本里用Session.Property(SERVER_URL)读取时如果用户没填返回的是空字符串而不是 undefined所以判断要写成if (url )而不是if (!url)。3.3 用 MST 变换实现多环境配置同一个 MSI 要装到测试环境和生产环境区别只是配置文件里的数据库连接串不同。如果打两个包维护成本翻倍。正确做法是打一个基础 MSI再生成两个 MSTTransform文件。Advanced Installer 的“Builds”功能支持这种模式在“Builds”页新建两个 Build分别设置不同的“Configuration”和输出 MST。编译后你会得到MyApp.msi、Test.mst、Prod.mst。安装时用msiexec /i MyApp.msi TRANSFORMSTest.mst /qn就能应用测试环境配置。MST 的本质是一个差异数据库只记录与基础 MSI 不同的表行所以体积很小。注意MST 必须和 MSI 放在同一目录或者用绝对路径指定否则 msiexec 会报“找不到变换”。4. 避坑与排查那些让我重装三次系统的教训4.1 现象安装包在 Win7 上报“不是有效的 Win32 应用程序”原因Advanced Installer 22.5 默认生成的引导程序EXE 外壳是 64 位的而 Win7 32 位系统无法运行。虽然 MSI 本身是平台无关的但外层 EXE 挂了。解决在“Builds”页把“Package Type”从“EXE with resources”改成“MSI only”或者强制引导程序为 32 位。如果客户坚持要 EXE 外壳在“Bootstrapper”设置里勾选“Build x86 version”。4.2 现象静默安装后程序能跑但开始菜单没有快捷方式原因msiexec /qn模式下所有标记为“Advertised”的快捷方式不会被创建。Advanced Installer 默认把快捷方式设为“Advertised”因为这样支持“按需安装”。解决在“Shortcuts”页选中快捷方式把“Advertised”属性改为“No”。或者在命令行加ADDLOCALAll强制安装所有功能。但注意ADDLOCALAll会安装所有语言资源包体积会变大。4.3 现象升级安装时提示“已安装该产品的另一个版本”无法覆盖原因MSI 的ProductCode变了但UpgradeCode没变或者两个都没变。Windows Installer 靠UpgradeCode识别产品家族靠ProductCode识别具体版本。如果UpgradeCode相同但ProductCode也相同它会认为你在装同一个包。解决在“Product Details”页确认UpgradeCode保持不变整个产品生命周期都不变每次发版只改ProductCode和ProductVersion。Advanced Installer 有“Generate new ProductCode”按钮每次构建前点一下。另外在“Upgrades”页配置“Custom Upgrade”指定旧版本范围勾选“Uninstall old version first”。4.4 现象自定义操作里的脚本在 Win10 上正常在 Server 2016 上超时失败原因Server 2016 默认的 WSHWindows Script Host版本较老且 IE 增强安全配置可能禁用了 ActiveXObject。解决把 Custom Action 的类型从“JScript”改成“EXE”或“DLL”用 C# 写一个控制台程序编译成 .NET Framework 4.6.2 版本Server 2016 自带 4.6.2。在 Advanced Installer 里把这个 EXE 作为“Temporary File”嵌入执行完自动删除。注意 EXE 的入口参数要接收Session.Property传过来的值通常用环境变量或命令行参数传递。4.5 现象数字签名后安装包体积暴涨原因签名工具在 MSI 里嵌入了完整证书链如果证书链很长比如包含根证书、中间证书体积会增加几百 KB。更严重的是某些时间戳服务器响应慢导致签名过程卡住。解决用signtool的/tr参数指定 RFC3161 时间戳服务器比老式/t更可靠。如果体积敏感可以在签名后对 MSI 做一次“压缩优化”——Advanced Installer 的“Media”页有“Compression”选项选“High”用 LZMA 算法但注意压缩后的 MSI 在部分老旧系统上安装会变慢。5. 进阶用 PowerShell 做安装后验证与回滚兜底5.1 安装后自动验证的脚本模板MSI 装完不代表万事大吉文件可能被杀毒软件删了服务可能没起来。我习惯在 Custom Action 的最后一步调一个 PowerShell 脚本做自检把结果写进日志文件。下面这个脚本检查三个关键点主程序是否存在、服务是否运行、注册表键是否写入。# Verify-Install.ps1 # 由 Custom Action 在 InstallFinalize 后调用 param( [string]$InstallDir $env:APPDIR, [string]$LogPath $env:TEMP\MyApp_InstallVerify.log ) $result () $result Verification started at $(Get-Date) # 检查主程序文件 $exePath Join-Path $InstallDir MyApp.exe if (Test-Path $exePath) { $result PASS: Main executable found at $exePath } else { $result FAIL: Main executable missing } # 检查 Windows 服务状态 $svc Get-Service -Name MyAppService -ErrorAction SilentlyContinue if ($svc -and $svc.Status -eq Running) { $result PASS: Service MyAppService is running } elseif ($svc) { $result FAIL: Service exists but status is $($svc.Status) } else { $result FAIL: Service not installed } # 检查注册表 $regPath HKLM:\SOFTWARE\MyCompany\MyApp if (Test-Path $regPath) { $ver (Get-ItemProperty -Path $regPath -Name Version -ErrorAction SilentlyContinue).Version $result PASS: Registry key found, version$ver } else { $result FAIL: Registry key missing } # 输出结果 $result | Out-File -FilePath $LogPath -Encoding UTF8 $result | ForEach-Object { Write-Host $_ } # 如果有 FAIL返回非零值触发回滚 if ($result -match FAIL) { exit 1 } else { exit 0 }逻辑说明脚本接收两个参数$InstallDir默认从环境变量APPDIR取这是 Advanced Installer 在调用外部脚本时自动注入的。Get-Service的-ErrorAction SilentlyContinue避免服务不存在时抛异常中断脚本。最后用$result -match FAIL做整体判断只要有一条失败就exit 1。参数说明$LogPath默认写到 TEMP 目录方便安装失败后让用户直接发日志给你。如果要在 MSI 回滚时也保留日志需要把日志路径设到C:\ProgramData下因为 TEMP 目录在回滚时可能被清理。注意 PowerShell 脚本的执行策略——在 Server 2016 上默认是 Restricted需要在 Custom Action 里用powershell.exe -ExecutionPolicy Bypass -File Verify-Install.ps1来调用。5.2 回滚兜底当验证失败时自动卸载如果验证脚本返回 1MSI 会触发回滚但回滚只撤销 MSI 自己做的更改你的 Custom Action 写的注册表、创建的服务可能残留。稳妥做法是在“Rollback”阶段再加一个 Custom Action专门清理这些残留。Advanced Installer 的“Custom Actions”页支持设置“Rollback”时机把清理脚本挂上去。我一般会写一个Cleanup-OnRollback.ps1内容就是反向操作停服务、删服务、删注册表键、删安装目录。注意这个脚本必须用-ErrorAction SilentlyContinue包住所有命令因为回滚时环境可能已经半损坏报错会掩盖真正的问题。从那以后我每次打 MSI 包都强制走一遍“编译 → 签名 → 在干净虚拟机上静默安装 → 跑验证脚本 → 故意让验证失败测回滚”这个完整流程。少一步客户现场就可能多一个通宵。希望帮到你。本文还有配套的精品资源点击获取
返回列表