Finding 64-bit components in an MSI database

This blog entry provides an example of finding 64-bit components in an MSI database using VBScript.  It follows on from the previous blog post which provided a tutorial on editing MSI files in the windows installer cache using VBScript.

It forms part 17 of an 17-part series that explores how to use VBScript to manipulate MSI relational databases using the Windows Installer API.  Throughout this series of tutorials, we identify the common issues that we encounter and the best practises that we use to overcome them.

A couple of weeks ago, I needed to scan an MSI for 64-bit components. I knew each component had an ‘attribute’ value (which is actually a bit flag), but I needed to figure out a way to extract each bit flag so that I could find out how the component was configured and which attributes were set.

Here’s how I did it….

Firstly, let’s list down the component attributes and their corresponding bit flags:

Bit Flag DescriptionDecimal Value
Component cannot be run from source0
Component can only be run from source1
Component can run locally or from source2
Has a Registry Keypath4
Increments Shared DLL Registry Count8
Permanent Component (doesn’t remove on uninstall)16
Has an ODBC Data Source Keypath32
Re-evaluates Condition on Reinstall64
Do Not Overwrite if Component Exists128
64-Bit Component256
Disable Registry Reflection512
Prevent Leaving Orphan Components1024
Share Component2048

When we want to set multiple bit flags on a component, we add the decimal values together. For example, let’s say we have a component which contains a 64-bit DLL as the keypath, and we want to incrememnt the shared DLL reference count. The attribute of our component would be:

(Increments Shared DLL Registry Count + 64-Bit Component)
= 8 + 256
= 264

Now let’s reverse things. If we have a value of 264 in our attribute column, how do we work out which decimal values were added together to make this up?
The answer is that we need to convert the decimal value to a binary value. Here goes a quick binary lesson:

A 16-bit binary value would consist of 16 1’s and 0’s. For example, 0010101000101101. Each ‘bit’ flag has a corresponding decimal value. In the table below, we’ll use our 16-bit shared DLL component as an illustrated example:

component_attributes

The MSI component attribute only uses the first 13 bits. The last 3 bits will always be zero. By converting the decimal value of 264 in to binary, we can see which bit flags are set and therefore decipher the attribute which has been applied to the component.

Now let’s see it in code….

'Function to convert decimal to 16-bit binary
Function DecToBin(intDec)
  dim strResult
  dim intValue
  dim intExp
  strResult = ""

  intValue = intDEC
  intExp = 32768
  while intExp >= 1
    if intValue >= intExp then
      intValue = intValue - intExp
      strResult = strResult & "1"
    Else
      strResult = strResult & "0"
    end if
    intExp = intExp / 2
  Wend

  DecToBin = strResult
End Function

Dim componentBinary : componentBinary = 0
Dim componentName : componentName = ""

Dim isComponent64Bit : isComponent64Bit = 0
Dim isComponentSharedDLL : isComponentSharedDLL = 0

'Select the name and attribute for each component 
Set View = Database.OpenView("SELECT Component, Attributes FROM `Component`")
View.Execute
Set rec = View.Fetch

Do While Not rec Is Nothing	

	'get component name
	componentName = rec.StringData(1)

	'get the attribute (decimal value) and convert it to 16-bit binary
	componentBinary = DecToBin(Cint(rec.StringData(2)))

	'get bit flag for shared dll (4th bit) - remember vbscript arrays start at 0!
	isComponentSharedDLL = Mid(componentBinary,3,1)

	'get bit flag for 64-bit (9th bit) - remember vbscript arrays start at 0!
	isComponent64Bit = Mid(componentBinary,8,1)

	If isComponentSharedDLL = "1" Then
		MsgBox "Component '" & componentName & "' is a shared DLL resource!"
	End If

	If isComponent64Bit = "1" Then
		MsgBox "Component '" & componentName & "' is a 64-bit component!"
	End If

  	Set rec = View.Fetch
Loop
View.Close
Set View = Nothing
Set rec = Nothing

Thanks for reading how about finding 64-bit components in an MSI database using VBScript.

Editing MSI files in the Windows Installer cache

This blog entry provides an example of editing MSI files in the windows installer cache using VBScript.  It follows on from the previous blog post which provided a tutorial on writing to the windows installer log file from a custom action using VBScript.

