Getting a list of installed software with a script is never going to be perfect – there are just too many loopholes, but you can get close. This is part 2 of 4 (Part 1 is here, Part 3 is here, and Part 4 is here).
In the past I’ve used WMI’s Win32_Product class to achieve these results (though that was a long time ago) – but please DO NOT use the Win32_Product WMI class – even if it looks like a much easier/simpler/cleaner solution. That class has many side-effects that you may not be aware of (see here and here).
Below is the most comprehensive solution I’ve been able to come up with to-date, but again, it’s not bulletproof – just “good enough” for most of what I’d use it for. It also includes most Windows and Office updates in its output.
This script queries two different parts of the Windows Registry and returns an object, $software, with the display name, version, install date (if recorded), and uninstall string of each piece of software found.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# Try getting 64-bit software registry entries try { $softwareregistry1 = (get-itemproperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*) | select "(default)", displayname, pschildname, displayversion, installdate, uninstallstring; } catch { $softwareregistry1 = $null;} # Try getting 32-bit software registry entries try { $softwareregistry2 = (get-itemproperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*) | select "(default)", displayname, pschildname, displayversion, installdate, uninstallstring; } catch { $softwareregistry2 = $null;} # Combines both lists, only selecting the unique entries (sometimes they are duplicated) $softwareregistry = $softwareregistry1 + $softwareregistry2 | select -unique * # Initialise output object $software = @(); # Loop through registry results to fix empty displaynames foreach ($item in $softwareregistry) { # If the displayname is blank, replace with the "default" property if ($item.displayname -eq $null) { $item.displayname = $item."(default)"; } # If the displayname is still blank, replace with the pschildname property if ($item.displayname -eq $null) { $item.displayname = $item.pschildname; } # Add item to output object only if displayname is not blank if ($item.displayname -ne "") { # Remove "(default)" and pschildname from $item $item = $item | select displayname, displayversion, installdate, uninstallstring; $software = $software + $item } } |
Out of interest, the (not to be used) WMI method on my computer only found 106 bits of software installed, whereas the registry method found 313. A decisive victory: