Bobcares

Use PowerShell to find list of installed software quickly

In certain situations, we may need to check the list of installed software and its version and for this, we can make use of PowerShell.

Here at Bobcares, we have encountered several such PowerShell-related queries as part of our Server Management Services for web hosts and online service providers.

Use PowerShell to find list of installed software quickly

Today, we’ll take a look at how to get the list of all installed software using PowerShell.

Why Use PowerShell to Check Installed Software?

If you are on the fence about using PowerShell when you can just check Programs and Features in the Control Panel, here are some compelling reasons:

  • Speed: One-line commands can instantly generate detailed software inventories.
  • Automation: Easily integrate checks into larger scripts and scheduled jobs.
  • Remote Management: PowerShell lets us query software on remote machines.
  • Filtering & Reporting: Filter by vendor, version, or date, and export results to CSV, text, or databases.

 

PowerShell is also useful when performing other automated admin tasks, such as disabling password expiration policies or configuring firewall settings.

PowerShell: Check installed software list locally

Now let’s see how our Support Engineers list the installed software locally.

Generally, we make use of Programs and Features in the Control Panel. Or browse all disk partitions in search of a specific app.

Checking the installed software versions by using PowerShell allows gathering data that we need much quicker.

 

1. Get installed software list with Get-WmiObject

In this method, we simply paste a simple query:

Get-WmiObject -Class Win32_ProductCopy Code

Also, we can filter the data to find specific applications from a single vendor, together with their versions, for example:

Get-WmiObject -Class Win32_Product | where vendor -eq CodeTwo | select Name, VersionCopy Code

This method is quite easy. However, the downside is that returning the results takes quite a while.
Alternatively, we can query installed software with the Get-WmiObject cmdlet and the Windows Management Instrumentation (WMI) database. WMI has a wealth of system information, including details on installed programs.

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

This command filters out entries without a display name and lists the Name, Version, and Vendor of the remaining items. Our Experts would like to point out that querying Win32_Product can be quite slow compared to other methods, as it triggers a Windows Installer consistency check each time it’s run.

If you encounter issues while running such commands, you might find our PowerShell error clearing guide helpful.

2. Via Get-CimInstance

Another option for querying installed software is to use the Get-CimInstance cmdlet along with the WMI database. WMI stores a vast amount of system information, including details about software installed via MSI.

Get-CimInstance -ClassName "Win32_product" | Where-Object {$_.Name -ne $null} | Select-Object Name, Version, VendorCopy Code

This command retrieves a list of installed MSI-based software and displays the Name, Version, and Vendor for each entry.

3. Via Get-ItemProperty Or Get-ChildItem cmdlets

One of the simplest and safest ways to retrieve a list of installed programs on a local Windows machine is by querying the Windows Registry using the Get-ItemProperty or Get-ChildItem cmdlets. These methods avoid the side effects associated with querying the Win32_Product WMI class.

  • For 64-bit system-wide installations:
    Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |
    Where-Object {$_.DisplayName -ne $null} |
    Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Format-Table -AutoSize
    Copy Code
  • For 32-bit applications on a 64-bit system:
    Get-ChildItem "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" |
    Get-ItemProperty |
    Where-Object {$_.DisplayName -ne $null} |
    Select-Object DisplayName, DisplayVersion, Publisher, InstallDate
    Copy Code
  • For applications installed for the current user:
    Get-ChildItem "HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall" |
    Get-ItemProperty |
    Where-Object {$_.DisplayName -ne $null} |
    Select-Object DisplayName, DisplayVersion, Publisher, InstallDate
    Copy Code

These registry-based queries offer a fast way to gather software inventory information and are suitable for scripts and system audits.

You can also combine all three methods to generate a comprehensive CSV report of the installed software on the system, as seen below:

#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\InstalledSoftwareList.csv"
Copy Code

This PowerShell script collects installed software details from three registry locations- 32-bit system-wide apps, 64-bit system-wide apps, and Current user-specific apps.

It gathers the Name, Version, Publisher, and Install Date for each application and labels the Scope (32-Bit, 64-Bit, or Current User).

It then compiles all results into a single list and exports it to a CSV file at C:\Temp\InstalledSoftwareList .csv

The missing values are replaced with `N/A` for consistency.

You can also integrate this into broader PowerShell scripts — for example, when resetting IIS across multiple servers.

4. Use Get-Package to List Installed Software

If we are running PowerShell 5.1, we can use the Get-Package cmdlet to retrieve details about installed programs. Unlike registry-based methods, this queries the PackageManagement database.

Get-Package | Select-Object Name, Version, Source, ProviderNameCopy Code

This command returns a concise table showing each package’s name, version, source, and provider. One key advantage of Get-Package is that it includes traditional Windows applications and packages installed via PackageManagement.

To narrow down the results to specific types of packages, we can use the -ProviderName parameter. For example, to list only MSI-based installations:

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

This method is most reliable in PowerShell 5.1 and may not work consistently in newer versions.

5. Query registry for installed software

Another method is querying the registry to get the list of installed software. Here is a short script that returns the list of applications together with their versions:

$InstalledSoftware = Get-ChildItem "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall"
foreach($obj in $InstalledSoftware){write-host $obj.GetValue('DisplayName') -NoNewline; write-host " - " -NoNewline; write-host $obj.GetValue('DisplayVersion')}Copy Code

