PowerShell Problem Solver: Searching the Registry to Find Installed Software

In the first part of this series we looked at using WMI to identify installed applications. While I believe that is an effective method, it can be painfully slow. Fortunately, there is another path to explore and that is by searching the registry. Most applications that are installed via an installation package will record uninstalled information in the registry. There’s no guarantee of knowing if something you find in the registry is in fact still installed, and of course, not every installed application will record itself. But let’s look at how you could query this information because I’m sure more than a few of you will find it useful.


It is not too difficult to query the registry with PowerShell. However, you can only query using the Registry PSDrive on the local computer. To query remote computers, simply wrap the commands I’ll be showing you in a script block and use the Invoke-Command. In fact, let’s jump right to it, and here’s a one-line command to list names of applications that can be uninstalled.

dir HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | Get-Itemproperty -Name Displayname | Select Displayname

To run on a remote computer, use something like this:

Invoke-Command –scriptblock {dir HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | Get-Itemproperty -Name Displayname | Select Displayname } –computername Desk01

There is a potential problem here in that some registry entries might not have a Displayname property, which will result in an error. If you are merely looking for a quick list, you can substitute the registry key name for any missing displayname properties.

dir HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall |
Get-Itemproperty | Select @{Name="Name";Expression={
if ($_.displayname) { $_.Displayname }  else { $_.PSChildname}
}} | Out-GridView -title "Uninstalls"

Here’s my result.

Uninstall results after substituting the registry key name for any missing displayname properties. (Image Credit: Jeff Hicks)
Uninstall results after substituting the registry key name for any missing displayname properties. (Image Credit: Jeff Hicks)

By the way, I’ll be showing results from my computer. I test and try out a lot of different applications, so don’t take anything you see that I might have installed as a recommendation.

But I’m expecting you want to know more than merely the name. Let’s drill down and get some more information.

dir HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall -PipelineVariable p |
Get-ItemProperty | Select @{Name="Path";Expression={$p.name}},Displayname,DisplayVersion,
Publisher,InstallDate,InstallLocation,Comments,UninstallString	

Using the pipelinevariable common parameter in PowerShell to obtain more information about installed software. (Image Credit: Jeff Hicks)
Using the pipelinevariable common parameter in PowerShell to obtain more information about installed software. (Image Credit: Jeff Hicks)

My command is taking advantage of the new pipelinevariable common parameter. This parameter has an alias of pv. The end result is that the output of the directory listing is stored in $p. I can reference objects from that variable later in my expression. In my command, I am defining a new property called Path that uses the Name property of each directory item, pulled from $p.
As you look through the results, you’ll realize there are many “applications” that are merely updates, especially if you have Microsoft Office installed. What I think you will find more helpful is to filter out these applications.

$data = dir HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall |
where {$_.name -notmatch '(\.)?KB\d+'}  -pv p |
Get-ItemProperty | Where {$_.displayname -notmatch "KB\d{5,}"} |
Select @{Name="Path";Expression={$p.name}},Displayname,DisplayVersion,
Publisher,InstallDate,InstallLocation,Comments,UninstallString

My solution is to filter out using regular expression patterns, any entry that includes the string KB followed by a series of numbers. My result will be similar to the screenshot above, but without any of the update entries. The reason I saved the result to a variable is because I want to add to it. What am I adding? On 64bit machines there is another registry location to check: HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall. I am going to repeat my command using this new path and append the results to $Data.

$data += dir HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall |
where {$_.name -notmatch '(\.)?KB\d+'}  -pv p |
Get-ItemProperty | Where {$_.displayname -notmatch "KB\d{5,}"} |
Select @{Name="Path";Expression={$p.name}},DisplayName,DisplayVersion,
Publisher,InstallDate,InstallLocation,Comments,UninstallString

Now I can do whatever I want with $data, and I should have a good feel what applications are installed or at least what can be uninstalled. To query a remote machine, I can wrap these commands inside a script block and use the Invoke-Command.

Finally, there is one more location in the registry where you might find this type of information and that is per user. You can use similar registry query techniques for HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall.

dir HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall -pv p |
get-ItemProperty |
Select @{Name="Path";Expression={$p.name}},Displayname,DisplayVersion,
Publisher,InstallDate,InstallLocation,Comments,UninstallString	

My experience with applications under HKCU is that I don’t need to filter out anything.

Querying installed applications in the HKCU with PowerShell. (Image Credit: Jeff Hicks)
Querying installed applications in the HKCU with PowerShell. (Image Credit: Jeff Hicks)

But there is one enormous caveat, which most of you are probably thinking about. When you run a query like this remotely, HKCU will be for the account you use to connect such as administrator. If it is a server where someone might have installed something under that account, then you could see something. But if you are checking a user’s desktop you won’t see what they installed unless you connect with their credentials, which you are probably not going to be able to do.
Next time I’ll guide you through some ways to still query the user hives.