windows-installerinstallationorcamsitransform

Simplest solution to replace a tiny file inside an MSI?


Many of our customers have access to InstallShield, WISE or AdminStudio. These aren't a problem. I'm hoping there is some way I can provide our smaller customers without access to commercial repackaging tools a freely available set of tools and steps to do the file replacement themselves.

Only need to replace a single configuration file inside a compressed MSI, the target user can be assumed to already have Orca installed, know how to use this to customize the Property table (to embed license details for GPO deployment) and have generated an MST file.



Disclaimer: this is very similar to another question but both questions and answers in that thread are not clear.


Solution

  • Okay, revisiting this question with my own answer providing nice little VB script that will do all heavy lifting. As mentioned in the original question, the aim was provide a simple solution for sysadmin users to make the updates/changes themselves.

    Below is a simplified version of the code I'm currently providing to customers

    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
    

    Update: The MakeCab.MakeCab.1 object has been depreciated, code updated to now work with Windows 7.