WMI“已安装”查询与添加/删除程序列表不同?

时间:2009-03-23 12:40:30

标签: windows windows-installer wmi

尝试使用WMI获取Windows XP已安装程序的列表。使用wmic,我尝试了:

wmic /output:c:\ProgramList.txt product get name,version

我得到了许多已安装程序的列表,但在根据显示的“添加/删除程序”清除此列表后,我看到添加/删除程序的GUI中列出的程序多于WMI查询。我需要使用另一个WMI查询来安装其余的程序吗?或者还有其他一些我需要寻找的地方吗?

此外,WMI查询中列出的两个已安装的程序不在“添加/删除程序”中。知道为什么吗?

13 个答案:

答案 0 :(得分:28)

我相信您的语法是在WMI中使用Win32_Product类。一个原因是此类仅显示使用Windows Installer(See Here)安装的产品。卸载注册表项是您最好的选择。这是some code来监视注册表项。

评论更新:

卸载注册表项是列出已安装内容和未安装内容的标准位置。它是“添加/删除程序”列表用于填充应用程序列表的位置。我确信有些应用程序没有在此位置列出自己。在这种情况下,您必须采用另一种更粗糙的方法,例如搜索Program Files目录或查看“开始菜单程序列表”。这两种方式都绝对不理想。

在我看来,查看注册表项是最好的方法。

答案 1 :(得分:13)

所有添加/删除程序实际上都在阅读此注册表项:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall

答案 2 :(得分:7)

除了已安装程序最常用的注册表项外:

  

HKEY_LOCAL_MACHINE \ SOFTWARE \微软\的Windows \ CurrentVersion \卸载

wmic命令和添加/删除程序也查询另一个注册表项:

  

HKEY_CLASSES_ROOT \安装\产品

列表中显示的软件名称是从此密钥中的数据条目的值中读取的:ProductName

从上述两个位置删除某个产品的注册表项将使其无法显示在“添加/删除程序”列表中。这不是卸载程序的方法,它只是从已知的Windows中删除条目作为已安装的软件。

由于使用此方法,您将无法使用“添加/删除”列表中的“删除”按钮从系统中清除软件;建议在删除文件之前将注册表项导出到文件中。将来,如果您决定将该项目带回列表,您只需运行您存储的注册表文件。

答案 3 :(得分:5)

我一直在使用Inno Setup作为安装程序。我只使用64位Windows 7。我发现注册表项正在写入

  

HKEY_LOCAL_MACHINE \ SOFTWARE \ Wow6432Node \微软\的Windows \ CurrentVersion \卸载

我还没有弄清楚如何让WMI报告这个列表(尽管程序列在程序和功能中已安装)。如果我搞清楚了,我会记得在这里报告。

<强>更新

安装在64位计算机上的32位程序的条目进入该注册表位置。这里写的更多:

http://mdb-blog.blogspot.com/2010/09/c-check-if-programapplication-is.html

请参阅我的评论,其中描述了同一帖子中的32位与64位行为:

http://mdb-blog.blogspot.com/2010/09/c-check-if-programapplication-is.html?showComment=1300402090679#c861009270784046894

不幸的是,似乎没有办法让WMI列出添加/删除程序列表中的所有程序(也就是Windows 7中的程序和功能,不确定Vista)。我当前的代码已经放弃了WMI,转而使用注册表。查询注册表的代码本身比使用WMI更容易。示例代码位于上述链接中。

答案 4 :(得分:4)

不是最好的,但是否是实用的方法:

使用HijackThis

运行劫持,点击“打开其他工具”部分按钮

HijackThis Main Menu

点击“打开卸载管理器”

HijackThis Configuration

点击保存列表(* .txt),按提示是,记事本将打开你的添加/删除程序列表。

HijackThis Add/Remove Programs Manager


Source

答案 5 :(得分:2)

已安装的产品包含已安装的软件元素和功能,因此值得检查PRODUCT的wmic别名以及检查SOFTWAREELEMENT和SOFTWAREFEATURE:

wmic product get name,version

wmic softwareelement get name,version

wmic softwarefeature get name,version

答案 6 :(得分:2)

您可以使用http://technet.microsoft.com/en-us/library/ee692772.aspx#EBAA中的脚本访问注册表并使用WMI列出应用程序。

