问题 更换MSI内部的小文件最简单的解决方案?


我们的许多客户都可以访问InstallShield,WISE或AdminStudio。这些不是问题。我希望有一些方法可以为我们的小客户提供服务 无法访问商业重新包装工具 一套免费的工具和步骤来自行更换文件。

只需要在压缩的MSI中替换单个配置文件,可以假定目标用户已经安装了Orca,知道如何使用它来自定义Property表(嵌入GPO部署的许可证详细信息)并生成MST文件。



放弃这非常相似 另一个问题 但该线程中的问题和答案都不清楚。


13046
2017-11-26 06:19


起源



答案:


好的,用我自己的答案重新审视这个问题提供了一个很好的小VB脚本,它将完成所有繁重的工作。正如原始问题中所提到的,目标是为系统管理员用户提供一个简单的解决方案,以便自己进行更新/更改。

以下是我目前向客户提供的代码的简化版本

Option Explicit

Const MY_CONFIG = "MyConfigApp.xml"
Const CAB_FILE = "config.cab"
Const MSI = "MyApp.msi"

Dim filesys : Set filesys=CreateObject("Scripting.FileSystemObject")

If filesys.FileExists("temp.tmp") Then filesys.DeleteFile("temp.tmp")
filesys.CopyFile MSI, "temp.tmp"

Dim installer, database, database2, view
Set installer = CreateObject("WindowsInstaller.Installer")
Set database = installer.OpenDatabase ("temp.tmp", 1)
Set database2 = installer.OpenDatabase (MSI, 1)

If Not filesys.FileExists(MY_CONFIG) Then WScript.Quit 2 ' No config file, abort!

Dim objFile, size, result, seq, objCab

' MakeCab object has been depreciated so we fallback to makecab.exe for with Windows 7
On Error Resume Next ' Disable error handling, for a moment
Set objCab = CreateObject("MakeCab.MakeCab.1") 
On Error Goto 0  ' Turn error handling back on

If IsObject(objCab) Then ' Object creation successful - use XP method   
    objCab.CreateCab CAB_FILE, False, False, False
    objCab.AddFile MY_CONFIG, filesys.GetFileName(MY_CONFIG)
    objCab.CloseCab
    Set objCab = Nothing
Else ' object creation failed - try Windows 7 method
    Dim WshShell, oExec
    Set WshShell = CreateObject("WScript.Shell")
    Set oExec = WshShell.Exec("makecab " & filesys.GetFileName(MY_CONFIG) & " " & CAB_FILE)
End If

Set objFile = filesys.GetFile(MY_CONFIG)
size = objFile.Size

Set view = database.OpenView ("SELECT LastSequence FROM Media WHERE DiskId = 1")
view.Execute
Set result = view.Fetch
seq = result.StringData(1) + 1 ' Sequence for new configuration file

Set view = database.OpenView ("INSERT INTO Media (DiskId, LastSequence, Cabinet) VALUES ('2', '" & seq & "', '" & CAB_FILE & "')")
view.Execute

Set view = database.OpenView ("UPDATE File SET FileSize = " & size & ", Sequence = " & seq & ", FileName = 'MYC~2.CNF|MyConfigApp.xml' WHERE File = '" & MY_CONFIG & "'")
view.Execute

database.GenerateTransform database2, "CustomConfig.mst"
database.CreateTransformSummaryInfo database2, "CustomConfig.mst", 0, 0
filesys.DeleteFile("temp.tmp")

Set view = nothing
Set installer = nothing
Set database = nothing
Set database2 = nothing
Set filesys = Nothing
WScript.Quit 0

更新: 该 MakeCab.MakeCab.1 对象已被折旧,代码已更新,现在可与Windows 7一起使用。


9
2018-02-06 04:21



你能解释一下:MY_CONFIG是你要替换的文件,CAB_FILE是MSI里面的媒体文件......对吗? - PawanS


答案:


好的,用我自己的答案重新审视这个问题提供了一个很好的小VB脚本,它将完成所有繁重的工作。正如原始问题中所提到的,目标是为系统管理员用户提供一个简单的解决方案,以便自己进行更新/更改。

以下是我目前向客户提供的代码的简化版本

Option Explicit

Const MY_CONFIG = "MyConfigApp.xml"
Const CAB_FILE = "config.cab"
Const MSI = "MyApp.msi"

Dim filesys : Set filesys=CreateObject("Scripting.FileSystemObject")

If filesys.FileExists("temp.tmp") Then filesys.DeleteFile("temp.tmp")
filesys.CopyFile MSI, "temp.tmp"

Dim installer, database, database2, view
Set installer = CreateObject("WindowsInstaller.Installer")
Set database = installer.OpenDatabase ("temp.tmp", 1)
Set database2 = installer.OpenDatabase (MSI, 1)

If Not filesys.FileExists(MY_CONFIG) Then WScript.Quit 2 ' No config file, abort!

Dim objFile, size, result, seq, objCab

' MakeCab object has been depreciated so we fallback to makecab.exe for with Windows 7
On Error Resume Next ' Disable error handling, for a moment
Set objCab = CreateObject("MakeCab.MakeCab.1") 
On Error Goto 0  ' Turn error handling back on

If IsObject(objCab) Then ' Object creation successful - use XP method   
    objCab.CreateCab CAB_FILE, False, False, False
    objCab.AddFile MY_CONFIG, filesys.GetFileName(MY_CONFIG)
    objCab.CloseCab
    Set objCab = Nothing
