Listar Software Instalado com PowerShell: Uma Ferramenta Gratuita

Se você é um administrador de sistemas, uma de suas tarefas é instalar, atualizar e remover software de muitos sistemas. E se eu te dissesse que você não precisa mais se conectar a cada máquina e verificar manualmente o software instalado? Na verdade, você pode listar o software instalado com o PowerShell!

Neste post do blog, vou te mostrar como listar o software instalado com o PowerShell na sua máquina local e em muitos computadores de uma só vez.

Listing installed software with PowerShell script

Observe que alguns artigos podem sugerir algo como Get-WmiObject -Class win32_product. Não faça isso. Saiba por que aqui.

Software Instalado e o Registro

Para referência, o software instalado existe em três locais:

  • a chave de registro de desinstalação do sistema de 32 bits
  • a chave de registro de desinstalação do sistema de 64 bits
  • a chave de registro de desinstalação do perfil de cada usuário.

Cada entrada de software é geralmente definida pelo identificador único global (GUID) do software. O interior da chave GUID contém todas as informações sobre aquele software específico. Para obter uma lista completa, o PowerShell deve enumerar cada uma dessas chaves, ler cada valor do registro e analisar os resultados.

Como o código para analisar corretamente esses valores é muito extenso para caber em um único artigo, eu pré-construí uma função chamada Get-InstalledSoftware para listar o software instalado com o PowerShell, que encapsula todo esse código para você, como você pode ver abaixo, que lista os programas instalados em um computador.

function Get-InstalledSoftware {
    <#
	.SINOPSE
		Recupera uma lista de todo o software instalado em um computador Windows.
	.EXEMPLO
		PS> Get-InstalledSoftware
		
		Este exemplo recupera todo o software instalado no computador local.
	.PARAMETRO ComputerName
		Se estiver consultando um computador remoto, use o nome do computador aqui.
	
	.PARAMETRO Name
		O título do software ao qual você gostaria de limitar a consulta.
	
	.PARAMETRO Guid
		O GUID do software ao qual você gostaria de limitar a consulta.
	#>
    [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() ## Alguns valores do registro têm espaços extras no final.
                                        } else {
                                            $output[$ValName] = $ValData.Trim() ## Alguns valores do registro têm espaços extras no final
                                        }
                                    }
                                }
                                $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)"
        }
    }
}

Depois de copiar e colar esta função no seu console do PowerShell ou adicioná-la ao seu script, você pode chamá-la usando um nome de computador específico com o parâmetro ComputerName.

Listar Software Instalado com PowerShell

PS> Get-InstalledSoftware -ComputerName XXXXX

Ao fazer isso, você receberá um objeto para cada software instalado. Você pode obter uma riqueza de informações sobre qualquer software instalado.

Se você souber o título do software com antecedência, também pode usar o parâmetro Name para limitar apenas ao software que corresponda a esse valor.

Por exemplo, talvez você queira apenas verificar se o Microsoft Visual C++ 2005 Redistributable (x64) está instalado. Você simplesmente usaria isso como o valor do parâmetro Name conforme mostrado abaixo.

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

Resumo

Usando o PowerShell para obter o software instalado, você pode construir uma ferramenta completamente gratuita que você e sua equipe podem usar para encontrar facilmente o software instalado em muitos computadores com Windows de uma só vez!

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