msiexec MsiSetExternalUI 的外部处理程序

External handler for msiexec MsiSetExternalUI

早上好,

我希望为 msiexec 实现外部处理程序,但不会阻止 msiexec 执行任何不同的操作。我希望能够使用 MsiSetExternalUI 拦截所有消息,但仍然对最终用户有相同的响应和对话。

我的主要目标是拦截安装 msi 的缓存源并将它们移动到另一个位置。

我已经尝试利用日志记录注册表项来使用日志记录,但是包的源位置可能会被删除,并且当我截获日志文件并获得 msi 的位置时,包的源将不存在。

例如,在安装程序 exe 中嵌入 msi,尤其是旧的 C++ 可再发行组件,使用 redist 将它们自己解压缩到主驱动器根目录上的随机目录并安装,然后在完成后删除该目录。 msiexec 的行为不一致,因为大多数包缓存在 windows 安装程序目录 c:\windows\installer 中,而原始包缓存在 c:\programdata\cached 包中。

为什么有些包被缓存而有些没有?

因此我想使用外部 UI 的原因,但要确保行为保持不变。

我目前正在使用

测试一个项目

MsiInterop.MsiSetExternalUI(新 MsiInstallUIHandler(_OnExternalUI), MsiInstallLogMode.ExternalUI, IntPtr.Zero);

任何想法或例子都会很有帮助。

"Intent"

我们在部署中遇到了一些问题,人们告诉我们他们在做什么在做什么,而不是他们是什么 打算有时这会导致我们写出无法回答问题的详尽答案。我希望这里不是这种情况。

尝试回答

您想在安装 MSI 期间找到在 %SystemRoot%\Installer 下缓存的 MSI 的确切路径吗?

我从未尝试过,但 saschabeaumont 很久以前发布了一个 VBScript,它似乎试图做你想做的事(尽管不是在安装过程中):WiX Custom Action - MSI copy itself.我从来没有尝试过这个脚本,也不想推荐它。

关于 C++ redist 的东西:我不确定他们到底在做什么,但是 Microsoft 倾向于一直重写他们自己的规则并且他们做了一些事情 - 有时 - 分析时没有任何意义。我不会花太多时间去理解它——除非你绝对必须这样做。只是我的 2 美分。


我们可以问一个显而易见的问题:为什么你需要这个副本? 也许有更好的方法来实现你想要的?下面是用于缓存 MSI 文件的不同文件夹和一些 link 的小概览,其中包含有关 MsiSetExternalUI 的信息。


MsiSetExternalUI

我看不出您需要如何像使用 MsiSetExternalUI 那样访问日志来实现 MSI 文件缓存,但这里有一些 link 供其使用:


有关 MSI 缓存的更多信息

多种形式的 MSI 缓存 - 一些内置于 Windows 安装程序中,另一些由第三方工具实现,某些 Microsoft 工具有自己的部署方式事情(例如Visual Studio)。

这里有一些关于如何在您的系统上缓存 MSI 文件的提示。这绝不是完整的,但这是我可以从脑海中记下的内容:

1。 Windows 安装程序(msiexec.exe)缓存

有一个 built-in Windows 安装程序功能可以在安装期间缓存原始 MSI 安装数据库的副本。这个缓存的副本曾经被删除了内部 CAB 文件(使它们比原始文件小得多),但是 this changed around Windows 7 and the MSI copies are now cached full-size(有关详细信息,请关注 link)。

缓存MSI的文件夹是:%SystemRoot%\Installer(通常是C:\Windows\Installer)。每个 MSI 都分配有一个随机的十六进制名称。 所有 MSI 文件都会进入此缓存文件夹 - 除非在安装或产品注册过程中出现问题。 此文件夹中缺少 MSI 文件是一个严重的问题 - 产品通常 un-uninstallable 和 un-upgradeable。我们开始看到某些安全软件从该文件夹中隔离 MSI 文件时出现问题 - 处理起来可能是一场噩梦 - 但这不是这个答案的重点。

除此 built-in 机制外,第三方供应商可能会将原始安装 MSI 缓存在其他位置 以及此 built-in 缓存文件夹 。这是为了支持修复、修补和修改操作,而无需 "source media" 的任何请求。非常适合家庭和小型办公室用户,但企业用户可能不会喜欢它,因为企业用户可以从所有工作站访问网络共享上的所有安装源(他们不喜欢这样的本地副本)。为了实现这一点,他们通常使用 MSI's built-in administrative installation feature - essentially a standardized way to create a network location share to trigger the installation from with extracted files (there is a another description of administrative installations here——也许比第一个更实用。

更新:老实说,我认为源文件的可选缓存应该从一开始就内置到Windows安装程序中 并成为默认的命令行选项(适用于家庭和小型办公室用户),然后一个简单的标志可以轻松防止所有企业用户进行此类缓存(例如 NOSOURCECACHING = 1)。另外:now that MSI files are cached full-size in %SystemRoot%\Installer - 似乎您仍然无法 auto-magically 从那里获取源文件? (最近未测试)。这是怎么回事?文件在那里 - 除非安装是从管理映像发生的(在这种情况下,源可能安全地位于网络共享上并且在需要时可以访问,因此可以避免本地 PC 混乱)。哦,好吧,将来我们无疑会直接从在线存储库中提取文件 on-demand,这样一个问题就解决了,一堆新问题正在酝酿中?恶意软件、欺骗和注入?远程文件在没有警告的情况下被删除(以摆脱不应再使用的易受攻击的版本 - 让用户陷入困境)?证书和签名问题?防火墙和代理问题? Auto-magic 更新时不幸的错误立即袭击了所有人?只是咆哮:-)。我相信这在很大程度上会有所改善。无论如何,继续以下部分中的当前第三方缓存方法(不是 MSI 标准)。