It forms part 16 of an 17-part series that explores how to use VBScript to manipulate MSI relational databases using the Windows Installer API.  Throughout this series of tutorials, we identify the common issues that we encounter and the best practises that we use to overcome them.

In this example, let’s say a user has an MSI installed and they want to remove it. Every time they try to remove it, a Custom Action called ‘AlkaneCustomAction’ keeps throwing an error, and as a result the uninstall fails.

This piece of code searches all products installed or advertised for the current user and machine. When we find the product code, we open the database in trasact mode, set the condition of the Custom Action to ‘1=0’ (I.e, NEVER run it) and commit the change. The MSI will now remove without error.

Obviously this is just an example. Simply not running the Custom Action may not be the optimal solution!

Const msiOpenDatabaseModeTransact = 1  

'Enter ProductCode of the MSI we want to amend
Const ProdCodeToFind = "{00000000-0000-0000-0000-000000000000}"

Dim productCodeFound : productCodeFound = False
Dim currentProductCode, oTempDatabase

'Loop through every product, and see if the product code matches the one we're looking for
Dim oInstaller : Set oInstaller = CreateObject("WindowsInstaller.Installer")  
For Each currentProductCode In oInstaller.Products  
 	If currentProductCode = ProdCodeToFind Then  
    		oTempDatabase = oInstaller.productInfo(currentProductCode, "LocalPackage")  
		productCodeFound = True
 	End If  
Next  

If productCodeFound Then  
	Set database = oInstaller.OpenDatabase(oTempDatabase, msiOpenDatabaseModeTransact)  
	Set view = database.OpenView("UPDATE `InstallExecuteSequence` SET `Condition`='1=0' WHERE `Action`='AlkaneCustomAction'")  
	view.Execute  
	database.Commit
	view.Close
        set view = Nothing
	set database = Nothing
End If

Set oTempDatabase = Nothing
Set oInstaller = Nothing

Thanks for reading about editing MSI files in the Windows Installer cache using VBScript.  Next you can find out how to find 64-bit components in an MSI database using VBScript.

Writing to the Windows Installer log file from a Custom Action

This blog entry provides an example of writing to the windows installer log file from a custom action using VBScript.  It follows on from the previous blog post which provided a tutorial on using SQL inside an MSI database custom action using VBScript.

It forms part 15 of an 17-part series that explores how to use VBScript to manipulate MSI relational databases using the Windows Installer API.  Throughout this series of tutorials, we identify the common issues that we encounter and the best practises that we use to overcome them.

Logging is extremely useful when debugging MSIs. Most people that write Custom Actions don’t write logs, but if you’re writing quite extensive logic you may wish to consider it. Simply paste the following logic into your CA:

'Subroutine to write to log file 
Const msiMessageTypeInfo = &H04000000
Sub writeToLog(ByVal msg)
	Set record = Installer.CreateRecord(1)
	record.stringdata(0) = "AlkaneLog: [1]"
	'This value gets subbed in to the [1] placeholder above
	record.stringdata(1) = msg
	record.formattext
	message msiMessageTypeInfo, record
	Set record = Nothing
End Sub

and write to the log like this:

writeToLog("This is a log message")

Thanks for reading about writing to the Windows Installer log file from a Custom Action using VBScript.  Next you can find out how to edit MSI files in the windows installer cache using VBScript.

Using SQL inside an MSI database custom action

This blog entry provides an example of using SQL inside an MSI database custom action with VBScript.  It follows on from the previous blog post which provided a tutorial on generating transforms for an MSI database using VBScript.

It forms part 14 of an 17-part series that explores how to use VBScript to manipulate MSI relational databases using the Windows Installer API.  Throughout this series of tutorials, we identify the common issues that we encounter and the best practises that we use to overcome them.

As well as creating administrative scripts like the previous examples, we can also use SQL queries during the installation of an MSI. When an MSI is installing, we
can refer to this as a ‘session’. Take the following excerpt – this is from a tutorial I wrote regarding using VBScript Custom Actions to automate the installation and removal of Excel add-ins:

...
...
Dim sql : sql = "SELECT File.FileName,File.Component_,Component.Directory_ FROM File, Component WHERE File.Component_ = Component.Component"

