Answered by:
Pull a MSI Property from a powershell custom object

Question
-
Have managed to use the information from Nicolaj http://www.scconfigmgr.com/2014/08/22/how-to-get-msi-file-information-with-powershell/
and Keith's blog https://keithga.wordpress.com/2014/09/30/use-power-to-get-msi-properties/ I'm having some issue pulling a specific value out at the end, E.G. Product Code ($PCode). I have to find Product Code in the array and pull that line into a new variable then pull the value directly ($PCode.MSIValue). (I want all the values found on the MSI but only need to pull specific lines for various requirements.
I think I should be able to pull this out of $MSIResult in a more direct fashion but having problems figuring that out.
Thanks,
$file = "C:\scripttest\ReportViewer2012.msi" $Path = [System.IO.FileInfo]$File $WindowsInstaller = New-Object -com WindowsInstaller.Installer $MSIDatabase = $WindowsInstaller.GetType().InvokeMember("OpenDatabase","InvokeMethod",$Null,$WindowsInstaller,@($Path.FullName,0)) $Query = "SELECT * FROM Property" $View = $MSIDatabase.GetType().InvokeMember("OpenView", "InvokeMethod", $null, $MSIDatabase,($Query)) $View.GetType().InvokeMember("Execute", "InvokeMethod", $null, $View, $null) $MSIResult = @() While($Record = $View.GetType().InvokeMember("Fetch","InvokeMethod",$null,$View,$null)) { $test = New-Object -TypeName PSObject Add-Member -InputObject $Test -type NoteProperty -Name MSIName -Value ($Record.GetType().InvokeMember("StringData","GetProperty",$null,$Record,1)) Add-Member -InputObject $Test -type NoteProperty -Name MSIValue -Value ($Record.GetType().InvokeMember("StringData","GetProperty",$null,$Record,2)) # $test += @{ $Record.GetType().InvokeMember("StringData","GetProperty",$null,$Record,1) = $Record.GetType().InvokeMember("StringData","GetProperty",$null,$Record,2)} $MSIResult += $test } # Commit database and close view $MSIDatabase.GetType().InvokeMember("Commit", "InvokeMethod", $null, $MSIDatabase, $null) $View.GetType().InvokeMember("Close", "InvokeMethod", $null, $View, $null) $MSIDatabase = $null $View = $nul Select-Object -InputObject $test -Property Name = ProductCode $test.name $test | where-Object {$_.name -eq "ProductCode"} $MSIResult | Select-Object -Property MSIName, MSIValue |where MSIName -EQ ProductCode $PCode = $MSIResult.Where({$_.MSIName -eq 'ProductCode'}) $PCode.msivalue
http://www.scconfigmgr.com/2014/08/22/how-to-get-msi-file-information-with-powershell/
Thursday, October 26, 2017 10:09 PM
Answers
-
Like this:
$msifile = 'd:\test7\MBSASetup-x64-EN.msi' $WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer $MSIDatabase = $WindowsInstaller.GetType().InvokeMember('OpenDatabase', 'InvokeMethod', $Null, $WindowsInstaller, @($msifile, 0)) $Query = 'SELECT * FROM Property' $View = $MSIDatabase.GetType().InvokeMember('OpenView', 'InvokeMethod', $null, $MSIDatabase, ($Query)) $View.GetType().InvokeMember('Execute', 'InvokeMethod', $null, $View, $null) $hash = @{} $MSIResult = while ($Record = $View.GetType().InvokeMember('Fetch', 'InvokeMethod', $null, $View, $null)) { $name = $Record.GetType().InvokeMember('StringData', 'GetProperty', $null, $Record, 1) $value = $hashMSIValue = $Record.GetType().InvokeMember('StringData', 'GetProperty', $null, $Record, 2) $hash.Add($name,$value) } $msiProperties = [pscustomobject]$hash
Now you can just do this:
$msiProperties |fl
Or this:
PS > $msiProperties |select ProductName, ProductCode ProductName ProductCode ----------- ----------- Microsoft Baseline Security Analyzer 2.3 {C058FC5D-565F-4360-A562-0527A3D993DC}
\_(ツ)_/
Thursday, October 26, 2017 10:28 PM
All replies
-
Like this:
$msifile = 'd:\test7\MBSASetup-x64-EN.msi' $WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer $MSIDatabase = $WindowsInstaller.GetType().InvokeMember('OpenDatabase', 'InvokeMethod', $Null, $WindowsInstaller, @($msifile, 0)) $Query = 'SELECT * FROM Property' $View = $MSIDatabase.GetType().InvokeMember('OpenView', 'InvokeMethod', $null, $MSIDatabase, ($Query)) $View.GetType().InvokeMember('Execute', 'InvokeMethod', $null, $View, $null) $hash = @{} $MSIResult = while ($Record = $View.GetType().InvokeMember('Fetch', 'InvokeMethod', $null, $View, $null)) { $name = $Record.GetType().InvokeMember('StringData', 'GetProperty', $null, $Record, 1) $value = $hashMSIValue = $Record.GetType().InvokeMember('StringData', 'GetProperty', $null, $Record, 2) $hash.Add($name,$value) } $msiProperties = [pscustomobject]$hash
Now you can just do this:
$msiProperties |fl
Or this:
PS > $msiProperties |select ProductName, ProductCode ProductName ProductCode ----------- ----------- Microsoft Baseline Security Analyzer 2.3 {C058FC5D-565F-4360-A562-0527A3D993DC}
\_(ツ)_/
Thursday, October 26, 2017 10:28 PM -
Thanks,
I figured a hash table would be needed, thanks for showing how with the convoluted data pull from MSI's.
Found a couple of interesting articles on the Speed of using [pscustomobject] and it's features with hash tables
and
http://www.jonathanmedd.net/2011/09/powershell-v3-creating-objects-with-pscustomobject-its-fast.html
- Edited by J A M Monday, November 13, 2017 1:27 PM
Friday, October 27, 2017 6:15 AM