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.