MSI Installer – delete a table record

Welcome to the party, pal.

I recently had the need to adapt a feisty MSI installer that was not succumbing to the normal PROPERTY command line or transform file methods. Whether this was due to a fault while packaging, a deliberate choice during packaging, or a mind-obliteratingly rare instance of me making a mistake, I don’t know.

The problem: MSI installer giving entirely too much sass.
The solution: Delete a record from a table within the installer.
The means: (Keep reading to find out! Ohhhh boy!)

Below is a PowerShell script that will remove a record from an MSI installer table. The point, The want, nay — The Impetus — is that the com object used is native to Windows and does not require installing Orca. This means that you (I/myself/the-one-who-is-not “you”) can script the intake of the problematic installer and deployment without the extra Orca (a vicious sea mammal that kills for fun) ordeal.

Param (
	[Parameter(Mandatory=$true)]$MsiPath,
	[Parameter(Mandatory=$true)]$TableName,
	[Parameter(Mandatory=$true)]$PropertyName,
	$PropertyValue=""
)

# Create a new Windows Installer Object
$windowsInstaller = New-Object -ComObject WindowsInstaller.Installer

# Open the MSI database in transaction mode
try {
	$database = $windowsInstaller.OpenDatabase($msiPath, 1)
} catch {
	Write-Host "Error opening database: $_"
	exit
}

# Query to access the specific row in the table
# Literal backticks are required for table and column names with spaces
$query = "SELECT * FROM ``$TableName`` WHERE ``$PropertyName`` = '$PropertyValue'"

# Open a view of the table
try {
	$view = $database.OpenView($query)
	$view.Execute()
} catch {
	Write-Host "Error opening view: $_"
	$database.Commit()
	$database = $null
	[System.Runtime.Interopservices.Marshal]::ReleaseComObject($windowsInstaller) | Out-Null
	exit
}

# Delete record
try {
	$record = $view.Fetch()
	if ($record -ne $null) { $view.Modify(6, $record) }
} catch {
	Write-Host "Error modifying view: $_"
}

$view.Close()
$database.Commit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($view) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($database) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($windowsInstaller) | Out-Null

Leave a comment