Get-InstalledSoftware

Discussion in 'Scripting' started by GodHand, Oct 10, 2019.

  1. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    508
    750
    30
    #1 GodHand, Oct 10, 2019
    Last edited: Nov 3, 2019
    Here is a fairly useful function that will return all installed software on your system as well as its publisher, install date and uninstall string. Uninstall strings are useful for automated and/or manual removal of software without any "uninstallers" or Windows' uninstall feature.

    All details of how it can be run and how you can pipe the function to other cmdlets are in its header.

    Updated on 11-03-19:
    - It now loads the HKEY_USERS hive and loops through the local registry for each account SID to further gather all locally installed software.
    - Values with no properties assigned to them will return as '<null>'
    - The software's package-specific GUID is also returned.
    - The object returned with all the software information is now automatically sorted by the Display Name of the software for easier navigation.

    Code:
    Function Get-InstalledSoftware
    {
    <#
        .SYNOPSIS
            Display detailed information about the currently installed software on a device.
       
        .DESCRIPTION
            Return detailed information about the software currently installed on the device.
            Performs a query loop through the system registry to gather roaming installed software.
            Loads the HKEY_USERS hive and performs a query loop through the registry to gather locally installed software for each account SID.
            The software information returned includes its version, publisher, installation date, GUID and uninstall string.
            The GUID and uninstall string allows for command-line configuration or uninstallation of software.
            Any properties that do not contain any information will return as '<null>'.
       
        .EXAMPLE
            PS C:\> Get-InstalledSoftware | Where-Object -Property DisplayName -Like SAPIEN* | Select-Object -Property DisplayName, UninstallString -Unique
           
            This one-line command uses the pipe-line to pipe the Get-InstalledSoftware results to the Where-Object cmdlet to filter out all software except SAPIEN software.
            The SAPIEN-specific software is then piped to the Select-Object cmdlet to only return the DisplayName and UninstallStrings of the installed software.
            The -Unique switch it used to prevent any duplicate entries from being displayed.
           
            PS C:\> SAPIEN Document Explorer 2019                   msiexec.exe /x {FDD74C8F-E765-4EBE-A395-58CC7DB9AE15} AI_UNINSTALLER_CTP=1
            PS C:\> SAPIEN PowerShell Studio 2019                   msiexec.exe /x {A6A692FE-CDB1-4F93-AB53-DE6FDA13A003} AI_UNINSTALLER_CTP=1
            PS C:\> SAPIEN Updates                                  msiexec.exe /x {8E30326B-DCB2-4165-84B2-0725FB90DFAD} AI_UNINSTALLER_CTP=1
            PS C:\> SAPIEN ScriptMerge 2019                         msiexec.exe /x {C6F25D63-A5DE-4BE9-8111-56EAEEB41D40} AI_UNINSTALLER_CTP=1
       
        .EXAMPLE
            PS C:\> Get-InstalledSoftware | Select-Object -ExpandProperty DisplayName | Out-File -FilePath "$HOME\Desktop\InstalledSoftware.txt" -Force
           
            This command will get all installed software on the device and output the DisplayNames to an InstalledSoftware.txt file on the Desktop.
       
        .OUTPUTS
            PSCustomObject
       
        .INPUTS
            None
    #>
       
        [CmdletBinding()]
        [OutputType([PSCustomObject])]
        Param ()
       
        Begin
        {
            If (!(Test-Path -LiteralPath HKU:)) { $HKUDrive = New-PSDrive -Name HKU -PSProvider Registry -Root HKEY_USERS }
        }
        Process
        {
            $UninstallKeys = @('HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall', 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall')
            $UninstallKeys += Get-ChildItem -LiteralPath HKU: -ErrorAction SilentlyContinue | Where-Object -Property Name -Match 'S-\d-\d+-(\d+-){1,14}\d+$' | ForEach-Object -Process { "HKU:\$($_.PSChildName)\Software\Microsoft\Windows\CurrentVersion\Uninstall" }
            $UninstallKeys = $UninstallKeys | Get-ChildItem | ForEach-Object -Process { Get-ItemProperty -Path $_.PsPath } | ForEach-Object -Process {
                [PSCustomObject]@{
                    DisplayName     = If ($_.DisplayName) { $_.DisplayName } Else { '<null>' };
                    DisplayVerison  = If ($_.DisplayVersion) { $_.DisplayVersion } Else { '<null>' };
                    Publisher       = If ($_.Publisher) { $_.Publisher } Else { '<null>' };
                    InstallDate     = If ($_.InstallDate) { $_.InstallDate } Else { '<null>' };
                    GUID            = If ($_.PSChildName -and $_.PSChildName -match '\b[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}\b') { $_.PSChildName } Else { '<null>' };
                    UninstallString = If ($_.UninstallString) { $_.UninstallString } Else { '<null>' }
                }
            }
            $UninstallKeys | Where-Object { $_.DisplayName -ne '<null>' -and $_.UninstallString -ne '<null>' } | Sort-Object -Property DisplayName
        }
        End
        {
            If ($HKUDrive) { Remove-PSDrive -Name $HKUDrive.Name }
        }
    }
     
  2. abbodi1406

    abbodi1406 MDL KB0000001

    Feb 19, 2011
    10,653
    43,863
    340
    Some empty registry keys exist on Win 7/8.1 (and probably 10)
    Code:
    Windows Registry Editor Version 5.00
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\AddressBook]
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Connection Manager]
    "SystemComponent"=dword:00000001
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\DirectDrawEx]
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\DXM_Runtime]
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Fontcore]
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IE40]
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IE4Data]
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IE5BAKEX]
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IEData]
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\MobileOptionPack]
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\MPlayer2]
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\SchedulingAgent]
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\WIC]
    "NoRemove"=dword:00000001
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}.KB2151757]
    @="KB2151757"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}.KB2467173]
    @="KB2467173"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}.KB2524860]
    @="KB2524860"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}.KB2544655]
    @="KB2544655"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}.KB2549743]
    @="KB2549743"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}.KB2565063]
    @="KB2565063"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}.KB2608539]
    @="KB2608539"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}.KB2689322]
    @="KB2689322"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}.KB2723430]
    @="KB2723430"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}.KB2821701]
    @="KB2821701"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}.KB2845370]
    @="KB2845370"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}.KB2890375]
    @="KB2890375"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}.KB982573]
    @="KB982573"
    the latest keys are pat of VC++ 2010 redist
    maybe it's best to verify them and exclude them
    Code:
        {if ($InstallProperty.DisplayName -ne $nul) {
            [PSCustomObject]@{
                DisplayName     = $InstallProperty.DisplayName
                DisplayVerison  = $InstallProperty.DisplayVersion
                Publisher       = $InstallProperty.Publisher
                InstallDate     = $InstallProperty.InstallDate
                HelpLink        = $InstallProperty.HelpLink
                UninstallString = $InstallProperty.UninstallString
            }
            }
        }
    additionally, x86 programs on x64 system have separate path :)
    Code:
    [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall]
    thanks
     
  3. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    508
    750
    30
    I added that additional registry path although I personally have never noticed a difference with it enabled (then again, I have virtually no x86 programs).

    I also added a small filter to output only objects that have a valid Display Name and no duplicate programs. One way or another, some programs will have $null values for some of the properties but by filtering out the Display Name, it prevents those objects with no values from displaying.
     
  4. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    508
    750
    30
    I updated this function:

    In addition to querying the system registry hives, it now loads the HKEY_USERS hive and loops through the local registry for each account SID to further gather all locally installed software.
    The software-specific GUID is now included.
    Added better formatting for the object returned with the software data.