0
votes

I stuck at a problem by reading multiple non static values from a Msi file with powershell. Are there any Ideas?

I want read non static values from a Msi tables.

I can actually read static values from the table Properties, but one by one. like this function readMsiProperties($msifile, $Property) {

# Read property from MSI database
$WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer
$MSIDatabase = $WindowsInstaller.GetType().InvokeMember("OpenDatabase", "InvokeMethod", $null, $WindowsInstaller, @($msiFile, 0))
$Query = "SELECT Value FROM Property WHERE Property = '$Property'"

try {

    $View = $MSIDatabase.GetType().InvokeMember("OpenView", "InvokeMethod", $null, $MSIDatabase, ($Query))
    $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 $Value
    #Catch NullValues if a Query is not correct or not in the MSI File
}
Catch {

}

}

This works perfeclty for the Property table. But if i want to read something from Serviceinstall table, there are no static values i can use like an anchor.

if i try it in this way i get an "InvokeMember with 5 Arguments exception" for the Variable $view.

function readMsiServiceTable($msifile) {

#try{
# Read property from MSI database
$WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer
$MSIDatabase = $WindowsInstaller.GetType().InvokeMember("OpenDatabase", "InvokeMethod", $null, $WindowsInstaller, @($msiFile, 0))
$Query = "SELECT '*' FROM 'ServiceInstall' "

try {

    $View = $MSIDatabase.GetType().InvokeMember("OpenView", "InvokeMethod", $null, $MSIDatabase, ($Query))

So what can i do instead. the Idea ist to read this non static values into an array or a list to work with it.

Thanks!!

1

1 Answers

0
votes

See here (and an example below) for how to use PowerShell to query an MSI database: https://www.alkanesolutions.co.uk/2016/12/13/query-windows-installer-msi-using-powershell/

$msiOpenDatabaseModeReadOnly = 0
$msiOpenDatabaseModeTransact = 1

$windowsInstaller = New-Object -ComObject windowsInstaller.Installer

$pathToMSI = "C:\temp\test.msi"

$database = $windowsInstaller.GetType().InvokeMember("OpenDatabase", "InvokeMethod", $null, $windowsInstaller, @($pathToMSI, $msiOpenDatabaseModeReadOnly))

$query = "SELECT * FROM ServiceInstall"
$propView = $database.GetType().InvokeMember("OpenView", "InvokeMethod", $null, $database, ($query))
$propView.GetType().InvokeMember("Execute", "InvokeMethod", $null, $propView, $null) | Out-Null
$propRecord = $propView.GetType().InvokeMember("Fetch", "InvokeMethod", $null, $propView, $null)

while  ($propRecord -ne $null)
{
    $serviceInstall = $propRecord.GetType().InvokeMember("StringData", "GetProperty", $null, $propRecord, 1)
    $serviceName = $propRecord.GetType().InvokeMember("StringData", "GetProperty", $null, $propRecord, 2)
    $serviceType = $propRecord.GetType().InvokeMember("IntegerData", "GetProperty", $null, $propRecord, 4)

    write-host $serviceInstall $serviceName $serviceType

    #fetch the next record
    $propRecord = $propView.GetType().InvokeMember("Fetch", "InvokeMethod", $null, $propView, $null)    
}

$propView.GetType().InvokeMember("Close", "InvokeMethod", $null, $propView, $null) | Out-Null          
$propView = $null 
$propRecord = $null
$database = $null