Lista de software instalado con PowerShell: una herramienta gratuita

Si eres un administrador de sistemas, una de tus tareas es instalar, actualizar y eliminar software de muchos sistemas. ¿Qué tal si te digo que ya no tienes que conectarte a cada máquina y verificar manualmente el software instalado? ¡En realidad, puedes listar el software instalado con PowerShell!

En esta publicación de blog, te mostraré cómo listar el software instalado con PowerShell en tu máquina local y en muchas computadoras a la vez.

Listing installed software with PowerShell script

Ten en cuenta que algunos artículos pueden decirte que hagas algo como Get-WmiObject -Class win32_product. No lo hagas. Aprende por qué aquí.

Software instalado y el Registro

Para referencia, el software instalado existe en tres ubicaciones:

  • la clave del registro de desinstalación del sistema de 32 bits
  • la clave del registro de desinstalación del sistema de 64 bits
  • la clave del registro de desinstalación de cada perfil de usuario.

Cada entrada de software generalmente está definida por el identificador único global (GUID) del software. El interior de la clave GUID contiene toda la información sobre ese software en particular. Para obtener una lista completa, PowerShell debe enumerar cada una de estas claves, leer cada valor del registro y analizar los resultados.

Dado que el código necesario para analizar correctamente estos valores es mucho más extenso de lo que puede contener un solo artículo, he preconstruido una función llamada Get-InstalledSoftware para enumerar el software instalado con PowerShell, que envuelve todo ese código, como se puede ver a continuación, que lista los programas instalados en una computadora.

function Get-InstalledSoftware {
    <#
	.SINOPSIS
		Recupera una lista de todo el software instalado en una computadora con Windows.
	.EJEMPLO
		PS> Get-InstalledSoftware
		
		Este ejemplo recupera todo el software instalado en la computadora local.
	.PARÁMETRO ComputerName
		Si está consultando una computadora remota, use el nombre de la computadora aquí.
	
	.PARÁMETRO Name
		El título del software al que desea limitar la consulta.
	
	.PARÁMETRO Guid
		El GUID del software al que desea limitar la 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() ## Algunos valores del registro tienen espacios al final.
                                        } else {
                                            $output[$ValName] = $ValData.Trim() ## Algunos valores del registro tienen espacios al 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)"
        }
    }
}

Una vez que copie y pegue esta función en su consola de PowerShell o la agregue a su script, puede llamarla utilizando un nombre de computadora específico con el parámetro ComputerName.

Listar Software Instalado con PowerShell

PS> Get-InstalledSoftware -ComputerName XXXXX

Cuando haga esto, obtendrá un objeto por cada software instalado. Podrá obtener una gran cantidad de información sobre cualquier software que esté instalado.

Si conoces el título del software de antemano, también puedes usar el parámetro Name para limitar solo al software que coincida con ese valor.

Por ejemplo, tal vez solo quieras verificar si está instalado Microsoft Visual C++ 2005 Redistributable (x64). Simplemente usarías esto como el valor del parámetro Name como se muestra a continuación.

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

Resumen

¡Usando PowerShell para obtener el software instalado, puedes construir una herramienta completamente gratuita que tú y tu equipo pueden usar para encontrar fácilmente el software instalado en muchas computadoras con Windows a la vez!

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