Kae Travis

Split INI Files into Separate Components


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


Split INI Files into Separate Components
Split INI Files into Separate Components

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,




Leave a Reply