【问题标题】:Simplest solution to replace a tiny file inside an MSI?替换 MSI 中的小文件的最简单解决方案?
【发布时间】:2008-11-26 06:19:19
【问题描述】:

我们的许多客户都可以使用 InstallShield、WISE 或 AdminStudio。这些都不是问题。我希望有某种方法可以为我们的小客户提供无需使用商业重新打包工具一套免费提供的工具和步骤,让他们自己进行文件替换。

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



免责声明这与another question 非常相似,但该线程中的问题和答案都不清楚。

【问题讨论】:

    标签: windows-installer installation orca msitransform


    【解决方案1】:

    好的,用我自己的答案重新审视这个问题,提供了可以完成所有繁重工作的漂亮的小 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 上使用。

    【讨论】:

    • 您能解释一下:MY_CONFIG 是您要替换的文件,CAB_FILE 是 MSI 中的媒体文件...对吗?
    【解决方案2】:

    恕我直言,这种情况表明正在安装的应用程序中缺少功能,并且在应用程序中修复比使用 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 通过注册表向应用程序发送“消息”,应用程序根据这些消息知道“如何正确设置自己”。

    【讨论】:

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

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

    当您使用Wix 生成您的 msi 时,客户可以在替换文件后简单地重新生成整个 msi(wix 是免费的)。否则应该可以使用未嵌入在 msi 中的未压缩文件。在 wix 中,您必须添加不带橱柜属性的 media element。缺点是您必须分发两个文件,而不是单个 msi。

    【讨论】:

      【解决方案4】:

      您需要在Media 表中添加一个条目,添加另一个没有cabinet 文件的媒体,并且LastSequence 比CAB 文件的最后一个序列多一个。然后您需要用新文件替换File 表中的文件序列,并更新所有其他可能已更改的文件属性。

      【讨论】:

      • 这不太行,当添加没有压缩文件的媒体时,我得到“错误 2920。未为文件 指定源目录”但是它确实工作如果我使用橱柜文件。有什么建议吗?
      【解决方案5】:

      查看以下帖子: How to replace a file in a msi installer?

      在哪里提到:

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

      打开 OutputDir 并修改文件。

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-28
        • 1970-01-01
        • 1970-01-01
        • 2010-09-05
        • 2013-03-04
        • 1970-01-01
        • 1970-01-01
        • 2019-10-17
        相关资源
        最近更新 更多