Description:
This script will delete empty components from a Windows Installer.
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 "Deleting Empty 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 componentsView, componentsRec, tableView, tableRec, dataView, dataRec
Dim emptyComponent : emptyComponent = True
Dim tempComponent : tempComponent = ""
If oDatabase.TablePersistent("Component") = 1 Then
Set componentsView = oDatabase.OpenView("Select `Component` From `Component` ORDER BY `Component`")
componentsView.Execute
Set componentsRec = componentsView.Fetch
Do While Not componentsRec is Nothing
tempComponent = componentsRec.StringData(1)
emptyComponent = True
'list the tables that have 'Component_' (foreign key) columns
Set tableView = oDatabase.OpenView("SELECT `Table` FROM `_Columns` WHERE `Name`= 'Component_' AND `Table` <> 'FeatureComponents'")
tableView.Execute
Set tableRec = tableView.Fetch
Do While Not tableRec is Nothing
Set dataView = oDatabase.OpenView("SELECT `Component_` FROM `" & tableRec.StringData(1) & "` WHERE `Component_`='" & tempComponent & "'")
dataView.Execute
If Not dataView.Fetch is Nothing Then 'this table has a some data belonging to some component
'component contains data
emptyComponent = False
'skip component and move to next
Exit Do
End If
Set tableRec = tableView.Fetch
Loop
If emptyComponent Then
'delete the empty component
oDatabase.OpenView("DELETE FROM `Component` WHERE `Component` = '" & tempComponent & "'").Execute
oDatabase.OpenView("DELETE FROM `FeatureComponents` WHERE `Component_` = '" & tempComponent & "'").Execute
WriteLog "Deleting empty component: " & tempComponent
End If
Set componentsRec = componentsView.Fetch
Loop
Set tableRec = Nothing
Set tableView = Nothing
Set componentsView = Nothing
Set componentsRec = Nothing
Set dataView = 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
Hi,
i have tried using this script to remove empty component, but its not removing them, i am not getting any error it say just processing MSI.
WriteLog “Deleting Empty Components”
WriteLog “Processing: “ & MSIPath.Name
i have updated the script with
Dim Test : Set Test = dataView.Fetch ‘after line 51.
Script is deleting some components with file along with empty components.
Kindly Help.
Many Thanks,
Shashi
Hmmm. I’ve just repositioned ’emptyComponent = True’. Try again – perhaps use WriteLog to debug the code. Let me know how you get on.
Still no luck 🙁
If the MSI isn’t too big you can zip it and mail it to me. If it is big, strip out all the cabs/streams first…. Give me an example of a component that it is not removing.
My Test MSI has some empty components i tried using the write log, the script is not going in to the below condition.
If emptyComponent Then
WriteLog ” component name: ” & tempComponent
WriteLog “Deleting empty component: ” & tempComponent
End If
its just a simple MSI i have created with some random .dll, .exe and empty component
If i add the below after line 51 in the script,
Dim Test : Set Test = dataView.Fetch
Script enters the loop :
If emptyComponent Then
WriteLog ” component name: ” & tempComponent
WriteLog “Deleting empty component: ” & tempComponent
End If
Log Output:
9/27/2016 4:39:49 PM: Deleting Empty Components
9/27/2016 4:39:49 PM: Processing: Test.msi
9/27/2016 4:39:49 PM: component name: NewComponent2
9/27/2016 4:39:49 PM: Deleting empty component: NewComponent2
9/27/2016 4:39:49 PM: component name: NewComponent1
9/27/2016 4:39:49 PM: Deleting empty component: NewComponent1
9/27/2016 4:39:49 PM: component name: LendingBBLOracleConnect_old.dll
9/27/2016 4:39:49 PM: Deleting empty component: LendingBBLOracleConnect_old.dll
9/27/2016 4:39:49 PM: component name: OraOps10.dll
9/27/2016 4:39:49 PM: Deleting empty component: OraOps10.dll
9/27/2016 4:39:49 PM: component name: gacutil.exe
9/27/2016 4:39:49 PM: Deleting empty component: gacutil.exe
9/27/2016 4:39:49 PM: component name: LendingBBLOracleConnect_SELEX.dll
9/27/2016 4:39:49 PM: Deleting empty component: LendingBBLOracleConnect_SELEX.dl
Sorry, I can’t debug without seeing the MSI Tables. All I can suggest is that you use WriteLog to debug the SQL queries and the Loops/If statements…
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
You might want to use this script instead: https://www.alkanesolutions.co.uk/2013/01/04/split-ini-files-into-separate-components/ Thanks.
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
but it’s not working for my logic
Empty component having entry in create table, then that empty component will not be able to delete form the script, could please help