public/Get-MSIDatabasePropertyValue.ps1
<#
.SYNOPSIS Obtains the value for a property from an MSI database. .DESCRIPTION Given a path to an MSI and a property name (will default to ProductCode) it will return the value of that property. .EXAMPLE PS C:\> Get-MSIDatabaseProperty -Path \path\to\msi.msi This will return the product code for the given MSI .EXAMPLE PS C:\> Get-MSIDatabaseProperty -Path \path\to\msi.msi -Property UpgradeCode This will return the upgrade code from the MSI .PARAMETER Path The full path to the MSI, will check to ensure the file extension is MSI. .PARAMETER Property The property to pull the value of from the database. This will default to ProductCode. #> function Get-MSIDatabasePropertyValue { [CmdletBinding()] param( [Parameter( Mandatory = $true, HelpMessage = "Path to MSI, file extension will be validated and must be .msi" )] [ValidateScript( { if ([IO.Path]::GetExtension($_) -eq ".msi") { Write-Output $true } else { Write-Output $false } })] [string]$Path, [Parameter( Mandatory = $false, HelpMessage = "The property to obtain the value from. This will default to ProductCode." )] [string]$Property = "ProductCode" ) Process { try { if ($Path.StartsWith('\\')) { # Get filename $MSIFilename = Split-path -Path $Path -Leaf Write-Information "MSI is on network share, need to copy to $($env:temp) to get product code" Copy-Item -Path $Path -Destination "$($env:temp)\$MSIFilename" -Force $MSIPath = "$($env:temp)\$MSIFilename" } else { $MSIPath = $Path } # Read property from MSI database $WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer # Opens the database as read-only (0) $MSIDatabase = $WindowsInstaller.GetType().InvokeMember("OpenDatabase", "InvokeMethod", $null, $WindowsInstaller, @($MSIPath, 0)) $MSIQuery = "SELECT Value FROM Property WHERE Property = '$Property'" $View = $MSIDatabase.GetType().InvokeMember("OpenView", "InvokeMethod", $null, $MSIDatabase, ($MSIQuery)) $View.GetType().InvokeMember("Execute", "InvokeMethod", $null, $View, $null) $Record = $View.GetType().InvokeMember("Fetch", "InvokeMethod", $null, $View, $null) $Value = $Record.GetType().InvokeMember("StringData", "GetProperty", $null, $Record, 1) # Commit database and close view $MSIDatabase.GetType().InvokeMember("Commit", "InvokeMethod", $null, $MSIDatabase, $null) $View.GetType().InvokeMember("Close", "InvokeMethod", $null, $View, $null) $MSIDatabase = $null $View = $null # Return the value return $Value } catch { Write-Warning -Message $_.Exception.Message ; break } } End { # Run garbage collection and release ComObject [System.Runtime.Interopservices.Marshal]::ReleaseComObject($WindowsInstaller) | Out-Null [System.GC]::Collect() } } |