Creating A Registry Usage Tool
In this issue:
Let's spend some time building a new PowerShell tool. You may not have a need for the final product, but I think there is value in the process so time to dig in. I want to build a PowerShell tool based on a SysInternals command-line tool. You can download SysInternal utilities from https://live.sysinternals.com. Documentation for everything can be found at https://learn.microsoft.com/en-us/sysinternals/.
Registry Size Usage Reporter
The utility I want to use is the registry size usage command. I've downloaded the SysInternal tools to my OneDrive folder so that I can access them from my laptops and desktop. I am writing this on an Arm64-based laptop so I'll use the Arm-specific version.
$cmd = "$env:OneDrive\tools\arm64\ru64a.exe"
I can use the invoke operator (&) to test.
PS C:\> &$cmd
Ru v1.2 - Registry size usage reporter
Copyright (C) 2013-2016 Mark Russinovich
Sysinternals - www.sysinternals.com
usage: ru64a [-c[t]] [-l <levels> | -n | -v] [-q] <absolute path="">
usage: ru64a [-c[t]] [-l <levels> | -n | -v] [-q] -h <hive file=""> [relative path]
-c Print output as CSV. Specify -ct for tab delimiting.
Specify -nobanner to avoid banner being output to CSV
-h Load the specified hive file, perform the size calculation, then
unload it and compress it.
-l Specify subkey depth of information (default is one level).
-n Do not recurse.
-v Show size of all subkeys.
-nobanner
Do not display the startup banner and copyright message.
CSV output is formatted as:
Path,CurrentValueCount,CurrentValueSize,ValueCount,KeyCount,KeySize,WriteTime
Let's try a simple command.
PS C:\> &$cmd -nobanner hkey_current_user
Values: 48611
Keys: 21253
Size: 15,818,686 bytes
Not bad, but everything is a bunch of strings. I want something I can use in PowerShell. Fortunately, I see that the command has an option to use CSV output.
PS C:\> &$cmd -nobanner -c hkey_current_user
Path,CurrentValueCount,CurrentValueSize,ValueCount,KeyCount,KeySize,WriteTime
"HKCU",0,0,48611,21253,15818686,5/21/2026 9:51 AM
Excellent. I can easily turn this CSV output into an object.
PS C:\> &$cmd -nobanner -c hkey_current_user | ConvertFrom-CSV
Path : HKCU
CurrentValueCount : 0
CurrentValueSize : 0
ValueCount : 48611
KeyCount : 21253
KeySize : 15818686
WriteTime : 5/21/2026 9:51 AM
This gives me a custom object in the PowerShell pipeline, which is a great starting point.
Adding Value
When I'm creating something like this, I am always thinking about how someone might use it. What might someone do with the output? One thing I think about is that if someone serializes the output, such as converting it to a JSON file, and then later brings it back in another PowerShell session, there's no obvious indication where the information came from. And if you were pulling information from multiple sources, there's no apparent way to distinguish them.
The easy answer is to add a Computername property. I can use Add-Member to define this property on the current object.
PS C:\> Add-Member -MemberType NoteProperty -Name Computername -Value $env:COMPUTERNAME -PassThru
Path : HKCU
CurrentValueCount : 0
CurrentValueSize : 0
ValueCount : 48611
KeyCount : 21253
KeySize : 15818686
WriteTime : 5/21/2026 9:51 AM
Computername : CADENZA
Remember to include -Passthru so that Add-Member passes the object down the pipeline.
Another thought I had is to add a property that shows the age since this part of the registry was last updated. I'll need a script property for that so that I can calculate a time span based on the current date and time. I can use Add-Member for this as well.
PS C:\> &$cmd -nobanner -c hkcu | ConvertFrom-Csv | Add-Member -MemberType ScriptProperty -name Age -Value {New-TimeSpan -start $this.WriteTime -end (Get-Date)} -PassThru | Add-Member -MemberType NoteProperty -Name Computername -Value $env:COMPUTERNAME -PassThru
Path : HKCU
CurrentValueCount : 0
CurrentValueSize : 0
ValueCount : 48611
KeyCount : 21253
KeySize : 15818686
WriteTime : 5/21/2026 9:51 AM
Age : 04:57:29.8737818
Computername : CADENZA
I could have also created a custom object using a PowerShell class or even the [PSCustomObject] type accelerator. Using Add-Member makes it easier to perform the operations in-line. I can always refactor later.
Error Handling
You never want to assume the command will always work perfectly. Something will always go wrong.
PS C:\> $r = &$cmd -nobanner HKEY_LOCAL_MACHINE\FOO
The system cannot find the file specified.
PS C:\> $r
Error opening HKLM\foo:
From this test, I can tell that the output of the command is the message stored in $r. The other string The system cannot find the file specified. was written to the host and not the PowerShell pipeline. Since this is a command-line tool, that line is most likely being directed to the console's error stream. If that is true, I can redirect that stream to a text file using old school command techniques.
First, I'll create a temporary file using the New-TemporaryFile command in PowerShell 7.
PS C:\> $errTmp = New-TemporaryFile
I'll redirect the error stream to this file.
PS C:\> $r = &$cmd -nobanner HKEY_LOCAL_MACHINE\FOO 2>$errTmp
The temp file holds the error message.
PS C:\> Get-Content $errTmp
The system cannot find the file specified.
PS C:\>
This is actually a 3 line result, so I'll get rid of the blank lines.
PS C:\> Get-Content $errTmp | where {$_} | Write-Warning
WARNING: The system cannot find the file specified.
It is my responsibility to remove the temporary file.
Remove-Item $errTmp
At this point, I should have enough proof-of-concept code to begin building a PowerShell function.
Test-IsArm
Because I am building a tool around a command-line utility, I need to be able to find it. I could put a copy in a folder in %PATH%. I know that I might run the function from one of my laptops or my desktop. Since the file is available in OneDrive everywhere, I can use that location. However, the path to the native ARM version is different than the x64 version. I need to be able to identify the correct version.
I can quickly test using Get-CimInstance.
(Get-CimInstance Win32_OperatingSystem -Property OSArchitecture).OSArchitecture -match "ARM"