Else ' object creation failed - try Windows 7 method
    Dim WshShell, oExec
    Set WshShell = CreateObject("WScript.Shell")
    Set oExec = WshShell.Exec("makecab " & filesys.GetFileName(MY_CONFIG) & " " & CAB_FILE)
End If

Set objFile = filesys.GetFile(MY_CONFIG)
size = objFile.Size

Set view = database.OpenView ("SELECT LastSequence FROM Media WHERE DiskId = 1")
view.Execute
Set result = view.Fetch
seq = result.StringData(1) + 1 ' Sequence for new configuration file

Set view = database.OpenView ("INSERT INTO Media (DiskId, LastSequence, Cabinet) VALUES ('2', '" & seq & "', '" & CAB_FILE & "')")
view.Execute

Set view = database.OpenView ("UPDATE File SET FileSize = " & size & ", Sequence = " & seq & ", FileName = 'MYC~2.CNF|MyConfigApp.xml' WHERE File = '" & MY_CONFIG & "'")
view.Execute

database.GenerateTransform database2, "CustomConfig.mst"
database.CreateTransformSummaryInfo database2, "CustomConfig.mst", 0, 0
filesys.DeleteFile("temp.tmp")

Set view = nothing
Set installer = nothing
Set database = nothing
Set database2 = nothing
Set filesys = Nothing
WScript.Quit 0

更新: 该 MakeCab.MakeCab.1 对象已被折旧,代码已更新,现在可与Windows 7一起使用。


9
2018-02-06 04:21



你能解释一下:MY_CONFIG是你要替换的文件,CAB_FILE是MSI里面的媒体文件......对吗? - PawanS


我假设您自己创建msi文件(?)

当你使用 维克斯 为了生成你的msi,客户可以在替换文件后简单地重新生成整个msi(wix是免费的)。否则,应该可以使用未嵌入在msi中的未压缩文件。在wix中你必须添加一个 媒体元素 没有cabinet属性。缺点是你必须分发两个文件,而不是一个msi。


2
2017-11-26 10:12





恕我直言,这种情况表明正在安装的应用程序中缺少一项功能,并且比使用MSI进行攻击更容易在应用程序中修复。


管理员图片

我首先要说的是,为用户“解决”这个问题的简单方法是告诉他们运行MSI的管理员安装。这实际上将从内部CAB中提取所有文件,并将所有文件放在指定的文件夹中:

msiexec.exe / a myinstaller.msi TARGETDIR = C:\ AdminImage

然后,您的用户可以直接进入解压缩的文件夹结构并更新相关文件,然后将目录映射到其他PC并安装MSI。对于文件在MSI中具有哈希值(以避免欺骗)可能存在副作用,但在大多数情况下它工作正常。


运行XML XPath查询

新版本的部署工具(如Installshield和Wix)具有内置支持,可在安装期间运行XPath查询,从而动态编写部分。


应用更新

在PC上设置应用程序涉及几个步骤。首先是内容部署到机器 - 这应该使用MSI完成,毫无疑问。但是,在大多数高级应用程序中,需要几个类似于“配置文件更新”的“安装后配置任务”。

推迟这些配置任务几乎总是更好 申请发布而不是在MSI中实现功能。这有很多原因,但最重要的是只保证应用程序EXE在正确的用户上下文中运行。 MSI文件可以使用系统权限,不同的用户帐户或其他机制运行。

我们通常建议使用MSI 将所有必需的内容放到PC上。然后标记注册表以向应用程序指示它是第一次启动(对于更新,您可以递增计数器或将新版本号写入HKLM)。然后,应用程序可以在其启动例程中执行最终配置步骤。它可以从%ProgramFiles%中的某个位置复制默认的config.xml文件,并将其复制到用户配置文件中。然后,它可以从MSI编写的HKLM中读取所需的值,然后使用这些值更新config.xml文件。

通常:避免由MSI或任何其他设置机制执行的配置步骤。专注于将所需的文件和注册表项写入计算机,然后让应用程序本身设置适当的运行时环境。这将允许更好的部署控制。如果你愿意,它更好“封装”。 MSI通过注册表向应用程序发送“消息”,并且应用程序根据消息知道“如何正确设置自己”。


2
2018-06-28 22:11



就我而言,我正在更新AllUsers / AppData文件夹中的全局“默认配置”。首次启动时会复制到每个用户的位置。配置文件是专有格式的二进制数据,根本不是安装后配置 - 它设置安装后首次运行配置的默认值(一旦用户配置存在,系统默认配置将被忽略)。这个问题最初被问到,因为在InstallShield中这是一个简单的拖放操作,但是我们已经迁移到WiX并且需要为我们的客户提供一种简单的方法来实现它。 - saschabeaumont


你需要添加一个条目 媒体 表,添加另一个没有cabinet文件的介质,以及一个比CAB文件的最后一个序列多一个的LastSequence。然后你需要更换 文件 使用新文件表示文件的序列,并更新可能已更改的所有其他文件属性。


1
2017-11-26 07:30



这不是很有效,当添加没有cabinet文件的媒体时,我得到“错误2920.没有为文件<filename>指定源目录”但是它 不 如果我使用橱柜文件,我会工作。建议? - saschabeaumont


查看以下帖子: 如何在msi安装程序中替换文件?

提到的地方:

此命令提取MSI文件: msi2xml -c OutputDir TestMSI.MSI

打开OutputDir并修改文件。

要重建MSI运行: xml2msi.exe -m TestMSI.xml

您需要-m忽略在修改MSI文件时失败的“MD5校验和测试”。

下载: https://msi2xml.sourceforge.io/


1
2018-06-18 17:27