2。 WiX 缓存

WiX 捆绑功能(刻录)可以在系统上缓存 MSI 文件。老实说,我不是 100% 确定他们是怎么做到的,我希望 ArnsonMensching 可以 在这里纠正我,如果我我错了。但是,我相信他们使用: %ProgramData%\Package Cache(通常是 C:\ProgramData\Package 缓存)用于它们的缓存。我的系统上有很多不同的微软组件,我不确定它们是否都与 WiX 一起打包。

3。安装屏蔽缓存

Installshield 可以在 %SystemRoot%\Downloaded Installations 中为某些类型的构建配置缓存原始 MSI 文件。换句话说:并非所有 Installshield 安装程序都会以这种方式缓存自己 - 这是一个 Installshield 项目构建设置,可以根据安装程序开发人员的需要打开或关闭。

更新:似乎较新版本的 Installshield 现在可能默认缓存设置在 %LocalAppData%\Downloaded Installations(通常是 C:\Users\YOURUSERNAME\AppData\Local\Downloaded 安装)而不是 %SystemRoot%\Downloaded Installations。我不确定哪个版本切换到了这个位置。也许 Michael Urman 的 Installshield 可以帮助我们?

4。高级安装程序缓存

Bogdan Mitrache of Advanced Installer (many thanks - now it is accurate): The easiest way to get/copy of an MSI from an Advanced Installer built EXE is to use the /extract command line option 添加。

在安装时,对于 EXE 构建(MSI 捆绑在 EXE 中)高级安装程序默认在此位置提取内容:

[AppDataFolder][|Manufacturer]\[|ProductName] [|ProductVersion]\install.

如您所见,它取决于供应商,因此每个包的路径都不同。

此外,此路径可从安装项目中自定义,因此用户可以更改它(大多数时候他们不会)。

还有一个选项可以在安装完成后删除提取的资源,这也是用户可配置的,默认情况下启用。

如果您使用高级安装程序构建标准 MSI,则缓存由 Windows 安装程序完成,如上所述。

5。 Visual Studio缓存

Visual Studio 似乎在以下位置缓存包:%AllUsersProfile%\Microsoft\VisualStudio\Packages(通常是 C:\ProgramData\Microsoft\VisualStudio\Packages)。除了正在使用的这个文件夹之外,我真的不知道他们是如何做的。这里也有包: %ProgramData%\Microsoft\VisualStudio\Packages.

更新:文件夹 %ProgramData%\Microsoft\VisualStudio\Packages 似乎与上面的位置相同 (%AllUsersProfile%\Microsoft\VisualStudio\Packages)使用符号 link(文件夹指向磁盘上的相同文件和文件夹)。也可以按照 Heath Stewart 的描述禁用此缓存:Moving or disabling the package cache for Visual Studio 2017.

这对我来说是 non-MSI 而不是 well-known: %ProgramFiles(x86)%\Microsoft SDKs\NuGetPackagesFallback

6.其他缓存文件夹?

Apple:我不太了解,但似乎 Apple 可能使用此文件夹来缓存他们的一些 MSI 安装程序:%LocalAppData% \Apple\Apple Software Update\(通常是 C :\Users\Acer\AppData\Local\Apple\Apple 软件更新).

Sun:似乎 Sun 使用这个基本文件夹来缓存 Java 安装 MSI 文件:%UserProfile%\AppData\LocalLow\Oracle\Java(通常是 C:\Users\Acer\AppData\LocalLow\Oracle\Java) .

毫无疑问还有许多其他缓存文件夹正在使用。

谢谢 Bogdan 和 Stein,我不知道使用不同缓存文件夹的不同类型的安装程序。

我想出了一个半解决方案,通过外部重定向和附加 UI。我决定只设置某些标志

ExternalUINoDialog = FatalExit | Error | Warning | User | CommonData | Progress from Interop in the msiexec

这也允许用户输入对话框中的标准行为。我还根据从参数接收到的开关设置内部 UI。

我注意到一些随机和孤立的案例,例如 Microsoft 的奇妙使用方式:

MsiExec.exe -Embedding /V

有人知道开关嵌入的内容吗?我已尝试搜索,但主要搜索总是返回病毒问题和 msiexec?

是否有人知道 MSDN 上的文档?我看过 msiexec /?但没有提到 -embedding?

我不明白为什么拦截 UI 与安装过程中无法更改的缓存位置有任何关系。但是,尚不清楚 "cache" 您在这里打算使用什么。我假设您指的是完整的 MSI 文件,该文件可能已提取到某个位置进行安装,或者位于其安装位置。

让我们假设安装已经完成并且您知道(或可以获得)它的 ProductCode。要获取所有官方源位置,您需要做的就是调用 MsiSourceListEnumSources (),它将告诉您 Windows 将在需要时用于查找 MSI 以进行维护、升级、修复等的实际位置。

如果源 MSI 位于您不同意的位置,则使用 MsiSourceListClearSource () 删除该条目,将 MSI 复制到您选择的位置,然后使用 MsiSourceListAddSource () 添加该位置。有大量的源列表 API 正是用于这种类型的管理 activity,例如当产品从不再可用的网络位置安装时。

我认为您不应该移动或更改通常位于 \windows\installer 中的内部缓存(混淆名称)MSI 文件。我们有时将其称为缓存位置,但您似乎指的是用于安装产品的完整 MSI。