'start searching through file table for add-ins (.XLA or .XLL files)
Set fileView= Session.Database.OpenView(sql)
fileView.Execute
Set fileRecord = fileView.Fetch
While Not fileRecord Is Nothing

    componentState = Session.ComponentRequestState(fileRecord.StringData(2))

    'if component is being installed locally
    If componentState = 3 Then

	'get filename
        tempFileName = LCase(fileRecord.StringData(1))

        If InStr(tempFileName,"|") Then
            'if filename is currently in sfn form, try and retrieve the full file name
            tempFileName = Split(tempFileName,"|")(1)
        End If 

        'retrieve 3-length extension (that's all
        tempExtension = Right(tempFileName,Len(tempFileName)-InStrRev(tempFileName ,"."))

        If (tempExtension = "xla" OR tempExtension = "xll") Then       
                'return full path to Excel add-in file.
                filePath = Session.TargetPath(fileRecord.StringData(3)) & tempFileName          
                'install/add add-in using automation....(logic not included in this example)
        End If 

    End If 
    Set fileRecord = fileView.Fetch
Wend

fileView.Close
Set fileView = Nothing
Set fileRecord = Nothing
...
...

You can see that we don’t explicitly create an Installer object now, because we’re already in the session of one! Instead, we use this syntax:

Session.Database.OpenView(sql)

another handy tip in here is the use of:

Session.ComponentRequestState(fileRecord.StringData(2))

to detect if our session is installing/uninstalling or repairing. In this example, I’m detecting if we’re installing and if so I search for all Excel add-ins, finding their install locations by using:

Session.TargetPath

Thanks for reading about using SQL inside an MSI database custom action with VBScript.  Next you can find out how to write to the windows installer log file from a custom action using VBScript.

Generating MST transforms for an MSI database

This blog entry provides an example of generating MST transforms for an MSI database using VBScript.  It follows on from the previous blog post which provided a tutorial on applying transforms to an MSI database using VBScript.

It forms part 13 of an 17-part series that explores how to use VBScript to manipulate MSI relational databases using the Windows Installer API.  Throughout this series of tutorials, we identify the common issues that we encounter and the best practises that we use to overcome them.

Now we’re going to attempt to generate a transform from changes which we make to an MSI. An example of this could be adding certain properties for a customer, or possible an audit key in the registry table.

When we’re generating an MST from a script, here’s the idea:

  • We take a copy of the original base MSI, and create a new temporary MSI
  • We apply any changes we make to this temporary MSI
  • We find the difference between the temporary MSI and the base (original) MSI
  • We generates a transform from the differences between the base MSI and the temporary MSI.

So, here goes. We’re going to insert the following entry into the Registry table:

generate_xfm

'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 a file system object, so that we can copy the original MSI
Dim fso : Set fso = CreateObject("Scripting.FileSystemObject")

'get a reference to the original msi
Dim originalMSI : Set originalMSI = fso.GetFile(WScript.arguments(0))

'create a full path to our 'proposed' generated transform
Dim transformWithChanges: transformWithChanges = Left(originalMSI.Path, InStrRev(originalMSI.Path, ".") - 1) & "_Changes.MST"

'get random filename or a temporary MSI
temporaryMSI = originalMSI.ParentFolder & "\" & fso.GetTempName

'make a copy of the original MSI, and name it with our temporary name above
originalMSI.Copy (temporaryMSI)   'Make a backup of the MSI to work on

'set the attribute of the temp file - default to 'Normal'
fso.GetFile(temporaryMSI).Attributes = 0

'we can now use our temp file above as a base comparison

Set oInstaller = CreateObject("WindowsInstaller.Installer")

'open the temporary MSI in transact mode
Set oTempDatabase = oInstaller.OpenDatabase(temporaryMSI, msiOpenDatabaseModeTransact)

'insert our new value
Dim sql : sql = "INSERT INTO `Registry` (`Registry`,`Root`,`Key`,`Name`,`Value`,`Component_`) VALUES ('SampleTransformReg',2,'Software\AlkaneTest','testTransformName','testTransformValue','alkaneComponent')"

Dim regView : Set regView = oTempDatabase.OpenView(sql)

'execute the query
regView.Execute

'Now get a reference to the original, un-changed MSI.  Open it in Read-only mode
Set oOriginalDatabase = oInstaller.OpenDatabase(originalMSI.Path, msiOpenDatabaseModeReadOnly)

'get the differences between our original database (oOriginalDatabase) and our temp database (oTempDatabase), and generate transform to our new transform filename (transformWithChanges)
oTempDatabase.GenerateTransform oOriginalDatabase, transformWithChanges

