WMI:获取已安装软件的列表

Posted

技术标签:

【中文标题】WMI:获取已安装软件的列表【英文标题】:WMI: Get the list of Installed Softwares 【发布时间】:2020-11-14 02:39:21 【问题描述】:

我需要使用wmi 调用来获取远程Windows 主机上已安装软件的列表。我尝试过使用Win32_ProductWin32Reg_AddRemovePrograms 类。

使用Win32_Product 的好处是,它显示了机器上安装的所有软件,但它非常非常慢,并且在超过 90% 的主机上无法运行(出现错误,例如 -NTSTATUS: NT code 0xc002001b - NT code 0xc002001b)。另一方面,Win32Reg_AddRemovePrograms 速度更快,并且在大多数主机上运行良好,但缺少很多软件。

还有其他 Win32 类可以有效地做到这一点吗?

【问题讨论】:

另外值得记住的是,使用 Win32_Product 可能会产生一些奇怪的副作用:support.microsoft.com/kb/974524。不过这篇文章可能有用:blogs.technet.com/b/heyscriptingguy/archive/2011/11/13/… 【参考方案1】:

你可以使用 wmic。

例子:

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

或者您可以像“添加/删除程序”一样读取所有卸载注册表项:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall

在 64 位 Windows 上,请记住还要检查:

HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\

返回计算机上安装的所有软件的列表,无论是否通过 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 

【讨论】:

wmic product 只是Win32_Product 类的别名,不是吗?所有这些wmic 命令只是常规类的别名。 wmic product 实际上调用了wmic path Win32_Product get *。 OP 正在寻求替代方案。 @Dawid Ferenczy Rogožan:是的,但是 WMIC(Windows 管理界面命令)是针对批处理脚本的 WMI 优化。它更快。【参考方案2】:

基于系统注册表窗口读数的 c# 编码版本。

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();
        


    

【讨论】:

以上是关于WMI:获取已安装软件的列表的主要内容,如果未能解决你的问题,请参考以下文章

电脑管家(像qq,360管家)是怎么获取到系统中安装的软件列表和补丁列表(漏洞,已安装,未安装)用C#如何实现

我在 C# 中使用 WMI 来获取所有已安装的软件,但它并没有显示所有软件,只显示 Microsoft 软件

VB仿WINDOWS 卸载程序获取已安装软件列表

如何查看Ubuntu安装包信息

WMI VBScript 与 C#

powershell 使用PowerShell获取所有已安装软件的列表。见http://www.howtogeek.com/165293/how-to-get-a-list-of-software-i