Reputation: 1755
I need to get the list of installed softwares on remote Windows hosts using wmi
calls. I have tried using Win32_Product
and Win32Reg_AddRemovePrograms
Classes.
Advantage of using Win32_Product
is that, it displays all the softwares installed on the machine, but it is very very slow and does not work on more than 90% hosts (giving errors like- NTSTATUS: NT code 0xc002001b - NT code 0xc002001b
). On the other hand, Win32Reg_AddRemovePrograms
is much quicker and works pretty well on most of the hosts, but misses plenty of softwares.
Is there any other Win32 Class that could do the same efficiently?
Upvotes: 12
Views: 87981
Reputation: 27423
Also, get-package
in powershell 5.1 will list all the installed software. It's a compiled cmdlet, so I'm not sure how it works, if it uses wmi or the registry. Powershell 7 unfortunately doesn't support the msi or programs providers.
Win32_SoftwareElement seems to be msi installs only.
I believe Win32Reg_AddRemovePrograms requires the sccm client, 'Configuration Manager Client'.
Upvotes: 0
Reputation: 986
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();
}
}
}
Upvotes: 1
Reputation: 82176
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
Upvotes: 17