How to use PowerShell to Get Installed Software?

powershell command to list installed software

Introduction

One of the most common tasks I’m asked about is how to get a list of installed software using PowerShell. Whether you’re a system administrator managing multiple computers, a developer needing to check software dependencies, or a tech support specialist troubleshooting issues, being able to get a list of installed programs using PowerShell quickly is an essential skill. In this comprehensive guide, I’ll share my knowledge and experience to walk you through the different ways to use PowerShell to find installed software, from the simplest commands for local machines to more advanced options for querying remote computers.

This article will walk through several PowerShell methods for listing installed software. Whether you’re a system administrator looking to monitor an entire fleet of computers or an individual wanting to better understand your own machine, these techniques will give you the insights you need. Let’s get started!

How to get a list of all software installed on your machine?

As a tech-savvy, you likely have a variety of software programs installed on your computer. But when was the last time you took stock of everything you have? Do you know exactly what’s been installed, when it was installed, or what version you have?

You may need the inventory of your installed software is important for several reasons:

  1. Troubleshooting: When you encounter problems with your computer, knowing what software is installed can help you identify potential culprits.
  2. Security: Keeping track of your installed programs helps you ensure everything is up-to-date and secure. You can identify old, unsupported software that may pose a security risk.
  3. Performance: An inventory helps identify unnecessary or duplicate programs that may be slowing your machine down.
  4. System Updates & Migrations: Before updating to a new OS version or migrating to a new machine, it’s helpful to know exactly what needs to be installed on the new system.

Get a List of Installed Software from the Control Panel

So, how do you generate this software inventory? You could open the Control Panel or Settings app and manually write down each entry!

Here is the process of getting a list of installed software:

  1. Press the Windows key >> Type “Control Panel”
  2. Under “Programs”, Click on “Uninstall a program”
  3. Here, you can see a list of all installed software.
    get list of installed software powershell

Note that this method may not always capture every piece of software installed on your machine, especially if the software was installed using unconventional methods and doesn’t register itself with the system’s package manager or program registry.

Luckily, PowerShell provides a quick and easy way to get a list of installed programs! With a few lines of script, you can generate a detailed software inventory, complete with details like the version number, publisher, and install date.

Why Use PowerShell to Find Installed Software?

Before diving into the technical specifics, you may be wondering – why bother using PowerShell to get a list of installed programs? Why not just open up the Control Panel and look at the “Programs and Features” screen? Well, here are a few key reasons:

  • Speed – With a single line of PowerShell, you can instantly get a full software inventory. No need to wait for screens to load or manually scroll through a list.
  • Scriptability – By using PowerShell commands, you can incorporate checking installed software into larger automation scripts, scheduled jobs, configuration management workflows, and more. It’s easy to integrate into your overall IT processes.
  • Remote Management – PowerShell allows you to check installed software on remote computers without having to physically go to each machine or connect through other tools. You can query multiple computers simultaneously.
  • Filtering & Output – PowerShell gives you the ability to customize your output, filtering the software list as needed and saving it to a file or database for further analysis and record-keeping.

PowerShell Script to List Installed Software

Now let’s walk through the actual PowerShell commands to get installed software. Below are the key commands we’ll cover, along with real-world examples:

  • Get installed software from the Registry using Get-ItemProperty / Get-ChildItem cmdlets
  • Get-WmiObject / Get-CimInstance
  • Get-Package

Getting the list of installed software from the Windows Registry

For software installed on a computer, you can query the following registry keys:

  • x86: HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall
  • x64: HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
  • current user: HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall

Here’s an example command to query the registry keys and display the software name and version:

The simplest way to get a quick list of installed programs on a local Windows computer is to use the Get-ItemProperty cmdlet targeting the registry key where software installation information is stored.

Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | 
    Where-Object {$_.DisplayName -ne $null} | 
        Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Format-Table -AutoSize

This will query the registry to pull the display name, version number, publisher, and install date for all x86, 32-bit software listed under the “Uninstall” registry key, presenting the results in a neat table. For all 64-bit versions, use:

Get-ChildItem "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" |  Get-ItemProperty | Where-Object {$_.DisplayName -ne $null} | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate

You can also use the Get-ChildItem cmdlet to get the list of applications installed on the current user’s profile:

