Listing Installed Applications (Part 2)

by Mar 5, 2020

In the previous tip we read the registry to find out paths to applications you can launch. This approach worked well but had two flaws: first, the list did not include the friendly names for the applications, and second, the list was not complete. Only programs who chose to register themselves were listed.

Let’s get a complete list of applications and use three tricks to overcome the limitations:

  • Use a generic list for the results to be able to quickly add more information to the list
  • Blend in the applications PowerShell knows by incorporating the results from Get-Command
  • Identify the application friendly name by reading the extended file info

This is where we start: the list of registered applications from the registry:

$key = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\*", 
    "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\*"

[System.Collections.Generic.List[string]]$list = 
Get-ItemProperty -Path $key | 
Select-Object -ExpandProperty '(Default)' -ErrorAction Ignore 

$list

Now, let’s add the applications known by Get-Command to the list:

[System.Collections.Generic.List[string]]$commands = 
  Get-Command -CommandType Application | 
  Select-Object -ExpandProperty Source

$list.AddRange($commands) 

Finally, let’s sanitize the list by removing quotes, empty and duplicate items:

$finalList = $list |
    Where-Object { $_ } |
    ForEach-Object { $_.Replace('"','').Trim().ToLower() } |
    Sort-Object -Unique 

Now turn the list into objects with application name, description, and absolute path, by reading the extended information for each file. This also eliminates all paths that do not exist. This is the complete code:

$key = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\*", 
    "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\*"

[System.Collections.Generic.List[string]]$list = 
Get-ItemProperty -Path $key | 
Select-Object -ExpandProperty '(Default)' -ErrorAction Ignore 

[System.Collections.Generic.List[string]]$commands = Get-Command -CommandType Application | 
                Select-Object -ExpandProperty Source

$list.AddRange($commands)

$finalList = $list |
    Where-Object { $_ } |
    ForEach-Object { $_.Replace('"','').Trim().ToLower() } |
    Sort-Object -Unique |
    ForEach-Object {
        try {
            $file = Get-Item -Path $_ -ErrorAction Ignore
            [PSCustomObject]@{
                Name = $file.Name
                Description = $file.VersionInfo.FileDescription
                Path = $file.FullName
            }
        } catch {}
    } |
    Sort-Object -Property Name -Unique 

$finalList | Out-GridView -PassThru

The result looks similar to this:


 
PS> $finalList

Name                                           Description                                                                               
----                                           -----------                 
7zfm.exe                                       7-Zip File Manager          
accicons.exe                                   Microsoft Office component
acrord32.exe                                   Adobe Acrobat Reader DC               
agentservice.exe                               AgentService EXE        
aitstatic.exe                                  Application Impact Telemetry...   
 

You are a PowerShell Professional, passionate about improving your code and skills? You take security seriously and are always looking for the latest advice and guidance to make your code more secure and faster? You’d love to connect to the vibrant PowerShell community and get in touch with other PowerShell Professionals to share tricks and experience? Then PowerShell Conference EU 2020 might be just the right place for you: https://psconf.eu (June 2-5, 2020 in Hanover, Germany).

It’s a unique mixture of classic conference with three parallel tracks filled with fast-paced PowerShell presentations, and advanced learning class with live discussions, Q&A and plenty of networking.

Secure your seat while they last: https://psconf.eu/register.html. The speakers and agenda is available here: https://psconf.eu/schedule.

Twitter This Tip! ReTweet this Tip!