使用 PowerShell 列出已安裝的軟件: 免費工具

如果您是系統管理員,其中一個工作是在大量系統上安裝、升級和移除軟件。如果我告訴您,您不需要再連接到每台機器並手動檢查安裝的軟件了呢?您實際上可以使用 PowerShell 列出已安裝的軟件!

在這篇博文中,我將向您展示如何使用 PowerShell 在本地機器和多台計算機上列出已安裝的軟件。

Listing installed software with PowerShell script

請注意,一些文章可能會告訴您執行類似 Get-WmiObject -Class win32_product 的操作。請不要這樣做。了解為什麼可以在這裡。

已安裝的軟件和註冊表

作為參考,已安裝的軟件位於三個位置:

  • 32 位系統卸載註冊表鍵
  • 64 位系統卸載註冊表鍵
  • 每個用戶配置文件的卸載註冊表鍵。

每個軟件項目通常由軟件的全局唯一識別符 (GUID) 定義。GUID 鍵的內部包含有關該特定軟件的所有信息。要獲得完整列表,PowerShell 必須枚舉每個這些鍵,讀取每個註冊表值並解析結果。

由於正確解析這些值的程式碼遠超過一篇文章的範圍,我已經預先建立了一個名為Get-InstalledSoftware的功能,用於使用PowerShell列出已安裝的軟體。如下所示,該功能將所有程式碼封裝起來,以便您可以看到它在計算機上列出了已安裝的程式。

function Get-InstalledSoftware {
    <#
	.SYNOPSIS
		擷取 Windows 電腦上所有已安裝的軟體清單。
	.EXAMPLE
		PS> Get-InstalledSoftware
		
		此範例會擷取本機電腦上所有已安裝的軟體。
	.PARAMETER ComputerName
		如果查詢遠端電腦,請在此處使用電腦名稱。
	
	.PARAMETER Name
		您想限制查詢的軟體標題。
	
	.PARAMETER Guid
		您想限制查詢的軟體 GUID
	#>
    [CmdletBinding()]
    param (
		
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$ComputerName = $env:COMPUTERNAME,
		
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
		
        [Parameter()]
        [guid]$Guid
    )
    process {
        try {
            $scriptBlock = {
                $args[0].GetEnumerator() | ForEach-Object { New-Variable -Name $_.Key -Value $_.Value }
				
                $UninstallKeys = @(
                    "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall",
                    "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
                )
                New-PSDrive -Name HKU -PSProvider Registry -Root Registry::HKEY_USERS | Out-Null
                $UninstallKeys += Get-ChildItem HKU: | where { $_.Name -match 'S-\d-\d+-(\d+-){1,14}\d+$' } | foreach {
                    "HKU:\$($_.PSChildName)\Software\Microsoft\Windows\CurrentVersion\Uninstall"
                }
                if (-not $UninstallKeys) {
                    Write-Warning -Message 'No software registry keys found'
                } else {
                    foreach ($UninstallKey in $UninstallKeys) {
                        $friendlyNames = @{
                            'DisplayName'    = 'Name'
                            'DisplayVersion' = 'Version'
                        }
                        Write-Verbose -Message "Checking uninstall key [$($UninstallKey)]"
                        if ($Name) {
                            $WhereBlock = { $_.GetValue('DisplayName') -like "$Name*" }
                        } elseif ($GUID) {
                            $WhereBlock = { $_.PsChildName -eq $Guid.Guid }
                        } else {
                            $WhereBlock = { $_.GetValue('DisplayName') }
                        }
                        $SwKeys = Get-ChildItem -Path $UninstallKey -ErrorAction SilentlyContinue | Where-Object $WhereBlock
                        if (-not $SwKeys) {
                            Write-Verbose -Message "No software keys in uninstall key $UninstallKey"
                        } else {
                            foreach ($SwKey in $SwKeys) {
                                $output = @{ }
                                foreach ($ValName in $SwKey.GetValueNames()) {
                                    if ($ValName -ne 'Version') {
                                        $output.InstallLocation = ''
                                        if ($ValName -eq 'InstallLocation' -and 
                                            ($SwKey.GetValue($ValName)) -and 
                                            (@('C:', 'C:\Windows', 'C:\Windows\System32', 'C:\Windows\SysWOW64') -notcontains $SwKey.GetValue($ValName).TrimEnd('\'))) {
                                            $output.InstallLocation = $SwKey.GetValue($ValName).TrimEnd('\')
                                        }
                                        [string]$ValData = $SwKey.GetValue($ValName)
                                        if ($friendlyNames[$ValName]) {
                                            $output[$friendlyNames[$ValName]] = $ValData.Trim() ## 一些登錄值會有尾部空格。
                                        } else {
                                            $output[$ValName] = $ValData.Trim() ## 一些登錄值有尾部空格
                                        }
                                    }
                                }
                                $output.GUID = ''
                                if ($SwKey.PSChildName -match '\b[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}\b') {
                                    $output.GUID = $SwKey.PSChildName
                                }
                                New-Object -TypeName PSObject -Prop $output
                            }
                        }
                    }
                }
            }
			
            if ($ComputerName -eq $env:COMPUTERNAME) {
                & $scriptBlock $PSBoundParameters
            } else {
                Invoke-Command -ComputerName $ComputerName -ScriptBlock $scriptBlock -ArgumentList $PSBoundParameters
            }
        } catch {
            Write-Error -Message "Error: $($_.Exception.Message) - Line Number: $($_.InvocationInfo.ScriptLineNumber)"
        }
    }
}

將此功能複製並粘貼到您的PowerShell控制台中,或將其添加到您的腳本中後,您可以使用ComputerName參數和特定的電腦名稱來呼叫它。

使用PowerShell列出已安裝的軟體清單

PS> Get-InstalledSoftware -ComputerName XXXXX

這樣做時,您將為每個已安裝的軟體獲得一個物件。您可以獲得關於已安裝的任何軟體的豐富資訊。

如果您事先知道軟體的名稱,您也可以使用Name參數來限制只匹配該值的軟體。

例如,也許您只想檢查是否安裝了 Microsoft Visual C++ 2005 Redistributable (x64)。您只需將此作為Name參數值,如下所示。

PS> Get-InstalledSoftware -ComputerName MYCOMPUTER -Name 'Microsoft VisualC++ 2005 Redistributable (x64)'

摘要

使用 PowerShell 獲取已安裝的軟體,您可以構建一個完全免費的工具,您和您的團隊可以使用該工具輕鬆找到多台 Windows 電腦上已安裝的軟體!

Source:
https://adamtheautomator.com/powershell-list-installed-software/