Today we discuss how to list all locally installed applications. This is to say that we need to list all programs installed on the computer. This needs to also include if the application is installed to AppData for each user.
It was recently asked. I cannot get a list of applications from the computer that has all of the applications installed listed. Why? Simple answer, there are at least three important locations to get this information from.
What was being asked can to be done with Get-CimInstance
, but that comes at a cost and is no longer accurate. It used to be a WMI command. Now CIM. It is not a fast command, more on that later.
Get-CimInstance win32_product
The cost is Get-CimInstance
can return incomplete data.
It also runs a consistency check on all applications and performs automatic and silent repairs.
Yes, when you run this command, it automatically runs a consistency check on all applications and performs automatic and silent repairs. That is why this simple command is so slow to report back. Microsoft’s documentation on this: Link Here
So we do not use that anymore, now what? What we are looking for is gathering the information from both 32 and 64 bit installers that looks like this and must be done. This is the first step.
$installedApplications = @() $installedApplications+= Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" # 32 Bit $installedApplications+= Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" # 64 Bit
One caveat to the above is that the above method will return a ton more elements than the Win32_Product
command does. It will have things such as Service Packs, Office Updates, Language Packs, etc. Filtering out things you do not want to see should happen. Though you shouldn’t have an issue using PowerShell to filter results.
To complete this, how do you quantify data from installers regardless of their install location? Specifically finding the userprofile\AppData
install information. The good news is these applications have their installation information documented in the registry as well, under HKEY_CURRENT_USER
instead of HKEY_LOCAL_MACHINE
. What this means is every user’s install location information is sitting in the registry hive under their profile, for instance c:\users\inet\NTUSER.DAT
.
HKEY_USERS\$ACCOUNT_SID
key.REG LOAD
So how do we get what you are asking for, which is to replicate the “full install data” for the device, and not just what’s in the 32 and 64bit directories?
This is what I use, if one so chooses you can pipe the info to CSV/HTML/etc…
$32BitPath = "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" $64BitPath = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" $installedApplications = @() $installedApplications+= Get-ItemProperty $32BitPath $installedApplications+= Get-ItemProperty $64BitPath $tigerStripes= Get-CimInstance Win32_UserProfile | Select LocalPath, SID, Loaded, Special | Where {$_.SID -like "S-1-5-21-*"} $unavailableProfiles = $tigerStripes| Where {$_.Loaded -eq $true} $availableProfiles = $tigerStripes| Where {$_.Loaded -eq $false} #Mounted $unavailableProfiles | %% { $installedApplications += Get-ItemProperty -Path "Registry::\HKEY_USERS\$($_.SID)\$32BitPath" $installedApplications += Get-ItemProperty -Path "Registry::\HKEY_USERS\$($_.SID)\$64BitPath" } #Unmounted $availableProfiles | %% { #Mount Hive $Hive = "$($_.LocalPath)\NTUSER.DAT" if (Test-Path $Hive) { REG LOAD HKU\temp $Hive $installedApplications += Get-ItemProperty -Path "Registry::\HKEY_USERS\temp\$32BitPath" $installedApplications += Get-ItemProperty -Path "Registry::\HKEY_USERS\temp\$64BitPath" # Run manual GC to allow hive to be unmounted [GC]::Collect() [GC]::WaitForPendingFinalizers() REG UNLOAD HKU\temp } else { Write-Warning "Unable to access registry at $Hive" } }