Use PowerShell to Find Installed Software

Use PowerShell to Find Installed Software

  • Comments 32
  • Likes

Summary: Guest blogger, Marc Carter, reprises his popular blog post about locating installed software.

Microsoft Scripting Guy, Ed Wilson, is here. Marc Carter is joining us again today with another guest blog post...

Looking back a couple years ago to my previous post, Use PowerShell to Quickly Find Installed Software, I find it interesting to reflect on common issues shared amongst the IT pro community. In our underlying goal to control our environment, whether that environment consists of a desktop computer, a development server, or production data center, we must first discover and understand before we can effectively attempt to control. Such is the case for sys admins when determining what software is currently configuring a server.

But first, let’s have a quick refresher on what initially prompted this discussion…

Win32_Product: The Good, the Bad, and the Ugly

 [Good] The Win32_Product WMI class represents products as they are installed by Windows Installer.

If you choose to query Win32_Product class by using Get-WmiObject, you’ll find yourself [Bad] waiting for your query (or application) to return [Ugly] a consistency check of packages that are installed as it attempts to verify and repair installs. (For more information, see Event log message indicates that the Windows Installer reconfigured all installed applications).

Problem #1: Um, is there a problem, officer?

Querying the Win32_Product class to determine installed software is more than likely not your “best” option. Unfortunately, not everyone knows this.

Solution: (Understanding) Do your part and help spread the word.

Problem #2: Identify better alternatives

I really like some of the refinements and suggestions within comments that were mentioned by others on my previous post. One of the things I take a lot of pride in is my association with the men and women of US Army and their core values (The Army Values).

I see that similar mindset and participation reflected in the esprit de corps (or cohesion) of the Windows PowerShell community. As others have pointed out, there are a lot better and easier ways to gather information without invoking the Win32_Product class. One of my favorite alternatives involved suggestions from Knut Johansen and Mike Crowley: use the PS Registry Provider.

The Windows PowerShell Registry provider lets you get, add, change, clear, and delete registry keys, entries, and values in Windows PowerShell. The Registry provider lets you access a hierarchical namespace that consists of registry keys and subkeys. Registry entries and values are not components of that hierarchy. Instead, they are properties of each of the keys. The Registry provider supports all the cmdlets that contain the “item” noun—that is, the Item cmdlets (except Invoke-Item) such as Get-Item, Copy-Item, and Rename-Item. Use the Item cmdlets when you work with registry keys and subkeys.
For more information, see Registry Provider.

In the following example, I use the Get-ItemProperty cmdlet to return values from the Uninstall Registry Key within the HKEY LOCAL MACHINE (HKLM) Registry Provider, selecting specific properties and then formatting output.

Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |  Select-Object DisplayName, DisplayVersion, Publisher, InstallDate |
Format-Table –AutoSize

The Get-ItemProperty cmdlet is a great tool because it’s designed to work with data that is exposed by any provider. To get a better idea of the various providers that are available in your session, simply execute the Get-PSProvider cmdlet.  

And of course, depending on my needs, I could have also used alternative output methods like Out-GridView or Export-Csv. Either way, we’ve now reduced the process to a one-liner that can be used in 64-bit and 32-bit environments:

Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate |
Format-Table –AutoSize

Problem #3: Can we make it even more useful?

Absolutely! We are talking Windows PowerShell after all…

One way that comes to mind (and again, visible within the comments from the previous post), is addressing the issue of how to query multiple remote devices. My solution (or a number of reasons) is to rely on using the Invoke-Command cmdlet. In the following example, I query both of my SharePoint Web Front End (WFE) servers by using Invoke-Command to execute the same Get-ItemProperty on the remote system’s HKLM PS Registry Provider:

Invoke-Command -cn wfe0, wfe1 -ScriptBlock {Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | select DisplayName, Publisher, InstallDate }

The output now includes the PSComputerName column, which will help when I want to sort results down the road. And there we have it…an easy method to report installed software!

I look forward to reading comments from the Windows PowerShell community on other refinements and ways to improve this task. In many ways, I relate our efforts to that of a symphony or band. Each of us plays a different note in that we all hear and see things differently. Put us all together on the same sheet of music, and we have the potential for some awesome melodies.


Thank you, Marc, for another awesome blog.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • This is great information. Would there be a way to know what version of Java these applications are tied to?

  • WMI may be slower but it doesn't show security updates and hotfixes

  • I'd add 2 things,

    win32_product has the additional drawback of not reporting on x86 apps for x64 systems.

    The script repository has a couple functions for download that people can download in case anyone wants to add this to one of their modules or profile.  I keep get-applicationinfo in my profile because I end up using it so much.

  • @Jason - Win32_Product reports both x*^ and x64 products on all systems I have tested on.  It only reports products installed by Windows installer and  does not report O365 components.  They are not really installed locally but are web delivered and use a different tool to report.

    Older 'Setup'  installs are not reported and XCOPY self installers are not reported  "Store Apps" are not reported.

  • jrv,

    I was tracking on it missing installs that weren't pushed with msi's.  If you're confident it catches the x86 apps on x64 systems I'll double check my statement.

    Does it make a difference when you run it from a x86 or x64 shell?

  • @Jason - just to be sure I ran it on both x86 and x64 PowerShell and both report the exact same thing.

    You are thinking of the registry install keys. You have to query both the 32 and 64 bit registry on a 64 bit system to get all installed programs and that still will not get XCOPY installs.  Java is frequently a copy install local to the app that uses it.  There is no way to know about that automatically. You must know in advance that the program sues Java and then look for the Java file.  It can be anywhere.  It is usually in a  subdir of the program called JRE.

  • Good Post

  • $app1 = Get-WmiObject Win32reg_AddRemovePrograms | Select-Object DisplayName,Version $app2 = Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object -Property DisplayName,DisplayVersion Compare-Object -ReferenceObject $app1 -DifferenceObject $app2

  • Thank you so much for sharing this post. I'd been researching and attempting several ways to gather the information, but this one bubbled to the top. Especially when adding the Wow6432Node -- provided me with exactly what I needed in preparation of a huge transition. Thank you again.

  • I found I had to change to HKLM:\Software\wow6432node to get 32 bit apps

  • how to find whether the trend mcro antivirus is installed or not

  • Interesting.. but could we go on with this and uninstall a software? Thats actually why I started to look into Win32_Product class. I could search all systems in the domain for a software and start a deinstallation. Really nice if you need to remove a specific software from all systems.

  • Can you use a similar technique to identify what account/user installed an application and when? I need this for my forensics research.

  • I have a 64-bit system and this script does not output all installed applications. It only outputs a portion of all installed applications. Isn't there a script which output ALL installed applications?

  • I had a small query, can i get information about who installed the app , who has access to the app, it would help me all lot, and please note that i have very little knowledge about powershells