' Project: Extract CABinets
' Customer: Saxion Hogescholen
' Function: VB Script prototype for extracting embedded CABinets from MSI files
ARGS = Wscript.Arguments.Count
Set WIOBJ = CreateObject( "WindowsInstaller.Installer" )
Set IsFileSys = CreateObject("IsFileSys.File")
Const msiStreamAnsi = 2
' Make sure we have a good command line
If ARGS > 0 Then if InStr(1, Wscript.Arguments(0), "?", vbTextcompare) > 0 Then argCount = 0
If ARGS = 0 Then
Wscript.Echo "This script will extract embedded CABinets from" &_
vbLf & "MSI files, since this is a more efficient layout." &_
vbLf & "The argument is the path to an install database"
Wscript.Quit 1
End If
' Open command line delivered MSI and make a changed copy
WorkingDir = Left(Wscript.Arguments(0),InStrRev(Wscript.Arguments(0),"\"))
MSIBase = Wscript.Arguments(0)
MSIChanged = WorkingDir & "Changed.MSI"
Set objFS = CreateObject( "Scripting.FileSystemObject")
Set fsoBaseFile = objFS.GetFile(MSIBase)
fsoBaseFile.Copy (MSIChanged)
Set WIOBJ = CreateObject( "WindowsInstaller.Installer")
Set ODB = WIOBJ.OpenDatabase(MSIBase, 0)
Set MSIDB = WIOBJ.OpenDatabase(MSIChanged, 1)
If( ODB Is Nothing ) Then
MsgBox( "Error opening MSI file: " & MSIBase )
End If
If( MSIDB Is Nothing ) Then
MsgBox( "Error creating MSI file: " & MSIChanged )
End If
' Get a ModuleID from those listed in the Signature table,
' then get associated components and delete all related data
Set Media_View = MSIDB.OpenView( "SELECT Cabinet FROM Media" )
Media_View.Execute
Set Media_Record = Media_View.Fetch
Do Until Media_Record Is Nothing
If (Mid(Media_Record.StringData(1), 1, 1) = "#") Then
' Get "_Streams" table entry name from Media table entry name
OldMediaName = Right(Media_Record.StringData(1),(Len(Media_Record.StringData(1))-1))
' Loop to write the stream out in 1024 byte blocks
' **** USES "IsFileSys" INSTALLSHIELD FILE SYSTEM Object ****
Set streamview = MSIDB.OpenView("SELECT * FROM _Streams WHERE `Name`= '" & OldMediaName & "'")
streamview.Execute
Set streamrecord = streamview.Fetch
If Not (streamrecord Is Nothing) Then
sFullPath = WorkingDir & streamrecord.StringData(1)
IsFileSys.OpenFile (sFullPath)
Dim sData
sData = streamrecord.ReadStream(2, 1024, msiStreamAnsi)
While (sData <> Empty)
IsFileSys.WriteData(sData)
sData = streamrecord.ReadStream(2, 1024, msiStreamAnsi)
Wend
IsFileSys.CloseFile()
' MsgBox( "Written " & streamrecord.DataSize(2) & " bytes to " & sFullPath )
End If
' Rename internal references
NewMediaName = OldMediaName
Set view = MSIDB.OpenView("UPDATE `Media` SET `Cabinet`='" & NewMediaName & "' WHERE `Cabinet`='#" & OldMediaName & "'")
view.Execute
Set view = Nothing
' Delete old stream from database
Set view = MSIDB.OpenView("SELECT `Name` FROM _Streams WHERE `Name` = ?")
Set record = WIOBJ.CreateRecord(2)
record.StringData(1) = OldMediaName
view.Execute record
Set record = view.Fetch
view.Modify 3, record
Set view = Nothing
MsgBox "Deleted the embedded CABinet from MSI file (use Orca to recover size)."
End If
' Continue getting next media table entries, for spanning media such as floppy discs
Set Media_Record = Media_View.Fetch
Loop
' Close out and commit
MSIDB.Commit
Set MSIDB = Nothing
Set WIOBJ = Nothing