In short, the above command will list all the software installed on the LM – local machine. However, applications can be installed per user as well. So, to return a list of applications of the currently logged user, we change HKLM to HKCU (CU stands for “current user”):

$InstalledSoftware = Get-ChildItem "HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall"
foreach($obj in $InstalledSoftware){write-host $obj.GetValue('DisplayName') -NoNewline; write-host " - " -NoNewline; write-host $obj.GetValue('DisplayVersion')}Copy Code

 

6. Via the Event Log

To check only recently installed software, we use the following cmdlet to search through the Event Log.

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

This can be useful after deployments or changes in system configuration, such as configuring firewall rules with PowerShell.

PowerShell: Get a list of installed software remotely

Finding the list of installed software on other machines remotely is also possible. For that, we need to create a list of all the computer names in the network. Here are the different methods we can use within a Foreach loop to return results from multiple remote PCs.

$pcname in each script stands for the remote computer’s name on which we want to get a list of installed software and their versions.

 

1. Via remote Get-WmiObject command

The below cmdlet is the easiest one, but can take some time to finish:

Get-WmiObject Win32_Product -ComputerName $pcname | select Name,VersionCopy Code

Here, $pcname is the computer’s name we want to query.

 

2. Via remote registry query

Remote registry queries are slightly more complicated and require the Remote Registry service to be running. A sample query is as follows:

$list=@()
$InstalledSoftwareKey="SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
$InstalledSoftware=[microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$pcname)
$RegistryKey=$InstalledSoftware.OpenSubKey($InstalledSoftwareKey)
$SubKeys=$RegistryKey.GetSubKeyNames()
Foreach ($key in $SubKeys){
$thisKey=$InstalledSoftwareKey+"\\"+$key
$thisSubKey=$InstalledSoftware.OpenSubKey($thisKey)
$obj = New-Object PSObject
$obj | Add-Member -MemberType NoteProperty -Name "ComputerName" -Value $pcname
$obj | Add-Member -MemberType NoteProperty -Name "DisplayName" -Value $($thisSubKey.GetValue("DisplayName"))
$obj | Add-Member -MemberType NoteProperty -Name "DisplayVersion" -Value $($thisSubKey.GetValue("DisplayVersion"))
$list += $obj
}
$list | where { $_.DisplayName } | select ComputerName, DisplayName, DisplayVersion | FTCopy Code

 

3. Via Event Log remotely

We can check a user’s event log remotely by adding a single attribute (-ComputerName) to the cmdlet used before:

Get-WinEvent -ComputerName $pcname -ProviderName msiinstaller | where id -eq 1033 | select timecreated,message | FL *Copy Code

 

Check if a GPO-deployed software was applied successfully

If we apply a certain software version via GPO, then we can easily check if this GPO was successfully applied to a user or not. Also, all we need is the GPResult tool and the names of the target computer and user:

gpresult /s "PCNAME" /USER "Username" /h "Target location of the
HTML report"Copy Code

Finally, we look for the GPO name and check if it is present under Applied GPOs or Denied GPOs.

FAQs

Q. How can I list installed PowerShell modules?

We can use the Get-InstalledModule cmdlet to retrieve modules installed via PowerShellGet. To view all modules available on the system, run “Get-Module -ListAvailable”.

Q. How do I list installed packages in PowerShell?

We can use the Get-Package cmdlet to list all software packages installed using PackageManagement.
Furthermore,we can use this cmdlet remotely via Invoke-Command or Enter-PSSession.

Q. How can I view installed services in PowerShell?

To list all services on the system run Get-Service. This command displays both the service name and the display name. It focuses on system services and excludes drivers.

Q. How do I list files in a folder using PowerShell?

We can use the Get-ChildItem cmdlet to list files in a directory. This will return only the files in the specified folder, excluding subdirectories.

[Need any further assistance with PowerShell queries? – We are here to help you.]

 

Conclusion

Today, we saw how our Support Engineers get the list of all installed software using PowerShell.

var google_conversion_label = "owonCMyG5nEQ0aD71QM";

PREVENT YOUR SERVER FROM CRASHING!

Never again lose customers to poor server speed! Let us help you.

Our server experts will monitor & maintain your server 24/7 so that it remains lightning fast and secure.

GET STARTED

6 Comments
  1. Broc

    Nice one Gayathri, thanks

    Reply
  2. Milind

    Hi,

    I am looking for script which can be run on any server or desktop to know the number of Windows application installed on different VMware virtual desktop and servers.

    Reply
    • Hiba Razak

      Hi,
      Please contact our support through live chat(click on the icon at right-bottom).

      Reply
  3. dp

    Never use “Get-WmiObject -Class Win32_Product” unless you want to update your resume
    This causes software to re-initialize

    Use “Get-Package” instead

    Reply
  4. BSB

    This seems to work well, but it doesn’t appear to grab every application. For instance, when I run this I don’t see Firefox or Notepad++ listed. Are there limitations to this command?

    Reply
    • Hiba Razak

      Hi,
      Please contact our support team through live chat (click on the icon at right-bottom).

      Reply

Submit a Comment

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

Speed issues driving customers away?
We’ve got your back!