locked
Pull a MSI Property from a powershell custom object RRS feed

  • 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}
    


    \_(ツ)_/


    • Edited by jrv Thursday, October 26, 2017 10:30 PM
    • Marked as answer by J A M Friday, October 27, 2017 6:15 AM
    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}
    


    \_(ツ)_/


    • Edited by jrv Thursday, October 26, 2017 10:30 PM
    • Marked as answer by J A M Friday, October 27, 2017 6:15 AM
    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

    https://kevinmarquette.github.io/2016-10-28-powershell-everything-you-wanted-to-know-about-pscustomobject/

    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