Resolving The Registry Challenge
In this issue:
At the end of last month, I gave you, what I thought would be, a relatively simple PowerShell scripting challenge. In the Windows registry, you can find a list of applications scheduled to run automatically. You can find computer-specific applications under HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run. There is a similar key for user-specific applications under HKCU:.
I wanted you to write a PowerShell function to query these locations and write a custom object to the pipeline with the following properties:
- The application or program name
- The application or program command line
- The registry key path
- Scope (User or Machine based on the registry hive)
- UserName
- ComputerName
I hope found some time to work on a solution. As with all of these challenges, the benefit is is the process, not necessarily the final solution.
Using Registry PSDrives
The simplest approach is to use the existing registry PSDrives with native commands. This approach is straightforward and leverages PowerShell's built-in cmdlets.
PS C:\> Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run'
SecurityHealth : C:\WINDOWS\system32\SecurityHealthSystray.exe
RtkAudUService : "C:\WINDOWS\System32\DriverStore\FileRepository\realtekservice.inf_amd64_e80fb71
73daab733\RtkAudUService64.exe" -background
Logitech Download Assistant : C:\Windows\system32\rundll32.exe C:\Windows\System32\LogiLDA.dll,LogiFetch
LogiOptions : C:\Program Files\Logitech\LogiOptions\LogiOptions.exe /noui
DYMOWebApi : "C:\Program Files (x86)\DYMO\DYMO Connect\DYMO.WebApi.Win.Host.exe" /auto
DymoOfficeHelper : "C:\Program Files (x86)\DYMO\DYMO Connect\DYMO.OfficeHelper.exe" /w
Logi Tune : "C:\Program Files\Logitech\LogiTune\LogiTune.exe" --tray
1Password : C:\Program Files\1Password\app\8\1Password.exe --auto-start
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Window
s\CurrentVersion\Run
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Window
s\CurrentVersion
PSChildName : Run
PSDrive : HKLM
PSProvider : Microsoft.PowerShell.Core\Registry
Each application is a separate property. Here's a cleaner way to get just the application and its value.
$Path = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run'
$r = Get-Item $Path
$r.property | ForEach-Object {
[PSCustomObject]@{
RegistryPath = $Path
Scope = ($path -match '^HKLM:') ? 'Machine' : 'User'
Name = $_
Command = (Get-ItemPropertyValue -Path $Path -Name $_)
Username = "$($env:UserDomain)\$($env:UserName)"
Computername = $env:COMPUTERNAME
}
}
This gives output close to the desired format.
RegistryPath : HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
Scope : Machine
Name : 1Password
Command : C:\Program Files\1Password\app\8\1Password.exe --auto-start
Username : PROSPERO\Jeff
Computername : PROSPERO
This would also work for user current user. This code uses a variation to create the custom object.
$Path = 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run'
$r = Get-Item $Path
foreach ($property in $($r.property)) {
[PSCustomObject]@{
PSTypename = 'RegRunInfo'
RegistryPath = $Path
Scope = ($path -match '^HKLM:') ? 'Machine' : 'User'
Name = $property
Command = $r.GetValue($property)
Username = "$($env:UserDomain)\$($env:UserName)"
Computername = $env:COMPUTERNAME
}
}
I get the same type of output.
RegistryPath : HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
Scope : User
Name : com.squirrel.slack.slack
Command : "C:\Users\Jeff\AppData\Local\slack\slack.exe" --process-start-args --startup
Username : PROSPERO\Jeff
Computername : PROSPERO
Get-LocalAutoRun
Now that I have proof-of-concept commands running in the console, I can wrap the code in a function. I always try to get the core logic and commands working in the console before I start writing a function. This way, I can focus on the logic and not worry about the function syntax. But now that I have this working, here's the function:
#requires -version 7.5
function Get-LocalAutoRun {
[CmdletBinding()]
[OutputType("RegRunInfo")]
param()
$Computername = $env:COMPUTERNAME
#capture the date this information was gathered
$Capture = Get-Date
#query LocalMachine and CurrentUser using registry PSDrives
$paths = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run',
'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run'
foreach ($path in $paths) {
Write-Verbose "Querying auto run entries under $Path on $computerName"
$r = Get-Item $Path
#filter out the empty (Default) property
$properties = $r.property | where { $r.GetValue($_) }
Write-Verbose "Found $($properties.Count) setting(s)"
Write-Information $r -Tags data
foreach ($property in $properties) {
#Using the ScopeOwner property to indicate the "owner"
[PSCustomObject]@{
PSTypename = 'RegRunInfo'
RegistryPath = $Path
Scope = ($path -match '^HKLM:') ? 'Machine' : 'User'
Name = $property
Command = $r.GetValue($property)
ScopeOwner = ($path -match '^HKLM:') ? $env:COMPUTERNAME : "$($env:UserDomain)\$($env:UserName)"
Computername = $env:COMPUTERNAME
Date = $Capture
}
} #foreach property
} #foreach registry path
}
This code is designed to be run on the local computer. It is also written for PowerShell 7 since I am using the ternary operator.
PS C:\> $l = Get-localAutoRun
PS C:\> $l[0]
RegistryPath : HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
Scope : Machine
Name : SecurityHealth
Command : C:\WINDOWS\system32\SecurityHealthSystray.exe
ScopeOwner : PROSPERO
Computername : PROSPERO
Date : 2/24/2026 10:51:40 AM
PS C:\> $l[-1]
RegistryPath : HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
Scope : User
Name : com.squirrel.slack.slack
Command : "C:\Users\Jeff\AppData\Local\slack\slack.exe" --process-start-args --startup
ScopeOwner : PROSPERO\Jeff
Computername : PROSPERO
Date : 2/24/2026 10:51:40 AM
This function meets the requirements of the challenge. It queries both the machine and user auto run registry keys and outputs a custom object with the desired properties. I've enhanced the output a little to provide additional information and context.
Formatting the Output
What might be nicer, is to format the output.
PS C:\> $l | Format-Table -GroupBy RegistryPath -Property Scope,ScopeOwner,Name,Command
RegistryPath: HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
Scope ScopeOwner Name Command
----- ---------- ---- -------
Machine PROSPERO SecurityHealth C:\WINDOWS\system32\SecurityHealthSystray.exe
Machine PROSPERO RtkAudUService "C:\WINDOWS\System32\DriverStore\FileRepository\realtekservice…
Machine PROSPERO Logitech Download Assistant C:\Windows\system32\rundll32.exe C:\Windows\System32\LogiLDA.d…
Machine PROSPERO LogiOptions C:\Program Files\Logitech\LogiOptions\LogiOptions.exe /noui
Machine PROSPERO DYMOWebApi "C:\Program Files (x86)\DYMO\DYMO Connect\DYMO.WebApi.Win.Host…
Machine PROSPERO DymoOfficeHelper "C:\Program Files (x86)\DYMO\DYMO Connect\DYMO.OfficeHelper.ex…
Machine PROSPERO Logi Tune "C:\Program Files\Logitech\LogiTune\LogiTune.exe" --tray
Machine PROSPERO 1Password C:\Program Files\1Password\app\8\1Password.exe --auto-start
RegistryPath: HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
Scope ScopeOwner Name Command
----- ---------- ---- -------
User PROSPERO\Jeff OneDrive "C:\Users\Jeff\AppData\Local\Microsoft\OneDrive\OneDrive.exe" /b…
User PROSPERO\Jeff GoogleDriveFS "C:\Program Files\Google\Drive File Stream\121.0.1.0\GoogleDrive…
User PROSPERO\Jeff BraveSoftware Update "C:\Users\Jeff\AppData\Local\BraveSoftware\Update\1.3.361.151\Br…
User PROSPERO\Jeff DYMOConnectLauncher "C:\Program Files (x86)\DYMO\DYMO Connect\DYMOConnectLauncher.ex…
User PROSPERO\Jeff WingetUI "C:\Users\Jeff\AppData\Local\Programs\UniGetUI\UniGetUI.exe" --d…
User PROSPERO\Jeff com.squirrel.slack.slack "C:\Users\Jeff\AppData\Local\slack\slack.exe" --process-start-ar…
Naturally, I don't want to manually format this so I'll create a custom format file using my handy New-PSFormatXML function.
$l[0] | New-PSFormatXML -GroupBy RegistryPath -Properties Scope,ScopeOwner,Name,Command -Path c:\scripts\RegRunInfo.format.ps1xml
I'll even add an additional named table view.
$l[0] | New-PSFormatXML -GroupBy Scope -Properties ScopeOwner,Name,Command -Path c:\scripts\RegRunInfo.format.ps1xml -Append -ViewName scope
One change I made to the file is to convert the registry path in the default view.
<groupby>
<scriptblock>
<!-- Convert the RegistryPath to full name if not already in that format-->
if ($_.RegistryPath -NotMatch 'HKEY') {
$regPath = (Convert-Path $_.RegistryPath)
}
else {
$regPath = $_.RegistryPath
}
"{0}\{1}" -f $_.Computername,$regPath
</scriptblock>
<label>RegistryPath</label>
</groupby>
I'll load the format file by adding this line to the end of the script file.
Update-FormatData C:\scripts\RegRunInfo.format.ps1xml
Now I have a clean default display.`
PS C:\> $l
RegistryPath: PROSPERO\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
Scope ScopeOwner Name Command
----- ---------- ---- -------
Machine PROSPERO SecurityHealth C:\WINDOWS\system32\SecurityHealthSystray.exe
Machine PROSPERO RtkAudUService "C:\WINDOWS\System32\DriverStore\FileRepository\realtekservice…
Machine PROSPERO Logitech Download Assistant C:\Windows\system32\rundll32.exe C:\Windows\System32\LogiLDA.d…
Machine PROSPERO LogiOptions C:\Program Files\Logitech\LogiOptions\LogiOptions.exe /noui
Machine PROSPERO DYMOWebApi "C:\Program Files (x86)\DYMO\DYMO Connect\DYMO.WebApi.Win.Host…
Machine PROSPERO DymoOfficeHelper "C:\Program Files (x86)\DYMO\DYMO Connect\DYMO.OfficeHelper.ex…
Machine PROSPERO Logi Tune "C:\Program Files\Logitech\LogiTune\LogiTune.exe" --tray
Machine PROSPERO 1Password C:\Program Files\1Password\app\8\1Password.exe --auto-start
RegistryPath: PROSPERO\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
Scope ScopeOwner Name Command
----- ---------- ---- -------
User PROSPERO\Jeff OneDrive "C:\Users\Jeff\AppData\Local\Microsoft\OneDrive\OneDrive.exe" /b…
User PROSPERO\Jeff GoogleDriveFS "C:\Program Files\Google\Drive File Stream\121.0.1.0\GoogleDrive…
User PROSPERO\Jeff BraveSoftware Update "C:\Users\Jeff\AppData\Local\BraveSoftware\Update\1.3.361.151\Br…
User PROSPERO\Jeff DYMOConnectLauncher "C:\Program Files (x86)\DYMO\DYMO Connect\DYMOConnectLauncher.ex…
User PROSPERO\Jeff WingetUI "C:\Users\Jeff\AppData\Local\Programs\UniGetUI\UniGetUI.exe" --d…
User PROSPERO\Jeff com.squirrel.slack.slack "C:\Users\Jeff\AppData\Local\slack\slack.exe" --process-start-ar…