В этой инструкции мы покажем несколько способов получить список установленных программ в Windows 10, Windows 8 или Windows 7 с помощью командной строки. Эта методика построения списка программ в системе может пригодиться перед переустановкой системы, когда нужно найти нежелательное ПО или при выполнении инвентаризации установленного ПО на компьютерах организации.
Рассмотрим два способа: первый подразумевает использование командной строки и утилиты wmic, второй — PowerShell.
Содержание:
- Вывод списка программ с помощью утилиты командной строки WMIC
- Вывод списка программ через Windows PowerShell
Вывод списка программ с помощью утилиты командной строки WMIC
Список установленных в системе программ может быть получен с помощью утилиты командной строки WMIC, через которую можно обратиться и опросить пространство имен WMI. Запустите командную строку с правами администратора и выполните команду:
wmic product get name,version
После небольшого ожидания, на экран консоли будет выведен список названий и версия установленных в системе программ.
Этот список можно экспортировать в текстовый файл с помощью команды:
wmic product get name,version /format:csv > c:\Temp\Programs_%Computername%.csv
После окончания выполнения команды перейдите в каталог C:\Temp и найдите csv файл, имя которого начинается с Programs_[имя_ПК]. В данном файле в csv-формате помимо названия и версии ПО, также будет содержаться имя ПК (удобно для дальнейшего анализа).
Вывод списка программ через Windows PowerShell
Список установленных программ также может быть получен с помощью PowerShell. Идея метода в том, что список установленных программ, который мы видим в списке Programs and Features Панели Управления, строится на основе данных, хранящихся в ветке реестра HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
Наша задача – вывести содержимое данной ветки реестра. Итак, запустите консоль Powershell и выполните команду:
Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, Publisher, Size, InstallDate | Format-Table -AutoSize
Как вы видите, в результирующем списке содержится имя программы, версия, разработчик и дата установки.
Совет. Для 32-битных приложений на x64 версиях Windows, также нужно брать данные из ветки HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
Экспортировать полученный список в csv файл можно так:
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Format-Table -AutoSize > c:\temp\ installed-software.txt
Рассмотренный выше способ позволяет вывести данные только о классический Windows приложениях. Чтобы вывести список установленных Metro приложений, воспользуйтесь командой:
Get-AppxPackage | Select Name, PackageFullName |Format-Table -AutoSize > c:\temp\installed_metro_apps.txt
Чтобы получить список установленного ПО на удаленном компьютере (к примеру, с именем wks_name11), воспользуемся командлетом Invoke-command:
Invoke-command -computer wks_name11 {Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Format-Table -AutoSize }
Чтобы сравнить списки установленного ПО, полученные с двух разных компьютеров и найти отсутствующие приложения, можно воспользоваться такой командой:
Compare-Object –ReferenceObject (Get-Content C:\temp\installed-software.txt) –DifferenceObject (Get-Content C:\temp\installed-software2.txt)
В нашем примере в двух сравниваемых списках имеются различия в двух программах.
Другой способ вывести список установленных программ – воспользоваться командлетом Get-WmiObject, также позволяющего обращаться с пространству WMI:
Get-WmiObject -Class Win32_Product | Select-Object -Property Name
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 seen 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.
- PowerShell: Check installed software list locally
- Get installed software list with Get-WmiObject
- Query registry for installed software
- Getting the list of recently installed software from the Event Log
- PowerShell: Get a list of installed software remotely
- Get installed software list with remote Get-WmiObject command
- Check installed software with remote registry query
- Check recently installed software list from the Event Log remotely
- Check if a GPO-deployed software was applied successfully
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: 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_ProductAlso, 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, VersionThis method is quite easy. However, it has the downside that it takes quite a while to return the results.
2. 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')}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')}3. Getting the list of recently installed software from the Event Log
In order to check only the 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 *PowerShell: Get a list of installed software remotely
It is possible to remotely find the list of installed software on other machines. For that, we need to create a list of all the computer names in the network. Here are the different methods that we can use within a Foreach loop to return results from more than a single remote PC.
$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. Get installed software list with 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,VersionHere, $pcname is the computer’s name we want to query.
2. Check installed software with 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 | FT3. Check recently installed software list from the 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 *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"Finally, we look for the GPO name and check if it is present under Applied GPOs or Denied GPOs.
[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.
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
var google_conversion_label = «owonCMyG5nEQ0aD71QM»;
Recently, one of my clients asked me for a script to get the list of installed programs in their system. In this tutorial, I will explain how to get a list of all the software programs installed on your Windows computer using PowerShell. PowerShell provides a fast and efficient way to get this information, both locally and remotely.
While you can always manually check installed programs through the Control Panel or by browsing disk partitions, this becomes tedious and time-consuming when you need to audit multiple computers. PowerShell allows you to automate the process and quickly get a report of all the software installed on a system, including useful details like the version numbers.
There are several different PowerShell techniques for getting a list of installed software on Windows 10 and Windows Server systems. Let’s walk through some of the most common and useful methods.
1. Using the Get-ItemProperty Cmdlet
One of the easiest ways to list installed programs with PowerShell is using the Get-ItemProperty cmdlet to retrieve registry keys where information about installed software is stored. The registry paths we’ll query are:
HKLM:\Software\Microsoft\Windows\CurrentVersion\UninstallHKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
The second path is for 32-bit programs installed on 64-bit systems.
Here’s an example command to get all installed software and display the name, version, and install date:
Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, InstallDate
And here’s what the output looks like:
DisplayName DisplayVersion InstallDate
----------- -------------- -----------
7-Zip 24.05 (x64) 24.05
Duet Display 2.5.8.1
HP Documentation 1.0.0.1
Microsoft Visual Studio 2010 Tools for Office Runtime (x64) 10.0.60910
Mozilla Firefox (x64 en-US) 132.0.2
Mozilla Maintenance Service 112.0.2
Microsoft 365 - en-us 16.0.18227.20046
Microsoft 365 Apps for enterprise - en-us 16.0.18227.20046
Microsoft OneNote - en-us 16.0.18227.20046
VLC media player 3.0.20
I executed the above command in my local system, and you can see the exact output in the screenshot below:
You can further refine this by filtering, sorting, and exporting the results. For instance, to export to a CSV file:
Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |
Select-Object DisplayName, DisplayVersion, InstallDate |
Where-Object {$_.DisplayName -ne $null} |
Sort-Object DisplayName |
Export-CSV C:\InstalledSoftware.csv -NoTypeInformation
This filters out any entries missing a DisplayName, sorts alphabetically by the name, and exports the list to C:\InstalledSoftware.csv.
Check out List USB Devices Using PowerShell
2. Using Get-WmiObject
Get-WmiObject is a cmdlet available in Windows PowerShell that allows you to query WMI classes. Although it is somewhat older and less efficient compared to Get-CimInstance, it is still widely used. We can still use Get-WmiObject to get all the installed programs.
Let me show you an example and the complete script.
Here’s a script that uses Get-WmiObject to list installed programs:
# Query the Win32_Product WMI class
$installedPrograms = Get-WmiObject -Class Win32_Product | Select-Object -Property Name, Version, Vendor
# Display the results
$installedPrograms | Format-Table -AutoSize
Explanation
Get-WmiObject -Class Win32_Product: This command queries theWin32_ProductWMI class, which contains information about installed software.Select-Object -Property Name, Version, Vendor: This filters the output to display only theName,Version, andVendorproperties.Format-Table -AutoSize: This formats the output in a table for better readability.
Here is the exact output you can see in the screenshot below:
Read List Local Administrators Using PowerShell
3. Using Get-CimInstance
Get-CimInstance is a more modern cmdlet that provides similar functionality to Get-WmiObject but with improved performance and compatibility. It uses the CIM (Common Information Model) standard and is recommended for use in newer scripts.
Now, let me show you an example of how to use the Get-CimInstance cmdlet to get all the installed programs from the system.
Here’s a script that uses Get-CimInstance to list installed programs:
# Query the Win32_Product CIM class
$installedPrograms = Get-CimInstance -ClassName Win32_Product | Select-Object -Property Name, Version, Vendor
# Display the results
$installedPrograms | Format-Table -AutoSize
Explanation:
Get-CimInstance -ClassName Win32_Product: This command queries theWin32_ProductCIM class.Select-Object -Property Name, Version, Vendor: This filters the output to display only theName,Version, andVendorproperties.Format-Table -AutoSize: This formats the output in a table for better readability.
Check out List All Environment Variables in PowerShell
4. Querying the Registry
Windows stores information about installed programs in the registry. By querying specific registry paths, you can retrieve detailed information about installed software.
Let me show you an example.
Example:
$registryPaths = @(
"HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall",
"HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
)
foreach ($path in $registryPaths) {
Get-ItemProperty -Path $path\* | Select-Object DisplayName, DisplayVersion, Publisher
}
This script iterates through two registry paths to find both 32-bit and 64-bit installed programs. It then selects and displays the program name, version, and publisher.
Here is the exact output in the screenshot below:
Read How to Set Proxy in PowerShell?
5. Using Get-Package
PowerShell’s Get-Package cmdlet is another powerful cmdlet that lists installed software, especially if you are using newer versions of PowerShell (5.0 and above).
Example:
Get-Package | Select-Object -Property Name, Version, ProviderName
This command lists all installed packages, including those installed via package managers like Chocolatey or NuGet. It selects and displays the package name, version, and provider.
To ensure you capture all installed programs, you can combine the methods above into a single script. This approach helps cover any gaps that a single method might miss.
Here is the complete PowerShell script.
# Define registry paths
$registryPaths = @(
"HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall",
"HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
)
# Get installed programs from registry
$installedPrograms = foreach ($path in $registryPaths) {
Get-ItemProperty -Path $path\* | Select-Object DisplayName, DisplayVersion, Publisher
}
# Get installed programs using Get-WmiObject
$installedPrograms += Get-WmiObject -Class Win32_Product | Select-Object -Property Name, Version, Vendor
# Get installed packages using Get-Package
$installedPrograms += Get-Package | Select-Object -Property Name, Version, ProviderName
# Remove duplicates and display results
$installedPrograms | Sort-Object -Property Name -Unique | Format-Table -AutoSize
This script aggregates results from the registry, WMI, and package managers, removes duplicates, and displays the final list in a table format.
Read Get HP Laptop Model and Serial Number Using PowerShell
Filter and Export Installed Programs List
You may want to filter the list of installed programs or export the results for further analysis. Let me show you how to do it.
Filtering Results
To filter the list of installed programs, use the Where-Object cmdlet like the below:
$installedPrograms | Where-Object { $_.Name -like "*Microsoft*" } | Format-Table -AutoSize
This command filters the list to display only programs with “Microsoft” in their name.
Exporting Results
To export the list of installed programs to a CSV file, use the Export-Csv cmdlet.
Here is the complete script.
$installedPrograms | Export-Csv -Path "C:\InstalledPrograms.csv" -NoTypeInformation
This command exports the list to a CSV file located at C:\InstalledPrograms.csv.
Summary
In this tutorial, I explained multiple techniques for using PowerShell to get a list of programs installed on Windows computers, such as:
- Using the Get-ItemProperty Cmdlet
- Using Get-WmiObject
- Using Get-CimInstance
- Querying the Registry
- Using Get-Package
You may also like:
- Get the Windows Version Using PowerShell
Bijay Kumar is an esteemed author and the mind behind PowerShellFAQs.com, where he shares his extensive knowledge and expertise in PowerShell, with a particular focus on SharePoint projects. Recognized for his contributions to the tech community, Bijay has been honored with the prestigious Microsoft MVP award. With over 15 years of experience in the software industry, he has a rich professional background, having worked with industry giants such as HP and TCS. His insights and guidance have made him a respected figure in the world of software development and administration. Read more.
To retrieve a list of installed software on a Windows machine using PowerShell, you can use the following command:
Get-WmiObject -Class Win32_Product | Select-Object -Property Name, Version
Understanding PowerShell Commands
What is PowerShell?
PowerShell is a task automation and configuration management framework developed by Microsoft. It combines a command-line shell with an associated scripting language, which makes it an incredibly powerful tool for IT professionals and system administrators. Unlike traditional command-line interfaces, PowerShell enables users to work with objects rather than text, allowing for more complex and nuanced scripting capabilities that can greatly enhance productivity in a Windows environment.
PowerShell vs. Traditional Methods
When it comes to managing installed software, many users may instinctively turn to graphical user interfaces (GUIs). While GUIs can be user-friendly, they often become cumbersome when dealing with a large number of applications or for automating tasks. In contrast, PowerShell provides several advantages:
- Speed: Quickly executing commands saves time, especially in bulk operations.
- Automation: Scripts can automate repetitive tasks, reducing the risk of human error.
- Flexibility: Easy to filter or manipulate data with robust command options.
By utilizing PowerShell, you can efficiently manage and query installed software in a way that’s both effective and user-friendly.
PowerShell Get Installed Apps: Quick Command Guide
Getting Started with Installed Software Queries in PowerShell
How to Open PowerShell
Before diving into commands, it’s essential to know how to access PowerShell:
- Windows 10 and 11: Right-click the Start button and select «Windows PowerShell» or «Windows Terminal.»
- Windows 8 and Earlier: Press `Windows + X` and select «Windows PowerShell.»
It’s often beneficial to run PowerShell in administrator mode, which gives you the required permissions to query system-level information. Right-click on the icon and select «Run as administrator.»
PowerShell Remotely Uninstall Software Made Easy
Basic Command to List Installed Software
One of the simplest methods to list installed software is through the `Get-WmiObject` cmdlet. This cmdlet retrieves instances of Windows Management Instrumentation (WMI) classes, specifically the `Win32_Product` class, which represents applications installed using Windows Installer.
Execute the following command to see a basic list of installed software:
Get-WmiObject -Class Win32_Product
This command will display a comprehensive list of installed applications, including details such as the name and version of each software.
Filtering Installed Software Results
Using `Where-Object` to Filter Software
Sometimes, you may want to find specific software from the list. By using the `Where-Object` cmdlet, you can filter results based on various properties. For instance, if you’re looking for Adobe products, you’ll use:
Get-WmiObject -Class Win32_Product | Where-Object { $_.Name -like "*Adobe*" }
In this example, `Where-Object` filters the output so you only see applications that contain «Adobe» in their name. This method can be customized according to your needs, making it easy to find specific installed software.
Displaying Installed Software in a User-Friendly Format
Formatting Output with `Format-Table`
A long list of software can be overwhelming. To improve readability, you can format the output using the `Format-Table` cmdlet. Here’s how you can display just the name and version:
Get-WmiObject -Class Win32_Product | Format-Table Name, Version
This command outputs the name and version of each installed program in a neatly organized table, making it easier to identify installed software at a glance.
PowerShell Script to Install Software Made Easy
Advanced Techniques to Find Installed Software
Using `Get-Package` for More Options
The `Get-Package` cmdlet provides an alternative method to list installed software, showcasing supported package providers. This can include applications installed via Windows Installer, Store apps, or other package management systems. To execute this, simply run:
Get-Package
This command delivers a broader view of installed software, including non-WMI managed applications, ensuring no critical software is overlooked in your assessments.
Querying the Registry for Installed Software
Accessing the Registry with PowerShell
The Windows Registry is another essential resource for identifying installed applications. To retrieve a list of installed software from the registry, you can use the `Get-ItemProperty` cmdlet. Here’s a sample command to get you started:
Get-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*" | Select-Object DisplayName, DisplayVersion
This command queries the `Uninstall` registry key for details on installed applications, including their display names and versions. It’s critical for retrieving applications not registered via Windows Installer.
Exporting Installed Software List to a CSV File
If you need to document your findings or share them with others, you can export the list of installed software to a CSV file for easy access and analysis. Utilize the `Export-Csv` cmdlet like this:
Get-WmiObject -Class Win32_Product | Select-Object Name, Version | Export-Csv -Path "InstalledSoftware.csv" -NoTypeInformation
This command gathers the installed software’s names and versions, then creates a CSV file named `InstalledSoftware.csv` in the current directory. The `-NoTypeInformation` parameter omits unnecessary type information from the output, keeping the file clean and straightforward.
PowerShell 7 Installation: A Quick Start Guide
Conclusion
Mastering the ability to use PowerShell to get installed software is essential for effective system administration. It helps you quickly gather critical information, automate processes, and manage installed applications efficiently. The commands and techniques discussed in this article offer a solid foundation for working with installed software in PowerShell, empowering you to become more adept at managing your Windows environment.
Additional Resources
For those looking to expand their knowledge further, consider exploring official Microsoft documentation, online courses, or community forums dedicated to PowerShell. The PowerShell community is incredibly active and can provide additional insights and support as you continue your learning journey.
FAQs about PowerShell and Installed Software
As you delve deeper into PowerShell, you might encounter common questions about specific commands or parameters. Always feel free to ask within the community or consult documentation for a more comprehensive understanding of usage scenarios.
Sadly, “what is on this computer?” isn’t the simple question it seems to be. Discovering what has been installed and what patches have been applied can be found in multiple ways — they overlap but on their own none provides a complete least of original installations + patches.
The way NOT to do it
One method I have used, and still see recommended is to use Get-CimInstance Win32_Product.
Don’t
It is slow, but that is a symptom rather than the real reason to avoid it- it does a consistency check of all installed software, which is slow and can change it! There is more detail here. If this method gave a full list, maybe we could forgive it, but it doesn’t.
The commonly recommended way
A better way, and one which finds things others don’t, is to check the uninstall areas of the registry. There are two system ones, and potentially 2 more for each user, the link I just gave has a script to check users other than the current one. I’ve used variations of the following code to check for some years now — I don’t know the original source:
@('HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKCU:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*') | where {Test-path $_} |
Get-ItemProperty | Where-Object {$_.DisplayName -and -not $_.SystemComponent} |
Sort-Object DisplayName |
Select-Object -Property @{n='Name'; e='DisplayName' },
@{n='Version'; e='DisplayVersion'}, "Publisher",
@{n='ID'; e='PSChildName' }
There are four branches, 64-bit and 32-bit in both HKey_CurrentUser, and in HKey_LocalMachine.
Some 64-bit programs are installed by a 32-bit installer (and I guess the reverse is possible), and
these are listed in the 32-bit branch of the registry — WOW6432.
I don’t have any 32-bit “user installations” and the Test-Path avoids an error.
There are some stub entries which don’t give helpful information, and the where in the code above
filters those out, together with items which are flagged as components that are installed as part of something else.
Other properties are left to the publisher, “Version” is missing from a few, “Size” from more, and
install dates — where present — are a mixture of yyyyMMdd and 3/31/2022 US format.
This source replicates the list shown in Control Panel -it’s good but it is not complete,
it has some drivers but not all of them, none of the Windows store apps appear here, and we don’t see updates and hotfixes.
Winging it with wing-et
(Side note — the & character is the letters E and t combined so I’m tempted to write it as Wing-& )
WingEt is a relatively new package manager for Windows, with a frankly dreadful command line app,
(written in C++ for that authentic 1980s feel). It needs to run in a elevated session even when not
making changes (a side effect of its poor design.) It can get a very similar list to the one just
described, with a bonus that software distributed through the winge-t repository is called out and
where newer versions are available they are highlighted. Sorting the output was too much trouble
for the team that wrote it, and because it doesn’t output objects, parsing the output to sort in
PowerShell is your problem*. It truncates names and IDs when printing, so even if you get
something that you can sort, some data will be broken. But if you’re using it, it’s another way
to get a partial listing.
Filling in missing apps
Windows store applications can be checked with :
Get-AppxPackage -AllUsers | Sort-Object Name ,Version |
Select-Object Name, Version, Publisher, NonRemovable, SignatureKind | Format-Table
Some apps are signed by the store rather than by the developer, and these will have a GUID for
the publisher; for dev-signed apps the publisher is a distinguished name — which I’d assume is
the one on the cert that signed the app.
The names here can be quite cryptic: for example, I had “Age of Empires” installed which has a
name of Microsoft.MSPhoenix. Each app has a manifest file and in some cases this holds
the app’s and publisher’s display names as literal text, in others it looks like a link to a
resource in one of the app’s binary files. The list from the previous code fragment can be improved
by filling in names where they can be found in the manifests, and using parts of the existing
attributes where the manifest doesn’t help.
Filtering out items which have “IsFramework” or “NonRemovable” flags set gives a list which is
more like the apps we see installed. There is a Get-AppxPackageManifest command but it doesn’t
work with this script, so I cheat and read the manifest XML directly.
Get-AppxPackage -AllUsers | where {-not ($_.IsFramework -or $_.NonRemovable)} |
Select-Object Name, Version, InstallLocation, Publisher, NonRemovable, IsBundle, IsFramework -Unique | ForEach-Object {
$props = ([xml](Get-Content (Join-path $_.InstallLocation "Appxmanifest.xml"))).Package.Properties
if ($Props.DisplayName -notlike 'ms-resource*') {
Add-Member -InputObject $_ -NotePropertyName DisplayName -NotePropertyValue $props.DisplayName
}
else { Add-Member -InputObject $_ -NotePropertyName Displayname -NotePropertyValue ($_.name -replace "^.*?\.","")}
if ($Props.PublisherDisplayname -notlike 'ms-resource*') {
Add-Member -InputObject $_ -NotePropertyName Pub -NotePropertyValue $props.PublisherDisplayname -PassThru
}
else { Add-Member -InputObject $_ -NotePropertyName Pub -NotePropertyValue ($_.publisher -replace '^cn=(.*?),.*$','$1') -PassThru}
} | Sort-Object DisplayName |
select-Object @{n='Name';e='DisplayName'}, Version, @{n='Publisher';e='Pub'}
These packages record their dependencies, and we see can which items are used most — some of them will have “NonRemovable” or “IsFrameWork” set so won’t show up in the previous list.
$packNameToId = @{}
Get-AppxPackage | ForEach-Object {
$packNameToId[$_.PackageFullName] = $_.Name
foreach ($d in ($_.Dependencies| Sort-Object -Unique)) {[PSCustomObject]@{"Name"=$_.PackageFullName; DependsOn=$d}}
} | Group-Object Dependson -NoElement | Sort-Object Count |
Select-Object -Property Count, @{n='shortname'; e={$packNameToId[$_.name] }} | where-object shortname
Get-AppxPackage returns a list which is a mixture of apps added by users and apps that Windows pre-installs, but it is not the complete list because some apps are staged on the computer: a store app may be installed for the user (e.g. “Age Of Empires” downloaded from the store), Staged and installed (e.g. “Microsoft.Paint”), Staged but either never installed or uninstalled (e.g. “Microsoft.YourPhone”) or staged with a different version installed.
Get-AppxProvisionedPackage -Online | Sort DisplayName, Version |
Select-Object @{n="Name";e="DisplayName"},Version,PublisherId
Using the manifest to translate names is only slightly different for provisioned packages, and again not all packages have the name as simple text, instead of a distinguished name, there is a cryptic ID for each publisher, but it does show us that when we see “8wekyb3d8bbwe” attached to a name means “published by Microsoft”.
Get-AppxProvisionedPackage -Online |
Select-Object @{n='Name';e='DisplayName'}, Version, InstallLocation, PublisherID -Unique | ForEach-Object {
$props = ([xml](Get-Content ($_.InstallLocation -replace "%SystemDrive%", $env:SystemDrive ) )).Package.Properties
if ($Props.DisplayName -and $Props.DisplayName -notlike 'ms-resource*') {
Add-Member -InputObject $_ -NotePropertyName Displayname -NotePropertyValue $props.DisplayName
}
else { Add-Member -InputObject $_ -NotePropertyName Displayname -NotePropertyValue ($_.name -replace "^.*?\.","")}
if ($Props.PublisherDisplayname -and $Props.PublisherDisplayname -notlike 'ms-resource*') {
Add-Member -InputObject $_ -NotePropertyName PublisherDisplayname -NotePropertyValue $props.PublisherDisplayname -PassThru
}
else { Add-Member -InputObject $_ -NotePropertyName PublisherDisplayname -NotePropertyValue $_.PublisherID -PassThru}
} | Sort-Object DisplayName | ft @{n='Name';e='DisplayName'}, Version, @{n='Publisher';e='PublisherDisplayName'},InstallLocation
Updates
There’s more! In Windows PowerShell 5 you can get installed software using the Get-Package cmdlet and specify either the Programs or MSI providers — combined these give you the same as the registry query above. However there is also an MSU provider for updates. This includes hotfixes (of which more in a moment), drivers and a some other components of interest. The MSU provider was not been ported to PowerShell 6 and 7, but we can get the same effect like this.
$updateSession = New-Object -ComObject Microsoft.Update.Session
$updateSearcher = $updateSession.CreateUpdateSearcher()
$updates = $updateSearcher.QueryHistory(1, $updateSearcher.GetTotalHistoryCount() ) |
Where-Object ResultCode -eq 2 | Select-object @{n="Name"; e="Title"},
@{n='KB'; e={if ($_.Title -match '(KB\d{5,})') {$matches[1]} }},
@{n='Version'; e={if ($_.Title -match '(-\s+v?|version\s+)(\d+(\.\d+)+)') {$matches[2]} }},
Date, Description |
Sort-Object @{e={$_.kb -as [boolean]}}, title,version
$updates | ft -a
Above shows the first entries returned which includes drivers, and below are later entries showing KB items.
The KB numbers for hotfixes, and the version numbers for other things are embedded in the title, so the code above extracts those. The update process tags each update with a result-code: 0 for not started, 1 for running, 2 for succeeded, 3 for succeeded with errors, 4 for failed, 5 for aborted, and the where in the code above filters to only successes. On my machine which I’d had about a month when I wrote this, I can check how many KBs have been installed with
$updates.kb | Sort-Object -Unique | measure
— it was 17 at that point, rather higher now.
There is a Get-Hotfix command in PowerShell, which is really just calling Get-CimInstance win32_QuickFixEngineering but on my machine it only returns 4 items
$kbs = $updates.kb | Sort-Object -Unique
Get-CimInstance Win32_QuickFixEngineering | Where-Object HotFixID -NotIn $kbs
Of the four only one is an extra, the other three are in the updates query, so I’m not sure this is is a useful test.
And the list of drivers found by checking updates is long, yet incomplete: Get-WindowsDriver returns a more complete list and with a little processing it can look like the values returned as updates.
Get-WindowsDriver -Online |
select-Object @{n='Name';e={$_.ProviderName + " - " + $_.ClassName + " - " + $_.version}}, Version,
@{n='Description';e={"{0} {1} driver update released in {2:MMMM yyyy}" -f $_.providerName, $_.ClassName,$_.Date}}
Get-WindowsDriver -Online | Sort-Object -Unique ProviderName, ClassName, Date, OriginalFileName |
Format-Table -Autosize ProviderName, ClassName, Version, Date, @{n='File';e={Split-Path -leaf $_.OriginalFileName }}
All the above have been designed to produce similar enough output that I can pull them into a single spreadsheet and have something that is easy to de-duplicate. My month-old system already had 373 rows and you’d think that was all. But it doesn’t cover PowerShell modules.
Get-Package -ProviderName PowerShellGet
Will get a list of PowerShell modules, run in PowerShell 7 it lists only the modules installed in 7, so if some were installed from Windows PowerShell, the command needs to be run in both versions. Other products will have ways of installing scripts/macros/templates/presets and so on, and I’m not looking here at things installed into the Windows-Subsystem for Linux.
But wait — there’s no Quick Assist, no SSH client, no WordPad (has anyone used WordPad in the last 20 years?) — these have their own page in settings. And they are found with Get-WindowsCapability each name ends with “~~~~0.0.1.0” so the code below reduces it to just the name. Most of the items returned are recognizable as items on that page in settings, but there are some extra network components which the UI doesn’t show.
Get-WindowsCapability -Online | Where-Object state -eq installed |
ForEach-Object {$_.name -replace '~.*$',''} | Sort-Object -Unique
At one time these components were accessed through the Optional features part of control panel, rather than via the settings app. Whether that’s installation or Windows configuration I’m not sure, but for completeness the list of items which still use the control panel method can be found with
Get-WindowsOptionalFeature -Online | where-object state -eq enabled | sort-object FeatureName |ft
These last two add 79 more items on my machine.
* The Crescendo toolkit for making PowerShell interfaces into legacy commands was meant for this and there is a module named (Cobalt)[https://www.powershellgallery.com/packages/Cobalt] built with it for winget. And I do know it is meant to be Win Get 
