Description:

This script will split PE files into separate components, as per Windows Installer Best Practices.

Usage

CScript.exe {Script} {MSI}

Script

'set up log file
Dim fso : Set fso = CreateObject("Scripting.FileSystemObject")
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8

'create a name/path for log file
Dim MSIPath : Set MSIPath = fso.GetFile(WScript.Arguments(0))  
Dim logFile : logFile = Left(MSIPath.Path, InStrRev(MSIPath.Path, ".") - 1) & ".log"

Dim objLogFile : Set objLogFile = fso.OpenTextFile(logFile, ForAppending, True)

WriteLog "Splitting PE Files into Separate Components"
WriteLog "Processing: " & MSIPath.Name

'create 2 constants - one for when we want to just query the MSI (read) and one for when we want to make changes (write)

Const msiOpenDatabaseModeReadOnly = 0
Const msiOpenDatabaseModeTransact = 1
Const msiViewModifyReplace = 4

'create WindowsInstaller.Installer object
Dim oInstaller : Set oInstaller = CreateObject("WindowsInstaller.Installer")

'open the MSI (the first argument supplied to the vbscript)
Dim oDatabase : Set oDatabase = oInstaller.OpenDatabase(WScript.Arguments(0),msiOpenDatabaseModeTransact) 
Dim tempComponent : tempComponent = ""
Dim tempFilename : tempFilename = ""
Dim tempFileKey : tempFileKey = ""	
Dim	tempDirectory : tempDirectory = ""
Dim	tempAttributes : tempAttributes = ""
Dim	tempCondition : tempCondition = ""
Dim	tempFeature : tempFeature = ""
Dim tempKeypath : tempKeypath = ""
Dim tempExtensionArray

Dim TableView, TableRec, fileView, fileRec, tempExtension, id, compExistView, compExistRec

If oDatabase.TablePersistent("Component") = 1 AND oDatabase.TablePersistent("File") = 1 Then 

	'select component
	Set Tableview = oDatabase.OpenView("SELECT `Component`.`Component`,`Component`.`Directory_`,`Component`.`Attributes`,`Component`.`Condition`,`Component`.`KeyPath`,`FeatureComponents`.`Feature_` FROM `Component`,`FeatureComponents` WHERE `Component`.`Component` = `FeatureComponents`.`Component_`")
	Tableview.Execute
	Set TableRec = Tableview.Fetch

	'component table has records

	Do Until TableRec Is Nothing

		tempComponent = TableRec.StringData(1)
		tempDirectory = TableRec.StringData(2)
		tempAttributes = TableRec.StringData(3)
		tempCondition = TableRec.StringData(4)
		tempKeypath = TableRec.StringData(5)
		tempFeature = TableRec.StringData(6)

		If Not isMSMData(tempComponent) Then

			'select every file in this component except the keypath
			Set fileView = oDatabase.OpenView("SELECT `File`,`FileName`,`Version` FROM `File` WHERE `Component_`='" & tempComponent & "' and `File` <> '" & tempKeypath & "'")
			fileView.Execute
			Set fileRec = fileView.Fetch
			Do Until fileRec Is Nothing

				tempFileKey = fileRec.StringData(1)
				tempFilename = fileRec.StringData(2)

				If InStr(tempFilename,"|") Then
					'attempt to get actual filename if there is a sfn equivalent
					tempFilename = Split(tempFilename,"|")(1)
				End If

				If InStr(tempFilename,".") > 0 Then
					tempExtensionArray = Split(LCase(tempFilename),".")
					tempExtension = "." & tempExtensionArray(UBound(tempExtensionArray))
				Else
					tempExtension = ""
				End If			

				'If current file is a PE file, separate it into another component
				If Len(tempExtension) = 4 And InStr(1,".ica,.lnk,.inf,.ini,.dll,.exe,.ocx,.tlb,.chm,.drv,.hlp,.sys,.ttf,.mdb,.mdf,.ldf,.jar,.dbf,.vbs,.rll",tempExtension)>0 Then

   	  	  				id = 0		
						Do While componentExists(tempFilename)	
							id = id + 1			
							tempFilename = tempFilename & id
						Loop
						WScript.Echo "tempext: " & tempExtension
						WriteLog "Moving File: " & tempFileKey & " into new Component: " & tempFilename
						oDatabase.OpenView("INSERT INTO `Component` (`Component`,`ComponentId`,`Directory_`,`Attributes`,`Condition`,`KeyPath`) VALUES ('"& tempFilename &"','"& returnGuid &"','"& tempDirectory &"',"& tempAttributes &",'"& tempCondition &"','"& tempFileKey &"')").Execute
						oDatabase.OpenView("UPDATE `File` SET `Component_` = '" & tempFilename & "' WHERE `File` = '"& tempFileKey &"'").Execute
						oDatabase.OpenView("INSERT INTO `FeatureComponents` (`Feature_`,`Component_`) VALUES ('"& tempFeature &"','"& tempFilename &"')").Execute

				End If

				Set fileRec = fileView.Fetch
			Loop
			Set fileView = Nothing
			Set fileRec = Nothing

		end If
		Set TableRec = Tableview.Fetch
	Loop

	Set TableRec = Nothing
	Set Tableview = Nothing
	Set fileRec = Nothing

End If

oDatabase.Commit	

objLogFile.Close
Set fso = Nothing
Set objLogFile = Nothing	
Set oDatabase = Nothing
Set oInstaller = Nothing

Sub WriteLog(LogMessage)

	WScript.echo Now() & ": " & LogMessage
    objLogFile.Writeline(Now() & ": " & LogMessage)

End Sub

'return a random guid for when we create a new component
Function returnGuid()

	Dim TypeLib : Set TypeLib = CreateObject("Scriptlet.TypeLib")
	Dim tg : tg = TypeLib.Guid
	returnGuid = Left(tg, len(tg)-2)
	Set TypeLib = Nothing

End Function

'returns true if tempData contains MSM decoration
Function isMSMData(tempData)
	isMSMData = False
	Dim Match
	Dim regEx : Set regEx = New RegExp
	regEx.MultiLine = vbTrue
	regEx.global = vbTrue
	regEx.Pattern = "[A-Za-z0-9]{8}_[A-Za-z0-9]{4}_[A-Za-z0-9]{4}_[A-Za-z0-9]{4}_[A-Za-z0-9]{12}"
	For Each Match in regEx.Execute(tempData)
		isMSMData = True
	Next
	Set regEx = Nothing
End Function

'used to see if a component exists or Not
Function componentExists(component)

	'this function is called initially with '1' as the id.  Then this value gets incrememnetd if the component exists
	Set compExistView = oDatabase.OpenView("SELECT `Component` FROM `Component` WHERE `Component`='" & component & "'")
	compExistView.Execute
	Set compExistRec = compExistView.Fetch
	If Not compExistRec is Nothing Then
		Set compExistView = Nothing
		Set compExistRec = Nothing
		componentExists = True			
	Else
		Set compExistView = Nothing
		Set compExistRec = Nothing
		componentExists = False
	End If	

End Function

 

Split PE Files into Separate Components

1 thought on “Split PE Files into Separate Components

  1. hello

    thanks for your script

    it’s work but i have an error ICE03 like this:

    Invalid identifier; Table: File, Column: Component_, Key(s): File Component_

    and other

    can you advice how i an fix it?

     

Comments have now been disabled. If you have a question to ask about this post please ask the community!