Home » MSI (Windows Installer) » Useful Adminstrative Scripts » Delete Duplicate Registry

Delete Duplicate Registry

Posted on by

Description:

This script will delete duplicate registry entries in the Registry table of 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 "Removing Duplicate Registry"
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 registryView, registryRecord, duplicateView, duplicateRecord, tempRecord

If oDatabase.TablePersistent("Registry") = 1 And oDatabase.TablePersistent("Component") = 1  Then

	Set registryView = oDatabase.OpenView("SELECT `Registry`,`Key`,`Name`,`Value`,`Component_` FROM `Registry`")
	registryView.Execute
	Set registryRecord = registryView.Fetch
	Do Until registryRecord Is Nothing

		Set duplicateView = oDatabase.OpenView("SELECT `Registry` FROM `Registry` WHERE `Key`=? AND `Name`=? AND `Value`=? AND `Registry` <> ?")

		Set tempRecord = oInstaller.CreateRecord(4)    
		tempRecord.StringData(1) = registryRecord.StringData(2)    
		tempRecord.StringData(2) = registryRecord.StringData(3)
		tempRecord.StringData(3) = registryRecord.StringData(4)  
		tempRecord.StringData(4) = registryRecord.StringData(1) 		
		duplicateView.Execute(tempRecord)
		Set tempRecord = Nothing

		Set duplicateRecord = duplicateView.Fetch
		While not duplicateRecord is Nothing
			if not isMSMData(registryRecord.StringData(1)) and not isMSMData(duplicateRecord.StringData(1)) Then
				WriteLog "DELETE FROM `Registry` WHERE `Registry` = '" & registryRecord.StringData(1) & "'"
				oDatabase.OpenView("DELETE FROM `Registry` WHERE `Registry` = '" & registryRecord.StringData(1) & "'").Execute
			Else
				WriteLog "Omitted Duplicate Registry in Merge Module: " & registryRecord.StringData(1)
			end If
			Set duplicateRecord = duplicateView.Fetch
		Wend

		Set registryRecord = registryView.Fetch
	Loop

End If

objLogFile.Close
Set fso = Nothing
Set objLogFile = Nothing	
Set registryView = Nothing
Set registryRecord = Nothing
Set duplicateView = Nothing
Set duplicateRecord = Nothing

oDatabase.Commit	

Set oDatabase = Nothing
Set oInstaller = Nothing

Sub WriteLog(LogMessage)

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

End Sub

'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

 

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