'create transform summary information stream.  This was a bug which I found was missing from the SDK scripts
oTempDatabase.CreateTransformSummaryInfo oOriginalDatabase, transformWithChanges, 0, 0

regView.Close
Set regView = Nothing
Set oTempDatabase = Nothing
Set oOriginalDatabase = Nothing
Set oInstaller = Nothing

'delete our temporary database
Set File = fso.GetFile(temporaryMSI)
File.Delete

Wscript.Echo transformWithChanges & " Created!"

The comments throughout the example above explain what each section does. What I would say, though, is:

  • Always remember to call the CreateTransformSummaryInfo method! The Windows Installer SDK examples don’t include this. Omitting this may mean your transform wont generate/apply without error.
  • Ensure you close every view object, otherwise the temporary file will not delete at the end.
  • If no changes are made to the base MSI and you attempt to generate a transform, there will be an error because the difference between the base MSI and the new one will be nothing.

Thanks for reading about generating MST transforms for an MSI database.  Next you can find out how to use SQL from with a custom action using VBScript.

Applying MST transforms to an MSI database

This blog entry provides an example of applying MST transforms to an MSI database using VBScript.  It follows on from the previous blog post which provided a tutorial on using inner joins when reading from an MSI database using VBScript.

It forms part 12 of an 17-part series that explores how to use VBScript to manipulate MSI relational databases using the Windows Installer API.  Throughout this series of tutorials, we identify the common issues that we encounter and the best practises that we use to overcome them.

For this example I’ve created a sample MST file. Our test MSI has an entry in the Registry table with a primary key of ‘SampleReg’ and a Value of ‘This is an MSI’. To create the transform I used Orca. I opened our test MSI, selected the ‘Transform’ menu option, and scrolled down and clicked ‘New Transform’. I then changed the Value of our ‘SampleReg’ row to be ‘This is an MST’. To create the new transform file, I then selected the ‘Transform’ menu option, and scrolled down and clicked ‘Generate Transform’. By changing this value via a transform, it should enable us to see if the transform has applied.

To start with, copy and paste the following code into your script file:

'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

' Adds a row that already exists.
Const msiTransformErrorAddExistingRow = 1 
' Deletes a row that does not exist.
Const msiTransformErrorDeleteNonExistingRow = 2 
' Adds a table that already exists.
Const msiTransformErrorAddExistingTable = 4 
' Deletes a table that does not exist.
Const msiTransformErrorDeleteNonExistingTable = 8 
' Updates a row that does not exist.
Const msiTransformErrorUpdateNonExistingRow = 16 
' Transform and database code pages do not match and neither has a neutral code page.
Const msiTransformErrorChangeCodePage = 32 
' Creates the temporary _TransformView table.
Const msiTransformErrorViewTransform = 256 

Dim errorCondition : errorCondition = msiTransformErrorChangeCodePage + msiTransformErrorUpdateNonExistingRow + msiTransformErrorDeleteNonExistingTable _
+ msiTransformErrorAddExistingTable + msiTransformErrorDeleteNonExistingRow + msiTransformErrorAddExistingRow

'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),msiOpenDatabaseModeReadOnly) 

Dim sql : sql = "SELECT `Value` FROM `Registry` WHERE `Registry` = 'SampleReg'"

'create a view of the registry we want to see
Dim regView : Set regView = oDatabase.OpenView(sql)

'execute the query
regView.Execute 

'fetch the first row of data (if there is one!)
Dim regRecord : Set regRecord = regView.Fetch

'whilst we've returned a row and therefore regRecord is not Nothing
While Not regRecord Is Nothing

	'print out the registry key
	wscript.echo "Value from MSI is: " & regRecord.StringData(1)

	'go and fetch the next row of data	
	Set regRecord = regView.Fetch
Wend
Set regRecord = Nothing

wscript.echo "(...applying MST)"

'apply every transform in the argument list
For i = 1 To Wscript.Arguments.Count - 1
	oDatabase.ApplyTransform Wscript.Arguments(i), errorCondition
	oDatabase.Commit
Next

sql = "SELECT `Value` FROM `Registry` WHERE `Registry` = 'SampleReg'"

'create a view of the registry we want to see
Set regView = oDatabase.OpenView(sql)

'execute the query
regView.Execute 

'fetch the first row of data (if there is one!)
Set regRecord = regView.Fetch