Get-ChildItem "HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall" |  Get-ItemProperty | Where-Object {$_.DisplayName -ne $null} | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate

Let’s combine all three and generate a CSV report for all installed software in the system:

#Array to collect Installed Software details
$InstalledSoftware = New-Object System.Collections.ArrayList

#Get all 32-Bit version of Apps
$32BitApps = Get-ChildItem "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall" | Get-ItemProperty | Where-Object {$_.DisplayName -ne $null} | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate
$32BitApps | ForEach-Object { 
    $InstalledSoftware.Add([PSCustomObject]@{
        ApplicationName     = $_.DisplayName
        Version = if ($null -eq $_.DisplayVersion -or [string]::Empty -eq $_.DisplayVersion) { "N/A" } else { $_.DisplayVersion }
        Publisher      = if ($null -eq $_.Publisher -or [string]::Empty -eq $_.Publisher) { "N/A" } else { $_.Publisher }
        InstallDate = if ($null -eq $_.InstallDate -or [string]::Empty -eq $_.InstallDate) { "N/A" } else { $_.InstallDate }
        Scope = "32-Bit"
    }) | Out-Null
}
 
#Get 64 bit versions
$64BitApps = Get-ChildItem "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" | Get-ItemProperty | Where-Object {$_.DisplayName -ne $null} | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate
$64BitApps | ForEach-Object { 
   $InstalledSoftware.Add([PSCustomObject]@{
        ApplicationName     = $_.DisplayName
        Version = if ($null -eq $_.DisplayVersion -or [string]::Empty -eq $_.DisplayVersion) { "N/A" } else { $_.DisplayVersion }
        Publisher      = if ($null -eq $_.Publisher -or [string]::Empty -eq $_.Publisher) { "N/A" } else { $_.Publisher }
        InstallDate = if ($null -eq $_.InstallDate -or [string]::Empty -eq $_.InstallDate) { "N/A" } else { $_.InstallDate }
        Scope = "64-Bit"
    })| Out-Null
}
#Get Software installed in Current user scope
$CurrentUserApps = Get-ChildItem "HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall" | Get-ItemProperty | Where-Object {$_.DisplayName -ne $null} | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate
$CurrentUserApps | ForEach-Object { 
      $InstalledSoftware.Add([PSCustomObject]@{
        ApplicationName     = $_.DisplayName
        Version = if ($null -eq $_.DisplayVersion -or [string]::Empty -eq $_.DisplayVersion) { "N/A" } else { $_.DisplayVersion }
        Publisher      = if ($null -eq $_.Publisher -or [string]::Empty -eq $_.Publisher) { "N/A" } else { $_.Publisher }
        InstallDate = if ($null -eq $_.InstallDate -or [string]::Empty -eq $_.InstallDate) { "N/A" } else { $_.InstallDate }
        Scope           = "Current User"
    }) | Out-Null
}

#Export the Installed software list to CSV
$InstalledSoftware | Sort-Object -Property ApplicationName, Version, Publisher, InstallDate, Scope -Unique | Export-csv -NoTypeInformation "C:\Temp\SoftwareList.csv"

This PowerShell script generates a CSV file with all software installed on a machine:

powershell get software installed

Get-Package

If you’re using the PowerShell 5.1 you can utilize the Get-Package cmdlet to retrieve details on installed programs. This queries the PackageManagement database rather than the registry directly.

Get-Package | Select-Object Name, Version, Source, ProviderName

This will give you a concise table listing the name, version, source and provider for each installed package. One advantage of Get-Package is that it works for both Windows applications and any packages installed via PackageManagement (like PowerShellGet modules).

To filter the Get-Package output to only specific types of packages, you can use the “-ProviderName” parameter. For example, to only get MSI-based software installations:

Get-Package -ProviderName @("Programs","msi","msu") | Select-Object Name, Version

However, This works best only in the PowerShell 5.1 version.

Get-WmiObject

Another option for querying installed software is to use the Get-WmiObject cmdlet and the Windows Management Instrumentation (WMI) database. WMI stores a wealth of system information, including details on installed programs.

Get-WmiObject -Class Win32_Product | Where-Object {$_.DisplayName -ne $null} | Select-Object Name, Version, Vendor

