Modify msi Summary Information stream via transform
I need to remove "require elevated privileges" tick from msi's Summary Information Stream. Is it possible? The reason why i need this is to avoid UAC initiation. Files and registry are put into per-user location and no CAs which alter system.
Would appreciate any help.
1 Comment
[ + ] Show comment
-
wrong place - Saimon 7 years ago
Answers (5)
Answer Summary:
Please log in to answer
Posted by:
786_ak
7 years ago
Can't you select "No"? Also, look into "Install Condition" under "General" tab on the top to see if there is a condition listed as AdminUsers. But I don't think you'll be able to achieve the results that you are trying to get.
Best of luck.
AK
Comments:
-
Thanks, AK. Unfortunately best practices says i should not modify original msi but provide transform to inject any changes. Original msi already have "require elevated privileges" option set to "yes" and transform can not typically modify Summary information. - Saimon 7 years ago
Posted by:
anonymous_9363
7 years ago
Removing that flag won't prevent UAC prompts. Start reading here.
Comments:
-
Thank you for your reply. I may have confused simple windows "request elevated privileges" dialog with actual UAC. Message saying "this application is about to alter your system" or something is totally ok for me. The second one asking for credentials is a problem. - Saimon 7 years ago
Posted by:
EdT
7 years ago
Use the session.database method to modify the MSI database via a custom action at install time. The custom action can be placed in a transform which should meet your requirements and no one need know that the actual MSI will be modified as it gets cached.
Comments:
-
Thank you for your response. Can session.database method alter Summary information stream? I remember i saw some vb code actions changing Property value, and i heard that it's possible to read Summary Information stream but not sure if it can be changed. Could you please give me some code sample on this? - Saimon 7 years ago
Posted by:
EdT
7 years ago
Top Answer
Saimon - all this information can be found by using google, but actually it can be done more simply by using the windows installer object. Here is a bit of code I used a few years ago to migrate MSI templates to a new standard: Look for the section of code headed: 'modify the original msi's summary info stream.
' Windows Installer utility to update old style MSI templates to the latest
' For use with Windows Scripting Host, CScript.exe or WScript.exe
Option Explicit
' FileSystemObject.CreateTextFile and FileSystemObject.OpenTextFile
Const OpenAsASCII = 0
Const OpenAsUnicode = -1
' FileSystemObject.CreateTextFile
Const OverwriteIfExist = -1
Const FailIfExist = 0
' FileSystemObject.OpenTextFile
Const OpenAsDefault = -2
Const CreateIfNotExist = -1
Const FailIfNotExist = 0
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8
' Installer.OpenDatabase
Const msiOpenDatabaseModeReadOnly = 0
Const msiOpenDatabaseModeTransact = 1
' View.Modify
Const msiViewModifyInsert = 1
Const msiViewModifyUpdate = 2
Const msiViewModifyAssign = 3
Const msiViewModifyReplace = 4
Const msiViewModifyDelete = 6
' Installer.UILevel
Const msiUILevelNone = 2
' Session.Mode
Const msiRunModeSourceShortNames = 9
Const msidbFileAttributesNoncompressed = &h00002000
Const msidbFileAttributesCompressed = &h00004000
'Test arguments are valid
TestValidArguments()
'Set up global vars
Dim databasePath : databasePath = Wscript.Arguments(0) ' The path to the original MSI
Dim fileOriginalMSI, oOldDatabase 'objects to point to original database
Dim fso : Set fso = Createobject("Scripting.FileSystemObject") 'general purpose FileSystemObject
Set fileOriginalMSI = fso.GetFile(databasePath) 'The name of the original MSI
Dim TempMSI : TempMSI = fileOriginalMSI.ParentFolder & "\" & fso.GetTempName ' get a path for a safe temp file
Dim basename : basename = Left(fileOriginalMSI.Name, InStrRev(fileOriginalMSI.Name, ".") -1) ' e.g. file.msi -> file
Dim cabFile : cabFile = basename & ".CAB"
fileOriginalMSI.Copy(TempMSI) 'Make a backup of the MSI to work on
On Error Resume Next
' Connect to Windows Installer object
Dim installer
Set installer = Wscript.CreateObject("WindowsInstaller.Installer") : CheckError
Dim database, view, record, updateMode, sumInfo, sequence, lastSequence
' Open database
Set database = installer.OpenDatabase(TempMSI, msiOpenDatabaseModeTransact) : CheckError
' set the file attribute to compressed in File Table
set view = database.OpenView("SELECT Attributes FROM File") : CheckError
View.Execute : CheckError
dim attrib
Do
Set record = view.Fetch
If record Is Nothing Then Exit Do
attrib = Record.IntegerData(1)
If (attrib And msidbFileAttributesNoncompressed) <> 0 Then
'Record.IntegerData(1) = attrib - msidbFileAttributesNoncompressed + msidbFileAttributesCompressed
attrib = attrib - msidbFileAttributesNoncompressed + msidbFileAttributesCompressed
Record.IntegerData(1) = attrib
'wscript.echo "Check for Non Compressed - Attrib = "&attrib&" Record = "&Record.IntegerData(1)
view.Modify msiViewModifyUpdate, Record
end if
if (attrib And msidbFileAttributesCompressed) = 0 Then
'Record.IntegerData(1) = attrib + msidbFileAttributesCompressed
attrib = attrib + msidbFileAttributesCompressed
Record.IntegerData(1) = attrib
'wscript.echo "Check for Compressed - Attrib = "&attrib&" Record = "&Record.IntegerData(1)
view.Modify msiViewModifyUpdate, Record
End If
loop
database.Commit : CheckError
'resequence the File Table if necessary
set view = database.OpenView("SELECT Sequence FROM File ORDER BY Sequence") : CheckError
View.Execute : CheckError
Set record = view.Fetch : CheckError
Dim X : X = 1
Do
If X <> Record.IntegerData(1) Then 'File Table needs resequencing
'reset the view
View.Execute : CheckError
Set record = view.Fetch : CheckError
X=1
Do 'reset the sequence numbers
Record.IntegerData(1) = X
view.Modify msiViewModifyUpdate,Record
Set record = view.Fetch : CheckError
X=X+1
Loop While not (record Is Nothing )
database.Commit : CheckError
Exit Do 'Finished resequencing
End If
X=X+1
Set record = view.Fetch : CheckError
loop while not (record Is Nothing )
' Create an install session and execute actions in order to perform directory resolution
installer.UILevel = msiUILevelNone
Dim session : Set session = installer.OpenPackage(database) : If Err <> 0 Then Fail "Database: " & TempMSI & ". Invalid installer package format"
Dim shortNames : shortNames = session.Mode(msiRunModeSourceShortNames) : CheckError
Dim stat : stat = session.DoAction("CostInitialize") : CheckError
If stat <> 1 Then Fail "CostInitialize failed, returned " & stat
' Join File table to Component table in order to find directories
Set view = database.OpenView("SELECT File,FileName,Directory_,Sequence,File.Attributes FROM File,"&_
"Component WHERE Component_=Component ORDER BY File.Sequence" ) : CheckError
view.Execute : CheckError
' Create DDF file and write header properties
Dim compressType : compressType = "MSZIP"
Dim cabSize : cabSize = "CDROM"
Dim FileSys : Set FileSys = CreateObject("Scripting.FileSystemObject") : CheckError
Dim outStream : Set outStream = FileSys.CreateTextFile(baseName & ".DDF", OverwriteIfExist, OpenAsASCII) : CheckError
outStream.WriteLine "; Generated from " & TempMSI & " on " & Now
outStream.WriteLine ".Set CabinetNameTemplate=" & baseName & "*.CAB"
outStream.WriteLine ".Set CabinetName1=" & cabFile
outStream.WriteLine ".Set ReservePerCabinetSize=8"
outStream.WriteLine ".Set MaxDiskSize=" & cabSize
outStream.WriteLine ".Set CompressionType=" & compressType
outStream.WriteLine ".Set InfFileLineFormat=(*disk#*) *file#*: *file* = *Size*"
outStream.WriteLine ".Set InfFileName=" & baseName & ".INF"
outStream.WriteLine ".Set RptFileName=" & baseName & ".RPT"
outStream.WriteLine ".Set InfHeader="
outStream.WriteLine ".Set InfFooter="
outStream.WriteLine ".Set DiskDirectoryTemplate=."
outStream.WriteLine ".Set Compress=ON"
outStream.WriteLine ".Set Cabinet=ON"
' Fetch each file and request the source path, then verify the source path
Dim fileKey, fileName, folder, sourcePath, delim, message, attributes
Do
Set record = view.Fetch : CheckError
If record Is Nothing Then Exit Do
fileKey = record.StringData(1)
fileName = record.StringData(2)
folder = record.StringData(3)
sequence = record.IntegerData(4)
attributes = record.IntegerData(5)
If sequence <= lastSequence Then
Fail "Duplicate sequence numbers in File table"
sequence = lastSequence + 1
record.IntegerData(4) = sequence
view.Modify msiViewModifyUpdate, record
End If
lastSequence = sequence
delim = InStr(1, fileName, "|", vbTextCompare)
If delim <> 0 Then
If shortNames Then fileName = Left(fileName, delim-1) Else fileName = Right(fileName, Len(fileName) - delim)
End If
sourcePath = session.SourcePath(folder) & fileName
outStream.WriteLine """" & sourcePath & """" & " " & fileKey
If installer.FileAttributes(sourcePath) = -1 Then message = message & vbNewLine & sourcePath
Loop
outStream.Close
Set Session = Nothing
If Not IsEmpty(message) Then Fail "The following files were not available:" & message
' Generate compressed file cabinet
Dim WshShell : Set WshShell = Wscript.CreateObject("Wscript.Shell") : CheckError
Dim cabStat : cabStat = WshShell.Run("MakeCab.exe /f " & baseName & ".DDF", 1, True) : CheckError
If cabStat <> 0 Then Fail "MAKECAB.EXE failed, possibly could not find source files, or invalid DDF format"
' Update Media table
Set view = database.OpenView("SELECT DiskId, LastSequence, Cabinet FROM Media ORDER BY DiskId") : CheckError
view.Execute : CheckError
updateMode = msiViewModifyUpdate
Set record = view.Fetch : CheckError
If record Is Nothing Then ' Media table empty
Set record = Installer.CreateRecord(3)
record.IntegerData(1) = 1
updateMode = msiViewModifyInsert
End If
record.IntegerData(2) = lastSequence
record.StringData(3) = cabFile
view.Modify updateMode, record
' Commit database in case updates performed
database.Commit : CheckError
'make the transform
Dim TransformPath
TransformPath = fileOriginalMSI.ParentFolder & "\" & BaseName & "_cabgen.mst"
Set oOldDatabase = Installer.OpenDatabase(databasePath,msiOpenDatabaseModeTransact)
Database.GenerateTransform oOldDatabase, TransformPath : CheckError
'generate the transform summary info stream
Database.CreateTransformSummaryInfo oOldDatabase, TransformPath, 0, 0 : CheckError
Set Database = Nothing 'done with it
'modify the original msi's summary info stream
Set sumInfo = oOldDatabase.SummaryInformation(3) : CheckError
sumInfo.Property(11) = Now
sumInfo.Property(13) = Now
sumInfo.Property(15) = clng(sumInfo.Property(15) Or 2) 'set the compressed bit
sumInfo.Property(15) = clng(sumInfo.Property(15) And Not 4) 'remove any admin bit
sumInfo.Persist
Set sumInfo = Nothing ' must release stream
oOldDatabase.commit
'done, report it
DIM ReportFile
Set ReportFile = fso.OpenTextFile(fileOriginalMSI.ParentFolder & "\" &baseName & ".RPT", 1)
Wscript.Echo "Made "& cabFile &_
vbNewLine &_
vbNewLine & ReportFile.ReadAll &_
vbNewLine &_
vbNewLine & TransformPath & " Transform created for modified "&_
vbNewLine & "Media and Files Tables" &_
vbNewLine &_
vbNewLine
Set ReportFile = Nothing
'cleanup
DIM File
Set File = fso.GetFile(fileOriginalMSI.ParentFolder & "\" & BaseName & ".ddf")
File.Delete
Set File = fso.GetFile(fileOriginalMSI.ParentFolder & "\" & BaseName & ".inf")
File.Delete
Set File = fso.GetFile(fileOriginalMSI.ParentFolder & "\" & BaseName & ".rpt")
File.Delete
Set File = fso.GetFile(TempMSI) ': CheckError
File.Delete
Wscript.Quit 0
Sub CheckError
Dim message, errRec
If Err = 0 Then Exit Sub
message = Err.Source & " " & Hex(Err) & ": " & Err.Description
If Not installer Is Nothing Then
Set errRec = installer.LastErrorRecord
If Not errRec Is Nothing Then message = message & vbNewLine & errRec.FormatText
End If
Fail message
End Sub
Sub Fail(message)
Wscript.Echo message
Wscript.Quit 2
End Sub
Sub TestValidArguments()
Dim argCount : argCount = Wscript.Arguments.Count
REM Function tests for one argument
REM if
If argCount > 0 Then If InStr(1, Wscript.Arguments(0), "?", vbTextCompare) > 0 Then argCount = 0
If (argCount <> 1) Then
Wscript.Echo "Windows Installer utility to generate compressed file cabinets from MSI database" &_
vbNewLine & " The 1st argument is the path to MSI database, at the source file root" &_
vbNewLine &_
vbNewLine & " Notes:" &_
vbNewLine & " In order to generate a cabinet, MAKECAB.EXE must be on the PATH" &_
vbNewLine &_
vbNewLine & " This Util modifies only the Summary Stream of the original MSI to say that" &_
vbNewLine & " the files are compressed as this is not possible in the transform" &_
vbNewLine &_
vbNewLine & " Does not handle updating of Media table to handle multiple cabinets" &_
vbNewLine & " If your msi has some cabs in it, you should do an Admin install first" &_
vbNewLine &_
vbNewLine & "carlbennett"
Wscript.Quit 1
End If
End Sub
'What needs doing:
Report of differences between original template: C:\Temp\ACME_RT_ADS9_v1.0.ism
and updated template: C:\Temp\RepackagingTemplate_x86.ism
Table = _Validation
Added record ACMEACL | Type.
Added record ACMEACL | Group.
Added record ACMEACL | Permission.
Added record ACMEACL | Object.
Added record ACMEACL | ACL.
Table = AppSearch
Added record INSTALLEDBY | InstalledBy.Sig.
Table = Binary
Added record SetACL.exe.
Added record ACMESetAcl.dll.
Added record ACMEProcessAcl.dll.
Added record ACMERollbackAcl.dll.
Deleted record CATools.dll.
Table = CustomAction
Added record SetInstalledBy.
Added record ACMEProcessAcl.
Added record ACMESetAcl.
Added record ACMERollbackAcl.
Deleted record SetUserProfileNT. (Starts with capital letter, not lower case)
Deleted record SetAllUsersProfile2K. (Starts with capital letter, not lower case)
Deleted record LaunchAppWaitDeferred.
Table = InstallExecuteSequence
Added record setAllUsersProfile2K.
Added record SetAllUsersProfileNT.
Added record SetInstalledBy.
Added record setUserProfileNT.
Table = InstallUISequence
Added record setAllUsersProfile2K.
Added record SetAllUsersProfileNT.
Added record setUserProfileNT.
Table = ISString
Added record ID_STRING7 | 1033.
Added record ID_STRING8 | 1033.
Changed record:
From ID_STRING1 | 1033 | ACME_RT_ADS6_v8.0 | 0 | | 1100694193
To ID_STRING1 | 1033 | Your Name | 0 | | -1163971186
Changed record:
From IDPROP_ARPCOMMENTS | 1033 | This Value is set by the custom action SetARPComments. Any text set here will be ignored. | 0 | | -501675763
To IDPROP_ARPCOMMENTS | 1033 | This database contains the resources and logic to install [enter ProductName value here] | 0 | | -1163944562
Changed record:
From IDPROP_ARPCONTACT | 1033 | ACME GBM Helpdesk | 0 | | 1167778985
To IDPROP_ARPCONTACT | 1033 | ACME Helpdesk | 0 | | -1163950258
Changed record:
From NEW_STRING3 | 1033 | | 0 | | 202810477
To NEW_STRING3 | 1033 | Manufacturer ApplicationName ApplicationVersion | 0 | | -1163979378
Changed record:
From ID_STRING6 | 1033 | ACME CBFM | 0 | | -1273558772
To ID_STRING6 | 1033 | ACME | 0 | | -1163982994
Table = Property
Added record ACMEIsmTemplate.
Deleted record PackageVersion.
Deleted record PackagingLocation.
Changed record:
From ProductName | ACME_RT_ADS7_v8.0 |
To ProductName | RepackagingTemplate_x86 |
Table = Registry
Changed record:
From Registry2 | 2 | SOFTWARE\_ACME\Applications\[ProductName] | InstalledBy | [LogonUser] | SoftwareAudit | 0
To Registry2 | 2 | SOFTWARE\_ACME\Applications\[ProductName] | InstalledBy | [INSTALLEDBY] | SoftwareAudit | 0
Table = RegLocator
Added record InstalledBy.Sig.
Table ACMEACL added.
Posted by:
EdT
7 years ago
Saimon - all this information can be found by using google, but actually it can be done more simply by using the windows installer object. Here is a bit of code I used a few years ago to migrate MSI templates to a new standard: Look for the section of code headed: 'modify the original msi's summary info stream.
' Windows Installer utility to update old style MSI templates to the latest
' For use with Windows Scripting Host, CScript.exe or WScript.exe
Option Explicit
' FileSystemObject.CreateTextFile and FileSystemObject.OpenTextFile
Const OpenAsASCII = 0
Const OpenAsUnicode = -1
' FileSystemObject.CreateTextFile
Const OverwriteIfExist = -1
Const FailIfExist = 0
' FileSystemObject.OpenTextFile
Const OpenAsDefault = -2
Const CreateIfNotExist = -1
Const FailIfNotExist = 0
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8
' Installer.OpenDatabase
Const msiOpenDatabaseModeReadOnly = 0
Const msiOpenDatabaseModeTransact = 1
' View.Modify
Const msiViewModifyInsert = 1
Const msiViewModifyUpdate = 2
Const msiViewModifyAssign = 3
Const msiViewModifyReplace = 4
Const msiViewModifyDelete = 6
' Installer.UILevel
Const msiUILevelNone = 2
' Session.Mode
Const msiRunModeSourceShortNames = 9
Const msidbFileAttributesNoncompressed = &h00002000
Const msidbFileAttributesCompressed = &h00004000
'Test arguments are valid
TestValidArguments()
'Set up global vars
Dim databasePath : databasePath = Wscript.Arguments(0) ' The path to the original MSI
Dim fileOriginalMSI, oOldDatabase 'objects to point to original database
Dim fso : Set fso = Createobject("Scripting.FileSystemObject") 'general purpose FileSystemObject
Set fileOriginalMSI = fso.GetFile(databasePath) 'The name of the original MSI
Dim TempMSI : TempMSI = fileOriginalMSI.ParentFolder & "\" & fso.GetTempName ' get a path for a safe temp file
Dim basename : basename = Left(fileOriginalMSI.Name, InStrRev(fileOriginalMSI.Name, ".") -1) ' e.g. file.msi -> file
Dim cabFile : cabFile = basename & ".CAB"
fileOriginalMSI.Copy(TempMSI) 'Make a backup of the MSI to work on
On Error Resume Next
' Connect to Windows Installer object
Dim installer
Set installer = Wscript.CreateObject("WindowsInstaller.Installer") : CheckError
Dim database, view, record, updateMode, sumInfo, sequence, lastSequence
' Open database
Set database = installer.OpenDatabase(TempMSI, msiOpenDatabaseModeTransact) : CheckError
' set the file attribute to compressed in File Table
set view = database.OpenView("SELECT Attributes FROM File") : CheckError
View.Execute : CheckError
dim attrib
Do
Set record = view.Fetch
If record Is Nothing Then Exit Do
attrib = Record.IntegerData(1)
If (attrib And msidbFileAttributesNoncompressed) <> 0 Then
'Record.IntegerData(1) = attrib - msidbFileAttributesNoncompressed + msidbFileAttributesCompressed
attrib = attrib - msidbFileAttributesNoncompressed + msidbFileAttributesCompressed
Record.IntegerData(1) = attrib
'wscript.echo "Check for Non Compressed - Attrib = "&attrib&" Record = "&Record.IntegerData(1)
view.Modify msiViewModifyUpdate, Record
end if
if (attrib And msidbFileAttributesCompressed) = 0 Then
'Record.IntegerData(1) = attrib + msidbFileAttributesCompressed
attrib = attrib + msidbFileAttributesCompressed
Record.IntegerData(1) = attrib
'wscript.echo "Check for Compressed - Attrib = "&attrib&" Record = "&Record.IntegerData(1)
view.Modify msiViewModifyUpdate, Record
End If
loop
database.Commit : CheckError
'resequence the File Table if necessary
set view = database.OpenView("SELECT Sequence FROM File ORDER BY Sequence") : CheckError
View.Execute : CheckError
Set record = view.Fetch : CheckError
Dim X : X = 1
Do
If X <> Record.IntegerData(1) Then 'File Table needs resequencing
'reset the view
View.Execute : CheckError
Set record = view.Fetch : CheckError
X=1
Do 'reset the sequence numbers
Record.IntegerData(1) = X
view.Modify msiViewModifyUpdate,Record
Set record = view.Fetch : CheckError
X=X+1
Loop While not (record Is Nothing )
database.Commit : CheckError
Exit Do 'Finished resequencing
End If
X=X+1
Set record = view.Fetch : CheckError
loop while not (record Is Nothing )
' Create an install session and execute actions in order to perform directory resolution
installer.UILevel = msiUILevelNone
Dim session : Set session = installer.OpenPackage(database) : If Err <> 0 Then Fail "Database: " & TempMSI & ". Invalid installer package format"
Dim shortNames : shortNames = session.Mode(msiRunModeSourceShortNames) : CheckError
Dim stat : stat = session.DoAction("CostInitialize") : CheckError
If stat <> 1 Then Fail "CostInitialize failed, returned " & stat
' Join File table to Component table in order to find directories
Set view = database.OpenView("SELECT File,FileName,Directory_,Sequence,File.Attributes FROM File,"&_
"Component WHERE Component_=Component ORDER BY File.Sequence" ) : CheckError
view.Execute : CheckError
' Create DDF file and write header properties
Dim compressType : compressType = "MSZIP"
Dim cabSize : cabSize = "CDROM"
Dim FileSys : Set FileSys = CreateObject("Scripting.FileSystemObject") : CheckError
Dim outStream : Set outStream = FileSys.CreateTextFile(baseName & ".DDF", OverwriteIfExist, OpenAsASCII) : CheckError
outStream.WriteLine "; Generated from " & TempMSI & " on " & Now
outStream.WriteLine ".Set CabinetNameTemplate=" & baseName & "*.CAB"
outStream.WriteLine ".Set CabinetName1=" & cabFile
outStream.WriteLine ".Set ReservePerCabinetSize=8"
outStream.WriteLine ".Set MaxDiskSize=" & cabSize
outStream.WriteLine ".Set CompressionType=" & compressType
outStream.WriteLine ".Set InfFileLineFormat=(*disk#*) *file#*: *file* = *Size*"
outStream.WriteLine ".Set InfFileName=" & baseName & ".INF"
outStream.WriteLine ".Set RptFileName=" & baseName & ".RPT"
outStream.WriteLine ".Set InfHeader="
outStream.WriteLine ".Set InfFooter="
outStream.WriteLine ".Set DiskDirectoryTemplate=."
outStream.WriteLine ".Set Compress=ON"
outStream.WriteLine ".Set Cabinet=ON"
' Fetch each file and request the source path, then verify the source path
Dim fileKey, fileName, folder, sourcePath, delim, message, attributes
Do
Set record = view.Fetch : CheckError
If record Is Nothing Then Exit Do
fileKey = record.StringData(1)
fileName = record.StringData(2)
folder = record.StringData(3)
sequence = record.IntegerData(4)
attributes = record.IntegerData(5)
If sequence <= lastSequence Then
Fail "Duplicate sequence numbers in File table"
sequence = lastSequence + 1
record.IntegerData(4) = sequence
view.Modify msiViewModifyUpdate, record
End If
lastSequence = sequence
delim = InStr(1, fileName, "|", vbTextCompare)
If delim <> 0 Then
If shortNames Then fileName = Left(fileName, delim-1) Else fileName = Right(fileName, Len(fileName) - delim)
End If
sourcePath = session.SourcePath(folder) & fileName
outStream.WriteLine """" & sourcePath & """" & " " & fileKey
If installer.FileAttributes(sourcePath) = -1 Then message = message & vbNewLine & sourcePath
Loop
outStream.Close
Set Session = Nothing
If Not IsEmpty(message) Then Fail "The following files were not available:" & message
' Generate compressed file cabinet
Dim WshShell : Set WshShell = Wscript.CreateObject("Wscript.Shell") : CheckError
Dim cabStat : cabStat = WshShell.Run("MakeCab.exe /f " & baseName & ".DDF", 1, True) : CheckError
If cabStat <> 0 Then Fail "MAKECAB.EXE failed, possibly could not find source files, or invalid DDF format"
' Update Media table
Set view = database.OpenView("SELECT DiskId, LastSequence, Cabinet FROM Media ORDER BY DiskId") : CheckError
view.Execute : CheckError
updateMode = msiViewModifyUpdate
Set record = view.Fetch : CheckError
If record Is Nothing Then ' Media table empty
Set record = Installer.CreateRecord(3)
record.IntegerData(1) = 1
updateMode = msiViewModifyInsert
End If
record.IntegerData(2) = lastSequence
record.StringData(3) = cabFile
view.Modify updateMode, record
' Commit database in case updates performed
database.Commit : CheckError
'make the transform
Dim TransformPath
TransformPath = fileOriginalMSI.ParentFolder & "\" & BaseName & "_cabgen.mst"
Set oOldDatabase = Installer.OpenDatabase(databasePath,msiOpenDatabaseModeTransact)
Database.GenerateTransform oOldDatabase, TransformPath : CheckError
'generate the transform summary info stream
Database.CreateTransformSummaryInfo oOldDatabase, TransformPath, 0, 0 : CheckError
Set Database = Nothing 'done with it
'modify the original msi's summary info stream
Set sumInfo = oOldDatabase.SummaryInformation(3) : CheckError
sumInfo.Property(11) = Now
sumInfo.Property(13) = Now
sumInfo.Property(15) = clng(sumInfo.Property(15) Or 2) 'set the compressed bit
sumInfo.Property(15) = clng(sumInfo.Property(15) And Not 4) 'remove any admin bit
sumInfo.Persist
Set sumInfo = Nothing ' must release stream
oOldDatabase.commit
'done, report it
DIM ReportFile
Set ReportFile = fso.OpenTextFile(fileOriginalMSI.ParentFolder & "\" &baseName & ".RPT", 1)
Wscript.Echo "Made "& cabFile &_
vbNewLine &_
vbNewLine & ReportFile.ReadAll &_
vbNewLine &_
vbNewLine & TransformPath & " Transform created for modified "&_
vbNewLine & "Media and Files Tables" &_
vbNewLine &_
vbNewLine
Set ReportFile = Nothing
'cleanup
DIM File
Set File = fso.GetFile(fileOriginalMSI.ParentFolder & "\" & BaseName & ".ddf")
File.Delete
Set File = fso.GetFile(fileOriginalMSI.ParentFolder & "\" & BaseName & ".inf")
File.Delete
Set File = fso.GetFile(fileOriginalMSI.ParentFolder & "\" & BaseName & ".rpt")
File.Delete
Set File = fso.GetFile(TempMSI) ': CheckError
File.Delete
Wscript.Quit 0
Sub CheckError
Dim message, errRec
If Err = 0 Then Exit Sub
message = Err.Source & " " & Hex(Err) & ": " & Err.Description
If Not installer Is Nothing Then
Set errRec = installer.LastErrorRecord
If Not errRec Is Nothing Then message = message & vbNewLine & errRec.FormatText
End If
Fail message
End Sub
Sub Fail(message)
Wscript.Echo message
Wscript.Quit 2
End Sub
Sub TestValidArguments()
Dim argCount : argCount = Wscript.Arguments.Count
REM Function tests for one argument
REM if
If argCount > 0 Then If InStr(1, Wscript.Arguments(0), "?", vbTextCompare) > 0 Then argCount = 0
If (argCount <> 1) Then
Wscript.Echo "Windows Installer utility to generate compressed file cabinets from MSI database" &_
vbNewLine & " The 1st argument is the path to MSI database, at the source file root" &_
vbNewLine &_
vbNewLine & " Notes:" &_
vbNewLine & " In order to generate a cabinet, MAKECAB.EXE must be on the PATH" &_
vbNewLine &_
vbNewLine & " This Util modifies only the Summary Stream of the original MSI to say that" &_
vbNewLine & " the files are compressed as this is not possible in the transform" &_
vbNewLine &_
vbNewLine & " Does not handle updating of Media table to handle multiple cabinets" &_
vbNewLine & " If your msi has some cabs in it, you should do an Admin install first" &_
vbNewLine &_
vbNewLine & "carlbennett"
Wscript.Quit 1
End If
End Sub
'What needs doing:
Report of differences between original template: C:\Temp\ACME_RT_ADS9_v1.0.ism
and updated template: C:\Temp\RepackagingTemplate_x86.ism
Table = _Validation
Added record ACMEACL | Type.
Added record ACMEACL | Group.
Added record ACMEACL | Permission.
Added record ACMEACL | Object.
Added record ACMEACL | ACL.
Table = AppSearch
Added record INSTALLEDBY | InstalledBy.Sig.
Table = Binary
Added record SetACL.exe.
Added record ACMESetAcl.dll.
Added record ACMEProcessAcl.dll.
Added record ACMERollbackAcl.dll.
Deleted record CATools.dll.
Table = CustomAction
Added record SetInstalledBy.
Added record ACMEProcessAcl.
Added record ACMESetAcl.
Added record ACMERollbackAcl.
Deleted record SetUserProfileNT. (Starts with capital letter, not lower case)
Deleted record SetAllUsersProfile2K. (Starts with capital letter, not lower case)
Deleted record LaunchAppWaitDeferred.
Table = InstallExecuteSequence
Added record setAllUsersProfile2K.
Added record SetAllUsersProfileNT.
Added record SetInstalledBy.
Added record setUserProfileNT.
Table = InstallUISequence
Added record setAllUsersProfile2K.
Added record SetAllUsersProfileNT.
Added record setUserProfileNT.
Table = ISString
Added record ID_STRING7 | 1033.
Added record ID_STRING8 | 1033.
Changed record:
From ID_STRING1 | 1033 | ACME_RT_ADS6_v8.0 | 0 | | 1100694193
To ID_STRING1 | 1033 | Your Name | 0 | | -1163971186
Changed record:
From IDPROP_ARPCOMMENTS | 1033 | This Value is set by the custom action SetARPComments. Any text set here will be ignored. | 0 | | -501675763
To IDPROP_ARPCOMMENTS | 1033 | This database contains the resources and logic to install [enter ProductName value here] | 0 | | -1163944562
Changed record:
From IDPROP_ARPCONTACT | 1033 | ACME GBM Helpdesk | 0 | | 1167778985
To IDPROP_ARPCONTACT | 1033 | ACME Helpdesk | 0 | | -1163950258
Changed record:
From NEW_STRING3 | 1033 | | 0 | | 202810477
To NEW_STRING3 | 1033 | Manufacturer ApplicationName ApplicationVersion | 0 | | -1163979378
Changed record:
From ID_STRING6 | 1033 | ACME CBFM | 0 | | -1273558772
To ID_STRING6 | 1033 | ACME | 0 | | -1163982994
Table = Property
Added record ACMEIsmTemplate.
Deleted record PackageVersion.
Deleted record PackagingLocation.
Changed record:
From ProductName | ACME_RT_ADS7_v8.0 |
To ProductName | RepackagingTemplate_x86 |
Table = Registry
Changed record:
From Registry2 | 2 | SOFTWARE\_ACME\Applications\[ProductName] | InstalledBy | [LogonUser] | SoftwareAudit | 0
To Registry2 | 2 | SOFTWARE\_ACME\Applications\[ProductName] | InstalledBy | [INSTALLEDBY] | SoftwareAudit | 0
Table = RegLocator
Added record InstalledBy.Sig.
Table ACMEACL added.