答案 7 :(得分:1)

为了构建一个或多或少可靠的应用程序列表,这些应用程序出现在控制面板的“程序和功能”中,您必须考虑并非所有应用程序都是使用MSI安装的。 WMI仅提供安装了MSI的那些。

以下是我发现的简短摘要:

MSI应用程序始终在HKLM\...\Uninstall和/或HKLM\...\Installer\UserData\S-1-5-18\Products下有一个产品代码(GUID)子项。此外,他们可能有一个看起来像HKLM\...\Uninstall\NotAGuid的密钥。

非MSI应用没有产品代码,因此拥有HKLM\...\Uninstall\NotAGuidHKCU\...\Uninstall\NotAGuid等密钥。

答案 8 :(得分:0)

添加/删除程序还必须查看此注册表项以查找当前用户的安装:

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Uninstall

只能在此处找到通过JavaWS(网络启动)JNLP安装的Google Chrome,Dropbox或快捷方式等应用程序。

答案 9 :(得分:0)

我根据自己的需要调整了MS-Technet VBScript。它将Wow6432Node以及标准条目转储到&#34; programms.txt&#34; 使用它需要您自担风险,不保修!

另存为 dump.vbs

从命令行类型: wscript dump.vbs

Const HKLM = &H80000002
Set objReg = GetObject("winmgmts://" & "." & "/root/default:StdRegProv")
Set objFSO = CreateObject("Scripting.FileSystemObject")

outFile="programms.txt"

Set objFile = objFSO.CreateTextFile(outFile,True)
writeList "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\", objReg, objFile
writeList "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\", objReg, objFile
objFile.Close 

Function writeList(strBaseKey, objReg, objFile) 
objReg.EnumKey HKLM, strBaseKey, arrSubKeys 
    For Each strSubKey In arrSubKeys
        intRet = objReg.GetStringValue(HKLM, strBaseKey & strSubKey, "DisplayName", strValue)
        If intRet <> 0 Then
            intRet = objReg.GetStringValue(HKLM, strBaseKey & strSubKey, "QuietDisplayName", strValue)
        End If
        objReg.GetStringValue HKLM, strBaseKey & strSubKey, "DisplayVersion", version
        objReg.GetStringValue HKLM, strBaseKey & strSubKey, "InstallDate", insDate 
        If (strValue <> "") and (intRet = 0) Then
            objFile.Write strValue & "," & version & "," & insDate & vbCrLf
        End If
    Next
End Function

答案 10 :(得分:0)

您可以使用powershell和批处理文件在一行中获取它:

@echo off
Powershell /command "Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Format-List"
Pause

答案 11 :(得分:0)

希望这有助于某人:我一直在我的脚本中使用基于注册表的枚举(如上面的一些答案所示),但发现在Windows 10上运行时它没有正确枚举64位软件x64通过SCCM(使用32位客户端)。在我的特定情况下,找到这样的东西是最直接的解决方案:

Function Get-Programs($Bits) {
  $Result = @()
  $Output = (reg query HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall /reg:$Bits /s)

  Foreach ($Line in $Output) {
    If ($Line -match '^\s+DisplayName\s+REG_SZ\s+(.+?)$') {
      $Result += New-Object PSObject -Property @{
        DisplayName = $matches[1];
        Bits = "$($Bits)-bit";
      }
    }
  }

  $Result
}

$Software  = Get-Programs 32
$Software += Get-Programs 64

意识到这有点太糟糕了Perl-ish,但我见过的所有其他选择都涉及到包装脚本和类似聪明聪明的解决方案的疯狂,这似乎更人性化了。

P.S。在这里努力避免向微软倾倒大量的盐,以便做出一个绝对无足轻重的事情。即,枚举在网络上使用的所有MS Office版本是让成年人哭泣的任务。

答案 12 :(得分:0)

自从提出这个问题以来,时间已经过去了很多。

这些天,注册表中有一个WMI类可用于Uninstall条目。这比Win32_Product引用要快得多,我认为Win32_Product也在列表上运行验证,可能需要一段时间才能枚举。下面的Powershell代码(可能需要Powershell 3或更高版本)将列出所有条目(Out-Gridview部分仅用于漂亮的显示)。

Get-CimInstance Win32Reg_AddRemovePrograms | Out-gridview