PS: 模拟 CCleaner "Uninstall" 工具来列出 PC 上安装的程序

PS: Emulate CCleaner "Uninstall" tool to list programs installed on PC

CCleaner 包含一个工具,用于列出然后卸载您 PC 上的程序。此列表似乎以更全面的方式包含应用程序,而不是在不构建自定义包的情况下浏览 uninstall registry keys. One example of this, is Atom (the Open Source text editor). This program does not appear in the uninstall registry, and is installed in the AppData folder of the user (I'm not aware of a way to install this for all users

我写了一个脚本来定期安装和更新某些软件包。这使我很容易让它们保持最新状态,而无需每周访问十几个网站或每次 building a custom installer 我想更新它们时(它们不会像 Chrome 或 Firefox 那样自动更新).因此,我需要一个可以动态创建并用于检查更新以及是否需要执行安装程序的列表。

所以我的问题是:如何以编程方式模拟 CCleaner 创建其卸载程序列表时的操作?我可以执行 GUI 并导航到卸载工具并单击“保存到文本文件”,但这不是动态的。任何允许我捕获(在 Powershell 脚本中)与 CCleaner 在卸载工具中生成的相同应用程序列表的答案都是可以接受的。

您也可以使用 Get-Package 列出已安装的程序。它将列出 Atom。您可能需要将注册表方法与 Get-Package 结合使用,以防它没有显示全部。

Get-Package | Where-Object name -like *atom*

Name       Version     Source      ProviderName                                                                                                 
----       -------      ------     ------------                                                                                                 
Atom       1.53.0                  Programs  

你所要求的过去是用 Get-CimInstance 完成的,但这是有代价的,而且正如你所指出的那样不再准确。它曾经是一个 WMI 命令。现在 CIM。这不是一个快速的命令,稍后会详细介绍。

Get-CimInstance win32_product

代价是Get-CimInstance可以return不完整的数据。它还 运行 对所有应用程序进行一致性检查并执行自动和静默修复。 是的,当您 运行 此命令时,它会自动 运行 对所有应用程序进行一致性检查并执行自动和静默修复。 这就是为什么这个简单的命令是如此迟迟不来汇报。 Microsoft 对此的文档:Link Here

所以我们不再使用它了,现在怎么办?您正在寻找的是从 32 位和 64 位安装程序收集信息,看起来像这样并且必须完成,我总是先做。

$installedApplications = @()
$installedApplications+= Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" # 32 Bit
$installedApplications+= Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*"             # 64 Bit

上面的一个警告是上面的方法将 return 比 Win32_Product 命令多出一吨的元素。它将包含 Service Pack、Office 更新、语言包等内容。您很可能需要过滤掉您不感兴趣的内容,尽管使用 PowerShell 过滤结果应该没有问题。

为了完成对您问题的回答,无论安装位置如何,您如何量化来自安装者的数据?专门查找 userprofile\AppData 安装信息。好消息是这些应用程序的安装信息也记录在注册表中,位于 HKEY_CURRENT_USER 而不是 HKEY_LOCAL_MACHINE 下。这意味着每个用户的安装位置信息都位于其配置文件下的注册表配置单元中,例如 c:\users\inet\NTUSER.DAT.

这个还有什么好说的;

  • 如果用户已登录,系统上的任何其他管理员用户都可以使用 HKEY_USERS$ACCOUNT_SID 键访问它。
  • 如果用户未登录,可以使用 REG LOAD
  • 手动安装配置单元
  • 如果用户的注册表配置单元已经加载,则无法再次加载,并且会强制显示“此文件正在被另一个进程使用”。

那么我们如何获得您所要求的,即复制设备的“完整安装数据”,而不仅仅是 32 位和 64 位目录中的内容?

这就是我使用的,如果有人愿意,您可以将信息通过管道传输到 CSV/HTML/etc...

    $installedApplications = @()
    $installedApplications+= Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" 
    $installedApplications+= Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*"  

    BitPath = "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
    BitPath = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*"

    $tigerStripes= Get-CimInstance Win32_UserProfile | Select LocalPath, SID, Loaded, Special | Where {$_.SID -like "S-1-5-21-*"}
    $unavailableProfiles = $tigerStripes| Where {$_.Loaded -eq $true}
    $availableProfiles = $tigerStripes| Where {$_.Loaded -eq $false}

    #Mounted
    $unavailableProfiles | % {
        $installedApplications += Get-ItemProperty -Path "Registry::\HKEY_USERS$($_.SID)$32BitPath"
        $installedApplications += Get-ItemProperty -Path "Registry::\HKEY_USERS$($_.SID)$64BitPath"
    }
    #Unmounted
    $availableProfiles | % {
        #Mount Hive
        $Hive = "$($_.LocalPath)\NTUSER.DAT"

        if (Test-Path $Hive) {
            REG LOAD HKU\temp $Hive
            $installedApplications += Get-ItemProperty -Path "Registry::\HKEY_USERS\temp$32BitPath"
            $installedApplications += Get-ItemProperty -Path "Registry::\HKEY_USERS\temp$64BitPath"

            #This lets the hive be unmounted, using a manual Get-Content
            [GC]::Collect()
            [GC]::WaitForPendingFinalizers()
        
            REG UNLOAD HKU\temp

        } else {
            Write-Warning "Unable to access registry at $Hive"
        }
    }

$installedApplications