This uses Microsoft.Win32.RegistryKey to check the SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall registry key on remote computers.
https://github.com/gangstanthony/PowerShell/blob/master/Get-InstalledApps.ps1
*edit: pasting code for reference
function Get-InstalledApps {
param (
[Parameter(ValueFromPipeline=$true)]
[string[]]$ComputerName = $env:COMPUTERNAME,
[string]$NameRegex = ''
)
foreach ($comp in $ComputerName) {
$keys = '','\Wow6432Node'
foreach (
keys) {
try {
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $comp)
$apps = $reg.OpenSubKey("SOFTWARE$key\Microsoft\Windows\CurrentVersion\Uninstall").GetSubKeyNames()
} catch {
continue
}
foreach (
apps) {
$program = $reg.OpenSubKey("SOFTWARE$key\Microsoft\Windows\CurrentVersion\Uninstall\$app")
$name = $program.GetValue('DisplayName')
if ($name -and $name -match $NameRegex) {
[pscustomobject]@{
ComputerName = $comp
DisplayName = $name
DisplayVersion = $program.GetValue('DisplayVersion')
Publisher = $program.GetValue('Publisher')
InstallDate = $program.GetValue('InstallDate')
UninstallString = $program.GetValue('UninstallString')
Bits =
key -eq '\Wow6432Node') {'64'} else {'32'})
Path = $program.name
}
}
}
}
}
}
Answer from Anthony Stringer on Stack OverflowSoftware List - Inventory -WMIC Product
Search WMIC for installed software - AutoIt General Help and Support - AutoIt Forums
How to get a list of software installed on remote computers
windows - WMI: Get the list of Installed Softwares - Stack Overflow
Videos
This uses Microsoft.Win32.RegistryKey to check the SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall registry key on remote computers.
https://github.com/gangstanthony/PowerShell/blob/master/Get-InstalledApps.ps1
*edit: pasting code for reference
function Get-InstalledApps {
param (
[Parameter(ValueFromPipeline=$true)]
[string[]]$ComputerName = $env:COMPUTERNAME,
[string]$NameRegex = ''
)
foreach ($comp in $ComputerName) {
$keys = '','\Wow6432Node'
foreach (
keys) {
try {
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $comp)
$apps = $reg.OpenSubKey("SOFTWARE$key\Microsoft\Windows\CurrentVersion\Uninstall").GetSubKeyNames()
} catch {
continue
}
foreach (
apps) {
$program = $reg.OpenSubKey("SOFTWARE$key\Microsoft\Windows\CurrentVersion\Uninstall\$app")
$name = $program.GetValue('DisplayName')
if ($name -and $name -match $NameRegex) {
[pscustomobject]@{
ComputerName = $comp
DisplayName = $name
DisplayVersion = $program.GetValue('DisplayVersion')
Publisher = $program.GetValue('Publisher')
InstallDate = $program.GetValue('InstallDate')
UninstallString = $program.GetValue('UninstallString')
Bits =
key -eq '\Wow6432Node') {'64'} else {'32'})
Path = $program.name
}
}
}
}
}
}
There are multiple ways how to get the list of installed software on a remote computer:
Running WMI query on ROOT\CIMV2 namespace:
- Start WMI Explorer or any other tool which can run WMI queries.
- Run WMI query "SELECT * FROM Win32_Product"
Using wmic command-line interface:
- Press WIN+R
- Type "wmic", press Enter
- In wmic command prompt type "/node:RemoteComputerName product"
Using Powershell script:
- Thru WMI object: Get-WmiObject -Class Win32_Product -Computer RemoteComputerName
- thru Registry: Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall* | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Format-Table –AutoSize
- thru Get-RemoteProgram cmdlet: Get-RemoteProgram -ComputerName RemoteComputerName
Source: https://www.action1.com/kb/list_of_installed_software_on_remote_computer.html
My output is empty / blank, see belwo.
The example is missing the trailing slash after Uninstall. I get different software lists when I look at the 32/64 bit entries.
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | sort-object -property DisplayName | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Format-Table –AutoSize
Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | sort-object -property DisplayName | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Format-Table –AutoSize
For a combined view, run this.
function Analyze(
f) {
Get-ItemProperty $p |foreach {
if (($_.DisplayName) -or ($_.version)) {
[PSCustomObject]@{
From = $f;
Name = $_.DisplayName;
Version = $_.DisplayVersion;
Install = $_.InstallDate
}
}
}
}
s += Analyze 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*' 64
$s += Analyze 'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' 32
$s | Sort-Object -Property Name
Instead of WMIC, try Get-CimInstance
Get-CimInstance Win32_Product | Sort-Object -property Name | Format-Table -Property Version, InstallDate, Name
One behavior I have noticed is that referencing Win32_Product generates an event for each product in the application event log. Check your log. You might be getting an error that is stopping the analysis.
Log Name: Application
Source: MsiInstaller
Date: 2/2/2021 10:06:39 AM
Event ID: 1035
Task Category: None
Level: Information
Keywords: Classic
User: SYSTEM
Computer: slick
Description:
Windows Installer reconfigured the product. Product Name: Microsoft SQL Server 2014 Management Objects. Product Version: 12.0.2000.8. Product Language: 1033. Manufacturer: Microsoft Corporation. Reconfiguration success or error status: 0.
Hi,
My output is empty / blank, see belwo.
Fire up your console and type:
wmic product get name,version
It takes a while, but you'll get the full list of installed programs. WMIC is the console version of Windows Management Instrumentation, available from Windows 2000 and onwards. Following the instructions here and here, you can tell WMIC to output in an XML format, that might be a bit more convenient for you. However just calling wmic product get name will get you a list of application names, that you can easily copy paste to a text editor and convert to spreadsheet format.
Alternatively, enter:
wmic /output:C:\InstallList.txt product get name,version
This will output a TXT file with the list of programs. You can then paste that into a spreadsheet, if you want.
Source: http://helpdeskgeek.com/how-to/generate-a-list-of-installed-programs-in-windows/
Also you can use the csv.xsl file to format the output into a CSV list of results:
wmic /output:C:\InstallList.csv product get /format:csv.xsl
or the htable.xsl file to create an HTML table of results:
wmic /output:C:\InstallList.htm product get /format:hform.xsl
Run wmic product get to get a list of installed software, it should be exactly the same list as add/remove programs.
You can supposedly get it to to output in a specific format, but I haven't tried it.
(Use wmic product get /? to see the parameters including the output formatting, I tried to include it here but the formatting wasn't quite right.)
You can use wmic.
Example:
wmic product get name,version /format:csv
wmic /node:localhost /output:d:\programlist.htm product
get name,version /format:htable.xsl
wmic product get name,version
wmic softwareelement get name,version
wmic softwarefeature get name,version
wmic wmic:root\cli>/output:c:\ProgramList.txt product get name,version
Or you can do it like the "Add/Remove Programs", reading all uninstall registry keys:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall
On 64 bit Windows, remember to also check:
HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\
To returns a list of all software installed on a computer, whether or not by Windows-Installer:
Const HKLM = &H80000002 'HKEY_LOCAL_MACHINE
strComputer = "."
strKey = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"
strEntry1a = "DisplayName"
strEntry1b = "QuietDisplayName"
strEntry2 = "InstallDate"
strEntry3 = "VersionMajor"
strEntry4 = "VersionMinor"
strEntry5 = "EstimatedSize"
Set objReg = GetObject("winmgmts://" & strComputer & _
"/root/default:StdRegProv")
objReg.EnumKey HKLM, strKey, arrSubkeys
WScript.Echo "Installed Applications" & VbCrLf
For Each strSubkey In arrSubkeys
intRet1 = objReg.GetStringValue(HKLM, strKey & strSubkey, _
strEntry1a, strValue1)
If intRet1 <> 0 Then
objReg.GetStringValue HKLM, strKey & strSubkey, _
strEntry1b, strValue1
End If
If strValue1 <> "" Then
WScript.Echo VbCrLf & "Display Name: " & strValue1
End If
objReg.GetStringValue HKLM, strKey & strSubkey, _
strEntry2, strValue2
If strValue2 <> "" Then
WScript.Echo "Install Date: " & strValue2
End If
objReg.GetDWORDValue HKLM, strKey & strSubkey, _
strEntry3, intValue3
objReg.GetDWORDValue HKLM, strKey & strSubkey, _
strEntry4, intValue4
If intValue3 <> "" Then
WScript.Echo "Version: " & intValue3 & "." & intValue4
End If
objReg.GetDWORDValue HKLM, strKey & strSubkey, _
strEntry5, intValue5
If intValue5 <> "" Then
WScript.Echo "Estimated Size: " & Round(intValue5/1024, 3) & " megabytes"
End If
Next
The encoded version in c# that is based on the readings in the system registry windows.
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace SoftwareInventory
{
class Program
{
static void Main(string[] args)
{
//!!!!! Must be launched with a domain administrator user!!!!!
Console.ForegroundColor = ConsoleColor.Green;
StringBuilder sbOutFile = new StringBuilder();
Console.WriteLine("DisplayName;IdentifyingNumber");
sbOutFile.AppendLine("Machine;DisplayName;Version");
//Retrieve machine name from the file :File_In/collectionMachines.txt
//string[] lines = new string[] { "NameMachine" };
string[] lines = File.ReadAllLines(@"File_In/collectionMachines.txt");
foreach (var machine in lines)
{
//Retrieve the list of installed programs for each extrapolated machine name
var registry_key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using (Microsoft.Win32.RegistryKey key = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, machine).OpenSubKey(registry_key))
{
foreach (string subkey_name in key.GetSubKeyNames())
{
using (RegistryKey subkey = key.OpenSubKey(subkey_name))
{
//Console.WriteLine(subkey.GetValue("DisplayName"));
//Console.WriteLine(subkey.GetValue("IdentifyingNumber"));
if (subkey.GetValue("DisplayName") != null)
{
Console.WriteLine(string.Format("{0};{1};{2}", machine, subkey.GetValue("DisplayName"), subkey.GetValue("Version")));
sbOutFile.AppendLine(string.Format("{0};{1};{2}", machine, subkey.GetValue("DisplayName"), subkey.GetValue("Version")));
}
}
}
}
}
//CSV file creation
var fileOutName = string.Format(@"File_Out\{0}_{1}.csv", "Software_Inventory", DateTime.Now.ToString("yyyy_MM_dd_HH_mmssfff"));
using (var file = new System.IO.StreamWriter(fileOutName))
{
file.WriteLine(sbOutFile.ToString());
}
//Press enter to continue
Console.WriteLine("Press enter to continue !");
Console.ReadLine();
}
}
}
You can use one of the Sysinternals tools PSinfo:
http://technet.microsoft.com/en-us/sysinternals/bb897550
PsInfo v1.77 - Local and remote system information viewer Copyright (C) 2001-2009 Mark Russinovich Sysinternals - www.sysinternals.com
PsInfo returns information about a local or remote Windows NT/2000/XP system.
Usage: psinfo [-h] [-s] [-d] [-c [-t delimiter]] [filter] [\computer[,computer[,..]]|@file [-u Username [-p Password]]]
-u Specifies optional user name for login to remote computer. -p Specifies password for user name. -h Show installed hotfixes. -s Show installed software. -d Show disk volume information. -c Print in CSV format -t The default delimiter for the -c option is a comma, but can be overriden with the specified character. Use "\t" to specify tab. filter Psinfo will only show data for the field matching thefilter. e.g. "psinfo service" lists only the service pack field. computer Direct PsInfo to perform the command on the remote computer or computers specified. If you omit the computer name PsInfo runs the command on the local system, and if you specify a wildcard (\*), PsInfo runs the command on all computers in the current domain. @file PsInfo will run against the computers listed in the file specified.
Issuing
PSinfo -s \\computername
will tell you what is installed on a remote computer.
On an rpm-based Linux distribution, you could run the following:
ssh <user-who-can-run-rpm>@<remote.host> 'rpm -qa | sort'
For a deb-based distribution, pass this to the ssh command:
'dpkg-query -l | sort'
For Gentoo (per a supplied comment from Monksy):
'qpkg -I | sort'
For Solaris:
'pkginfo -i | sort'
And on AIX:
'lslpp -a all | sort'