/build/static/layout/Breadcrumb_cap_w.png

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:
Posted by: 786_ak 7 years ago
Third Degree Green Belt
0
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
    • I don't disagree with best practices. Did you look into "Install Condition"? - 786_ak 7 years ago
      • Yes. Target platform restrictions there. Nothing else. - Saimon 7 years ago
Posted by: anonymous_9363 7 years ago
Red Belt
0
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
Red Belt
0
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
Red Belt
0

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
Red Belt
0
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.

Don't be a Stranger!

Sign up today to participate, stay informed, earn points and establish a reputation for yourself!

Sign up! or login

View more:

Share

 
This website uses cookies. By continuing to use this site and/or clicking the "Accept" button you are providing consent Quest Software and its affiliates do NOT sell the Personal Data you provide to us either when you register on our websites or when you do business with us. For more information about our Privacy Policy and our data protection efforts, please visit GDPR-HQ