This will return a list of installed software, including the name, version, and vendor. One thing to keep in mind with querying Win32_Product is that it can be quite slow compared to other methods, as it actually triggers a Windows Installer consistency check each time it’s run.

Get-CimInstance

Another option for querying installed software is to use the Get-CimInstance cmdlet and the Windows Management Instrumentation (WMI) database. WMI stores a wealth of system information, including details on installed programs.

Get-CimInstance -ClassName "Win32_product" | Where-Object {$_.Name -ne $null} | Select-Object Name, Version, Vendor
powershell list all installed software

This will return a list of installed software, including the name, version, and vendor. One thing to keep in mind with querying Win32_Product is that it can be quite slow compared to other methods, as it actually triggers a Windows Installer consistency check each time it’s run.

Query the Windows Event Log for Install Events

Get-WinEvent -ProviderName msiinstaller | where id -eq 1033 | select timecreated,message | FL *

However, you may not have multiple events logged for specific software, and the report may not be complete, as event logs may be cleared!

Check if a specific software is installed using PowerShell

Picture this: you’re a system administrator tasked with ensuring a specific critical software is installed on all the computers in your organization. How do you quickly and efficiently check if a program is installed, especially across multiple machines?

Opening up the Control Panel or Application folder and visually scanning for the software is certainly an option, but it’s time-consuming and impractical, especially if you need to check a large number of computers.

This is where PowerShell comes in. With a few simple commands, you can instantly check whether a specific software is installed on a local or remote machine. PowerShell provides a powerful and flexible way to query the registry, Windows Installer database, or package management tools to determine the presence of an application.

#Function to Check if a software is installed
Function Check-SoftwareInstalled
{
    param(
        [Parameter(Mandatory=$true)] [string]$ApplicationName,
        [Parameter(Mandatory=$true)] [string]$Version,
        [Parameter(Mandatory=$False)] [ValidateSet("32-Bit", "64-bit","Current User")] [string]$Scope =  "32-Bit"
        )

    #Array to collect Installed Software details
    $InstalledSoftware = New-Object System.Collections.ArrayList

    #Get all 32-Bit version of Apps
    $32BitApps = Get-ChildItem "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall" | Get-ItemProperty | Where-Object {$_.DisplayName -ne $null} | Select-Object DisplayName, DisplayVersion
    $32BitApps | ForEach-Object { 
        $InstalledSoftware.Add([PSCustomObject]@{
            ApplicationName     = $_.DisplayName
            Version = if ($null -eq $_.DisplayVersion -or [string]::Empty -eq $_.DisplayVersion) { "N/A" } else { $_.DisplayVersion }
            Scope = "32-Bit"
        }) | Out-Null
    }
 
    #Get 64 bit versions
    $64BitApps = Get-ChildItem "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" | Get-ItemProperty | Where-Object {$_.DisplayName -ne $null} | Select-Object DisplayName, DisplayVersion
    $64BitApps | ForEach-Object { 
       $InstalledSoftware.Add([PSCustomObject]@{
            ApplicationName     = $_.DisplayName
            Version = if ($null -eq $_.DisplayVersion -or [string]::Empty -eq $_.DisplayVersion) { "N/A" } else { $_.DisplayVersion }
            Scope = "64-Bit"
        })| Out-Null
    }
    #Get Software installed in Current user scope
    $CurrentUserApps = Get-ChildItem "HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall" | Get-ItemProperty | Where-Object {$_.DisplayName -ne $null} | Select-Object DisplayName, DisplayVersion
    $CurrentUserApps | ForEach-Object { 
          $InstalledSoftware.Add([PSCustomObject]@{
            ApplicationName     = $_.DisplayName
            Version = if ($null -eq $_.DisplayVersion -or [string]::Empty -eq $_.DisplayVersion) { "N/A" } else { $_.DisplayVersion }
            Scope           = "Current User"
        }) | Out-Null
    }

    #Check if a particular software is installed
    $SoftwareInstalled = $InstalledSoftware | Sort-Object -Property ApplicationName, Version, Scope -Unique | Where {$_.ApplicationName -eq $ApplicationName -and $_.Version -eq $Version -and $_.Scope -eq $Scope}
    If($null -eq $SoftwareInstalled)
    {
        Return $false
    }
    Else
    {
        Return $True
    }
}

