sebbu

get-msi (from coffee)

Sep 19th, 2019 (edited)
263
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. Try {
  3.     $CsvOutPath = '.\MsiList.csv'
  4.     $SearchPath = '.\'
  5.  
  6.     Function local:InvokeMember
  7.     {
  8.         Param ( [PSObject]$Target, [String]$Name, $MyArgs = @() )
  9.        
  10.         Return ($Target).GetType().InvokeMember(
  11.             $Name, [System.Reflection.BindingFlags]::InvokeMethod,
  12.                 $NULL, ($Target), $MyArgs )
  13.         # https://docs.microsoft.com/en-us/dotnet/api/system.type.invokemember?view=netframework-4.8#System_Type_InvokeMember_System_String_System_Reflection_BindingFlags_System_Reflection_Binder_System_Object_System_Object___
  14.     }
  15.  
  16.     Function local:GetProperty
  17.     {
  18.         Param ( [PSObject]$Target, [String]$Name, $MyArgs = @() )
  19.        
  20.         Return ($Target).GetType().InvokeMember(
  21.             $Name, [System.Reflection.BindingFlags]::GetProperty,
  22.                 $NULL, ($Target), $MyArgs )
  23.         # https://docs.microsoft.com/en-us/dotnet/api/system.type.invokemember?view=netframework-4.8#System_Type_InvokeMember_System_String_System_Reflection_BindingFlags_System_Reflection_Binder_System_Object_System_Object___
  24.     }
  25.  
  26.     [System.Collections.ArrayList]$Result = New-Object -TypeName System.Collections.ArrayList(0)
  27.  
  28.     $Inst = New-Object -ComObject WindowsInstaller.Installer
  29.  
  30.     gci -Path $SearchPath -Filter *.msi -Recurse -Force -ErrorAction SilentlyContinue | % {
  31.  
  32.         [hashtable]$cur = @{'path'=($_.FullName)}
  33.  
  34.         $MsiDataBase = InvokeMember $Inst 'OpenDatabase' $_.FullName, 0
  35.         # ^ https://docs.microsoft.com/en-us/windows/win32/msi/installer-opendatabase
  36.         # ^ https://docs.microsoft.com/en-us/windows/win32/msi/database-object
  37.  
  38.         ('ProductCode','ProductName','ProductVersion','Manufacturer') | % {
  39.  
  40.             [String]$Query = ('SELECT Value FROM Property WHERE Property = ''{0}''' -f $_)
  41.        
  42.             $View = InvokeMember $MsiDataBase 'OpenView' $Query
  43.             # ^ https://docs.microsoft.com/en-us/windows/win32/msi/database-openview
  44.             # ^ https://docs.microsoft.com/en-us/windows/win32/msi/view-object
  45.  
  46.             InvokeMember $View 'Execute'
  47.             # ^ https://docs.microsoft.com/en-us/windows/win32/msi/view-execute
  48.  
  49.             $Record = InvokeMember $View 'Fetch'
  50.             # ^ https://docs.microsoft.com/en-us/windows/win32/msi/view-fetch
  51.             # ^ https://docs.microsoft.com/en-us/windows/win32/msi/record-object
  52.  
  53.             $Value = GetProperty $Record 'StringData' 1
  54.             # https://docs.microsoft.com/en-us/windows/win32/msi/record-stringdata
  55.             $cur[$_] = $Value
  56.            
  57.             InvokeMember $View 'Close'
  58.             # ^ https://docs.microsoft.com/en-us/windows/win32/msi/view-close
  59.  
  60.             $View = $NULL
  61.  
  62.             if ( ([String]$_ -eq 'ProductName') ) {
  63.                 if ( ([String]$Value -eq '. .') -or ([String]$Value -eq '. . .') -or ([String]$Value -eq '') ) {
  64.                     [String]$Query = 'SELECT Title FROM Feature WHERE Feature = ''ProductFeature'''
  65.                     $View = InvokeMember $MsiDataBase 'OpenView' $Query
  66.                     InvokeMember $View 'Execute'
  67.                     $Record = InvokeMember $View 'Fetch'
  68.                     $Value = GetProperty $Record 'StringData' 1
  69.                     $cur[$_] = $Value
  70.                     InvokeMember $View 'Close'
  71.                     $View = $NULL
  72.                 }
  73.             }
  74.         } # ~ attrs
  75.  
  76.         # echo ("{0}" -f $cur['ProductCode'])
  77.         $res = Test-Path ("HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{0}" -f $cur['ProductCode'])
  78.         if ($res -eq "True") {
  79.             $cur['Installed'] = 1
  80.         }
  81.         else {
  82.             $res = Test-Path ("HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\{0}" -f $cur['ProductCode'])
  83.             if ($res -eq "True") {
  84.                 $cur['Installed'] = 1
  85.             }
  86.             else {
  87.                 $cur['Installed'] = 0
  88.             }
  89.         }
  90.  
  91.         InvokeMember $MsiDataBase 'Commit'
  92.         # ^ https://docs.microsoft.com/en-us/windows/win32/msi/database-commit
  93.         $MsiDataBase = $NULL
  94.  
  95.         $Result.Add( $cur ) | Out-Null
  96.     } # ~ gci
  97.  
  98.  
  99.     if ( $Result.Count -ne 0 )
  100.     {
  101.         $Result |
  102.             Sort-Object -Property @{ e={$_.'path'} } |
  103.             Select -Property `
  104.                 @{ n='Path'; e={$_.'path'} },
  105.                 @{ n='Company'; e={$_.'Manufacturer'} },
  106.                 @{ n='Product Name'; e={$_.'ProductName'} },
  107.                 @{ n='Product Version'; e={$_.'ProductVersion'} },
  108.                 @{ n='Product Code'; e={$_.'ProductCode'} },
  109.                 @{ n='Installed'; e={$_.'Installed'} } |
  110.             Export-Csv -Delimiter ';' -NoTypeInformation -Encoding UTF8 -Path $CsvOutPath
  111.     }
  112. }
  113. Finally {
  114.     [System.Runtime.Interopservices.Marshal]::ReleaseComObject($Inst) | Out-Null
  115.     [System.GC]::Collect()
  116. }
Add Comment
Please, Sign In to add comment