Home » MSI (Windows Installer) » Useful Adminstrative Scripts » Split INI Files into Separate Components

Split INI Files into Separate Components

Posted on by

Description:

This script will split INI 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 INI 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

'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 tableView, tableRec, tempView, tempRec, componentView, componentRec, tempComponent, id, compExistView, compExistRec, createFolderView, createFolderRec

Dim tempinifilename : tempinifilename = ""
Dim tempDir : tempDir = ""
Dim tempfilename : tempfilename = ""
Dim blnMovedComponent : blnMovedComponent = False

If oDatabase.TablePersistent("IniFile") = 1 Then

	'select component from the inifile table
	Set Tableview = oDatabase.OpenView("SELECT DISTINCT `IniFile`.`Component_`, `FeatureComponents`.`Feature_` FROM `IniFile`, `Component`, `FeatureComponents` WHERE `IniFile`.`Component_` = `Component`.`Component` AND `Component`.`Component` = `FeatureComponents`.`Component_`")
	Tableview.Execute
	Set TableRec = Tableview.Fetch	
	Do While Not TableRec Is Nothing

			blnMovedComponent = True
			tempfilename = ""

			'select all the ini files in this component
            Set Tempview = oDatabase.OpenView("SELECT `FileName` FROM `IniFile` WHERE `Component_`='" & TableRec.StringData(1) & "' ORDER BY `FileName`")
	        Tempview.Execute
	        Set TempRec = Tempview.Fetch
             	'component has more than one ini file
                Do While Not TempRec Is Nothing
         				'if we're in same component but different file
           	        	If (TempRec.StringData(1) <> tempfilename) And Not blnMovedComponent Then

           	        		Set componentView = oDatabase.OpenView("SELECT * FROM `Component` WHERE `Component`='" & TableRec.StringData(1) & "'")
							componentView.Execute
							Set componentRec = componentView.Fetch
							If Not componentRec Is Nothing Then

								'we want to name to component the same name as the ini file
								tempComponent = tempfilename 

								'we get the fir from the Component table (as opposed to the DirProperty column in the inifile table) - more reliable
								tempDir = componentRec.StringData(3)

								'if its in sfn form, take the long file name for our component
								If InStr(tempComponent,"|") > 0 Then
									tempComponent = Split(tempComponent,"|")(1)
								End If

								'comp name cannot start with a number
								If IsNumeric(Left(tempComponent,1)) Then
									tempComponent = "_" & tempComponent
								End If 

								'comp cannot contain dashes
								tempComponent = Replace(tempComponent,"-","_")

								id = 0
								'ensure component name is unique
								Do While Not getComponent(tempComponent)
									If (id > 0) Then
										tempComponent = Left(tempComponent,Len(tempComponent)-Len(CStr(id))) 
									End If
									id = id + 1		
									tempComponent = CStr(tempComponent & id)
								Loop									

								oDatabase.OpenView("INSERT INTO `Component` (`Component`,`ComponentId`,`Directory_`,`Attributes`,`Condition`) VALUES ('"& tempComponent &"','"& returnGuid &"','"& tempDir &"',"& componentRec.StringData(4) &",'"& componentRec.StringData(5) &"')").Execute

								oDatabase.OpenView("INSERT INTO `FeatureComponents` (`Feature_`,`Component_`) VALUES ('"& TableRec.StringData(2) &"','"& tempComponent &"')").Execute

								'ensure there's an entry in the CreateFolders table
								Set createfolderView = oDatabase.OpenView("SELECT `Directory_` FROM `CreateFolder` WHERE `Directory_` = '" & tempDir & "' AND `Component_` = '" & tempComponent & "'")
								createfolderView.Execute
								Set createfolderRec = createfolderView.Fetch
								If createfolderRec Is Nothing Then								
									oDatabase.OpenView("INSERT INTO `CreateFolder` (`Directory_`,`Component_`) VALUES ('"& tempDir &"','"& tempComponent &"')").Execute
									WScript.Echo "INSERT INTO `CreateFolder` (`Directory_`,`Component_`) VALUES ('"& tempDir &"','"& tempComponent &"')"
								End If

								Set createfolderRec= Nothing
								Set createfolderView= Nothing

								'Finally update the inifile table to point to the new component
								oDatabase.OpenView("UPDATE `IniFile` SET `Component_` = '" & tempComponent & "' WHERE `FileName` = '"& tempfilename &"'").Execute

								WriteLog "Separated INI File: " & tempfilename & " into its own component called: " & tempComponent
		    				End If
						End If
						Set componentView = Nothing
						Set componentRec = Nothing

		         	tempfilename = TempRec.StringData(1)
	            	blnMovedComponent = False

    		        Set TempRec = Tempview.Fetch
                Loop

	            Set TempRec = Nothing
		        Set Tempview = Nothing

		        Set TableRec = Tableview.Fetch
		     Loop

	Set TableRec= Nothing
	Set TableView= 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

'gets random guid	
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

'used to see if a component exists or not
Function getComponent(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
		getComponent = False					
	Else
		getComponent = True	
	End If

	Set compExistView = Nothing
	Set compExistRec = Nothing
End Function

 

2 thoughts on “Split INI Files into Separate Components

  1. I have one query component having ini table entry I want move to different component   and then want delete that component ,

    For example ;

    A&B having two components

    A component having exe file

    B component having ini table entry

    Just I want to move ini file to A component

    Then I want delete B component

    Can you please add this point to delete component script

    I have tested this script but it’s not working as per above example

    I am getting below error message

    There is no script engine for file extension “.msi”

    Can you please help me out

     

  2. hello Travis,

    when i am ruining with script i am getting below error message ,Please help me out

    Input Error: There is no script engine for file extension “.msi”.

    Thanks & Regards,

    Mahesh

     

     

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