#Call the function to check if a particular software is installed.
Check-SoftwareInstalled -ApplicationName "VLC media player" -Version "3.0.20"

This script returns True or False depending on the software installation found on the system.

Remote Computer Software Inventory

All of the above examples work great for getting installed software details from the local computer. But what if you want to inventory software on remote machines? Imagine you want to quickly verify the installation of a specific tool on multiple machines in your network for compliance purposes. Using the scripts above, you can modify them to check for the software’s presence and fetch the necessary details, which can then be logged or reported.

To get a list of installed software on a remote computer, you can use the Invoke-Command cmdlet with the -ComputerName parameter in combination with any of the methods discussed above. Here’s an example script that queries the registry keys on a remote machine:

Invoke-Command -ComputerName "RemoteComputerName" -ScriptBlock { Get-ChildItem "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" |  Get-ItemProperty | Where-Object {$_.DisplayName -ne $null} | Select-Object DisplayName, DisplayVersion, Publisher }

In the above command, the Invoke-Command cmdlet executes the registry query on the remote computer specified by the “ComputerName” parameter. The result is a list of 64-bit versions of installed software names on the remote computer.

Note that querying the registry keys for all users on a remote machine can take some time, especially if the machine has a large number of installed software packages. To improve performance, you can use the -Credential parameter to specify a user account with administrative privileges on the remote machine.

You can also use the Get-WmiObject and other commands:

Invoke-Command -ComputerName SRV1 -ScriptBlock {Get-WmiObject -Class Win32_Product | Select-Object Name, Version, Vendor }

This returns the installed software list. However, This list is incomplete and takes time!

In both cases, we simply specify the target computer name(s) and the PowerShell command will run on the remote system, returning the results to your local console. This makes it easy to centrally gather software inventory details across multiple computers without having to log into each one individually.

Handling Different Software Installation Types

It’s important to note that not all Windows software is installed the same way. Traditional Windows applications use Windows Installer (MSI) and will show up under Win32_Product or the “Uninstall” registry key. However, there are other types of software that may not show up there, such as:

  • Microsoft Store apps
  • Portable or xcopy-deployed applications
  • Self-contained .exe installers
  • Applications installed under a specific user profile rather than system-wide

In these cases, you may need to use additional PowerShell commands or look in other locations to fully inventory the installed software.

For Microsoft Store apps, you can use:

Get-AppxPackage -AllUsers | Select-Object Name, Version, PackageFullName

For portable apps, you’ll generally need to look for executable files or folders in common locations like “Program Files” or “AppData”.

Example:

Get-ChildItem -Path "C:\Program Files" -Recurse -Include *.exe | Select-Object -ExpandProperty VersionInfo | Select-Object ProductName, FileVersion

Saving & Exporting Results

Once you’ve perfected your PowerShell command to get the installed software inventory you need, you’ll likely want to save those results for later analysis or record-keeping. That’s easy to do by piping the output to an Export-Csv cmdlet.

Example:

Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-Object {$_.DisplayName -ne $null} | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Export-Csv -Path C:\Temp\InstalledSoftware.csv -NoTypeInformation

This will export the filtered software list to a CSV file that you can open in Excel. Alternatively, you can save the output directly to a text file using the Out-File cmdlet.

Conclusion

As you can see, PowerShell provides a variety of options for quickly and easily getting a list of installed software, both locally and remotely. You can leverage PowerShell to query the Windows registry, WMI, or package commands, get the software inventory, and integrate it into your overall system management automation.

PowerShell has you covered whether you need to retrieve a list of installed software, check if a specific software is installed, or even perform complex software management tasks. By following the scripts and methods outlined in this guide, you can harness the full power of PowerShell to retrieve software installations on your local or remote computers efficiently.

Salaudeen Rajack

Salaudeen Rajack - Information Technology Expert with Two-decades of hands-on experience, specializing in SharePoint, PowerShell, Microsoft 365, and related products. He has held various positions including SharePoint Architect, Administrator, Developer and consultant, has helped many organizations to implement and optimize SharePoint solutions. Known for his deep technical expertise, He's passionate about sharing the knowledge and insights to help others, through the real-world articles!

Leave a Reply

Your email address will not be published. Required fields are marked *