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

Split INI Files into Separate Components

Posted on by


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


CScript.exe {Script} {MSI}


'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_`")
	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`")
	        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) & "'")
							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)

								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 & "'")
								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

	            Set TempRec = Nothing
		        Set Tempview = Nothing

		        Set TableRec = Tableview.Fetch

	Set TableRec= Nothing
	Set TableView= Nothing

End If


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 & "'")
	Set compExistRec = compExistView.Fetch
	If Not compExistRec is Nothing Then
		getComponent = False					
		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,




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