'whilst we've returned a row and therefore regRecord is not Nothing
While Not regRecord Is Nothing

	'print out the registry key
	wscript.echo "Value from MST is: " & regRecord.StringData(1)

	'go and fetch the next row of data	
	Set regRecord = regView.Fetch
Wend

regView.Close
Set regView = Nothing
Set regRecord = Nothing
Set oDatabase = Nothing
Set oInstaller = Nothing

To run it, we need to specify both our MSI file and our MST file:

Open up a Command Prompt
Type: cscript.exe alkaneTestScript.vbs “c:\alkaneMSIs\testMSI.msi” “c:\alkaneMSIs\testMST.mst”

You should see the following result:
Applying MST transforms to an MSI database 1

The only new part to this script is that we use the ApplyTransform method to apply one (or many!) transforms to our MSI:

'apply every transform in the argument list
For i = 1 To Wscript.Arguments.Count - 1
	oDatabase.ApplyTransform Wscript.Arguments(i), 63
	oDatabase.Commit
Next

In the excerpt of code above, we loop through the arguments we’ve passed in to the VBCsript (exclusing the first argument – the MSI), we apply the transform to the database and we commit the changes.

Thanks for reading about applying MST transforms to an MSI database using VBScript.  Next you can find out how to generate transforms for an MSI database using VBScript.

Using inner joins to read from an MSI database

This blog entry provides an example of using inner joins to read from an MSI database using VBScript.  It follows on from the previous blog post which provided a tutorial on handling tables that don’t exist in an MSI database using VBScript.

It forms part 11 of an 17-part series that explores how to use VBScript to manipulate MSI relational databases using the Windows Installer API.  Throughout this series of tutorials, we identify the common issues that we encounter and the best practises that we use to overcome them.

Let’s say we want to know what directory a file gets installed too. In order to do that, we’d need to read the FileName column from the File table, and the Directory_
column from the Component table.

tipTip: All foreign key column names end with an underscore (_).

 

We can see that the File table includes a foreign key into the Component table (Component_). For this reason, we’ll join the two tables where:

File.Component_ equals Component.Component

'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),msiOpenDatabaseModeReadOnly) 

Dim sql : sql = "SELECT `File`.`FileName`, `Component`.`Directory_` FROM `File`, `Component` WHERE `File`.`Component_` = `Component`.`Component`"

'create a view of the registry we want to see
Dim fileView : Set fileView = oDatabase.OpenView(sql)

'execute the query
fileView.Execute 

'fetch the first row of data (if there is one!)
Dim fileRecord : Set fileRecord = fileView.Fetch

'whilst we've returned a row and therefore fileRecord is not Nothing
While Not fileRecord Is Nothing

	'print out the registry key
	wscript.echo "The file '" & fileRecord.StringData(1) & "' gets installed to the directory '" & fileRecord.StringData(2) & "'"  

	'go and fetch the next row of data	
	Set fileRecord = fileView.Fetch
Wend

fileView.Close
Set fileView = Nothing
Set fileRecord = Nothing
Set oDatabase = Nothing
Set oInstaller = Nothing

Thanks for reading about using inner joins when reading from an MSI database.  Next you can find out how to apply MST transforms to an MSI database using VBScript.

Inserting a registry value in an MSI database (Modify method)

This blog entry provides an example of inserting a registry value in an MSI database using the Modify method and VBScript.  It follows on from the previous blog post which provided a tutorial on deleting a registry value from an MSI database using the Modify method and VBScript.

It forms part 9 of an 17-part series that explores how to use VBScript to manipulate MSI relational databases using the Windows Installer API.  Throughout this series of tutorials, we identify the common issues that we encounter and the best practises that we use to overcome them.

In this example, we change the SQL statement to include the columns of data which we want to insert. Note that we MUST include all of the non-nullable columns as a minimum. When a column is not nullable, it means we MUST specify a value when we insert the record. Otherwise the insertion will fail. To find the non-nullable columns, consult the Windows Installer help file (MSI.chm) or MSDN. For example:

Inserting a registry value in an MSI database (Modify method) 2

The four non-nullable columns which we MUST include when inserting into the Registry table are:

Registry
Root
Key
Component_

Dim sql : sql = "SELECT `Registry`,`Root`,`Key`,`Component_` FROM `Registry` WHERE `Registry` = 'MyNewSampleReg'"

If we were lazy, we could just return all rows using the following:

Dim sql : sql = "SELECT * FROM `Registry` WHERE `Registry` = 'MyNewSampleReg'"

This time when we execute the query, we’re not going to loop through any records using the While…Wend loop. All we want to do is see if the record already exists:

If regRecord Is Nothing Then

and if it doesn’t, we’ll start to create a new record and populate the values….

'There are no records returned, so we create a new record
    Set regRecord = oInstaller.CreateRecord(4)

    'in this example, we've created a record ensuring that all the non-nullable field are populated
    regRecord.StringData(1) = "MyNewSampleReg"
    regRecord.IntegerData(2) = 2
    regRecord.StringData(3) = "SOFTWARE\alkaneTest"
    regRecord.StringData(4) = "alkaneComponent"

Note how we’ve used StringData for columns which can accept strings as their data types, and IntegerData for columns which accept numeric values only.
Again, to find columns with an ‘Integer’ data type you should consult the Windows Installer help file (MSI.chm) or MSDN.

Once we’ve created our new record, we insert it:

regView.Modify msiViewModifyInsert,regRecord

So, here it is:

'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 msiViewModifyInsert = 1
Const msiViewModifyUpdate = 2
Const msiViewModifyDelete = 6
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 sql : sql = "SELECT `Registry`,`Root`,`Key`,`Component_` FROM `Registry` WHERE `Registry` = 'MyNewSampleReg'"
'create a view of the registry we want to see
Dim regView : Set regView = oDatabase.OpenView(sql)

'execute the query
regView.Execute 
Set regRecord = regView.Fetch

If regRecord Is Nothing Then
	'There are no records returned, so we create a new record
	Set regRecord = oInstaller.CreateRecord(4)

	'in this example, we've created a record ensuring that all the non-nullable field are populated
	regRecord.StringData(1) = "MyNewSampleReg"
	regRecord.IntegerData(2) = 2
	regRecord.StringData(3) = "SOFTWARE\alkaneTest"
	regRecord.StringData(4) = "alkaneComponent"

	regView.Modify msiViewModifyInsert,regRecord

End If

oDatabase.Commit

regView.Close
Set regView = Nothing
Set regRecord = Nothing
Set oDatabase = Nothing
Set oInstaller = Nothing

Thanks for reading about inserting a registry value in an MSI database using the Modify method.  Next you can find out how to handle tables that don’t exist in an MSI database using VBScript.

Deleting a registry value in an MSI database (Modify method)

This blog entry provides an example of deleting a registry value in an MSI database using the Modify method and VBScript.  It follows on from the previous blog post which provided a tutorial on uddating a primary key in an MSI database using the Modify method and VBScript.

It forms part 8 of an 17-part series that explores how to use VBScript to manipulate MSI relational databases using the Windows Installer API.  Throughout this series of tutorials, we identify the common issues that we encounter and the best practises that we use to overcome them.

Use the scripts in Tutorial 8/Tutorial 9, but replace these lines:

regRecord.StringData(1) = "newTestValue"
regView.Modify msiViewModifyUpdate, regRecord

with

regView.Modify msiViewModifyDelete, regRecord

Thanks for reading about deleting a registry value in an MSI database using the Modify method.  Next you can find out how to insert a registry value in an MSI database using the Modify method and VBScript.

Updating a primary key in an MSI database (Modify method)

This blog entry provides an example of updating a primary key in an MSI database using the Modify method and VBScript.  It follows on from the previous blog post which provided a tutorial on updating a registry value using the Modify method of an MSI database.

It forms part 7 of an 17-part series that explores how to use VBScript to manipulate MSI relational databases using the Windows Installer API.  Throughout this series of tutorials, we identify the common issues that we encounter and the best practises that we use to overcome them.

Here we would change the SQL query to select our primary key value (in other words, we’re selecting the Registry column now instead of the Value column):

Dim regView : Set regView = oDatabase.OpenView("SELECT `Registry` FROM `Registry` WHERE `Registry` = 'SampleReg'")

and we would modify it like this:

regRecord.StringData(1) = "NewSampleReg"
regView.Modify msiViewModifyReplace, regRecord

Note that this essentially won’t update that particular row. Instead it will delete the current row, and insert the new row containing the new primary key value.

Thanks for reading about updating a primary key in an MSI database using the Modify method and VBScript.  Next you can find out how to delete a registry value in an MSI database using the Modify method and VBScript.