Behind the PowerShell Pipeline logo

Behind the PowerShell Pipeline

Archives
Subscribe
February 3, 2026

Capturing The Registry With A (dot)Net

In this issue:

  • Microsoft.Win32.RegistryKey
    • Opening A Registry Hive
    • Opening A Subkey
    • Accessing Registry Values
  • Get-RegistryKeyData
  • Creating a Registry Tree
  • Summary

When I first started using PowerShell, I was blown away by being able to do this:

PS C:\> cd hklm:
PS HKLM:\> cd '.\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
PS HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion> Get-Item .

    Hive: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT

Name                           Property
----                           --------
CurrentVersion                 SystemRoot                : C:\WINDOWS
                               BaseBuildRevisionNumber   : 1
                               BuildBranch               : ge_release
                               BuildGUID                 : ffffffff-ffff-ffff-ffff-ffffffffffff
                               BuildLab                  : 26100.ge_release.240331-1435
                               BuildLabEx                : 26100.1.amd64fre.ge_release.240331-1435
                               CompositionEditionID      : Enterprise
                               CurrentBuild              : 26200
                               CurrentBuildNumber        : 26200
                               CurrentMajorVersionNumber : 10
                               CurrentMinorVersionNumber : 0
                               CurrentType               : Multiprocessor Free
                               CurrentVersion            : 6.3
                               DisplayVersion            : 25H2
                               ...

I was navigating the Windows Registry like it was a file system! This was stunning. Up until then there were limited scripting and automation options for working with th registry. And certainly nothing as easy as using a PowerShell provider to expose the registry like a file system.

For most registry management tasks, using the PowerShell provider to access HKEY_LOCAL_MACHINE (HKLM) and HKEY_CURRENT_USER (HKCU) is sufficient. Although you need to use PowerShell remoting to access the registry of remote computers, this method is straightforward and effective for many scenarios.

But I like to dig deeper and go behind the scenes. The Registry provider is terrific, but it has limitations and isn't always intuitive. Let's explore the .NET classes that PowerShell uses under the hood to interact with the Windows Registry. I'm not suggesting that this is the best way to work with the registry, but it's a useful skill to have in your toolkit. And as you'll see, you'll need these tools for more advanced registry tasks.

Microsoft.Win32.RegistryKey

The secret ingredient that makes the PowerShell Registry provider work is the Microsoft.Win32.RegistryKey class from the .NET Framework. This class provides methods and properties to interact with registry keys and values. The provider abstracts the complexity of the RegistryKey class, allowing you to navigate and manipulate the registry as if it were a file system.

PS HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion> (Get-Item .).GetType().FullName
Microsoft.Win32.RegistryKey

However, more advanced and experienced PowerShell users may want to work directly with the RegistryKey class for more control and flexibility.

Let's use Get-TypeMember from the PSScriptTools module to peek at the members of the RegistryKey class.

Microsoft.Win32.RegistryKey class
figure 1

The class has a static method called OpenBaseKey that allows you to open a registry hive.

PS C:\> [Microsoft.Win32.RegistryKey]::OpenBaseKey.OverloadDefinitions
static Microsoft.Win32.RegistryKey OpenBaseKey(Microsoft.Win32.RegistryHive hKey, Microsoft.Win32.RegistryView view)

The method takes two parameters: a RegistryHive enumeration value that specifies the hive to open (e.g., HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, etc.) and a RegistryView enumeration value that specifies the view of the registry (e.g., Default, Registry32, or Registry64). You can see the expected object types so I can explore those as well.

PS C:\> Get-TypeMember Microsoft.Win32.RegistryHive

   Type: Microsoft.Win32.RegistryHive

Name            MemberType ResultType                   IsStatic IsEnum
----            ---------- ----------                   -------- ------
ClassesRoot     Field      Microsoft.Win32.RegistryHive     True
CurrentConfig   Field      Microsoft.Win32.RegistryHive     True
CurrentUser     Field      Microsoft.Win32.RegistryHive     True
LocalMachine    Field      Microsoft.Win32.RegistryHive     True
PerformanceData Field      Microsoft.Win32.RegistryHive     True
Users           Field      Microsoft.Win32.RegistryHive     True
GetType         Method     Type
HasFlag         Method     Boolean
ToString        Method     String

PS C:\> Get-TypeMember Microsoft.Win32.RegistryView

   Type: Microsoft.Win32.RegistryView

Name       MemberType ResultType                   IsStatic IsEnum
----       ---------- ----------                   -------- ------
Default    Field      Microsoft.Win32.RegistryView     True
Registry32 Field      Microsoft.Win32.RegistryView     True
Registry64 Field      Microsoft.Win32.RegistryView     True
GetType    Method     Type
HasFlag    Method     Boolean
ToString   Method     String

Any of the fields should be a valid value.

> You might see different values in Windows PowerShell. I am using PowerShell 7.5.4.

Opening A Registry Hive

I'm going to open the HKEY_LOCAL_MACHINE hive using the OpenBaseKey method.

$regBase = [Microsoft.Win32.RegistryKey]::OpenBaseKey('localMachine', 'default')

The object is relatively simple.

PS C:\> $regBase | Select *

SubKeyCount : 8
View        : Default
Handle      : Microsoft.Win32.SafeHandles.SafeRegistryHandle
ValueCount  : 1
Name        : HKEY_LOCAL_MACHINE

I can use the object's methods to list the immediate subkeys.

PS C:\> $regBase.GetSubKeyNames()
BCD00000000
COMPONENTS
HARDWARE
SAM
SCHEMA
SECURITY
SOFTWARE
SYSTEM

> You will encounter the same permission limitations as you would with any other registry tool.

Opening A Subkey

Let's open a subkey. I can specify it as a path.

$key = 'software\microsoft\Windows NT\CurrentVersion'
$cv = $regBase.OpenSubKey($key)

$cv is also a RegistryKey object.

Accessing Registry Values

The registry values are the item properties you work with in the Registry provider. You can use the GetValueNames method to list the value names.

PS C:\> $cv.GetValueNames()
SystemRoot
BaseBuildRevisionNumber
BuildBranch
BuildGUID
BuildLab
...

Once you know the value name, you can retrieve the value using the GetValue method.

PS C:\> $cv.GetValue('RegisteredOwner')
Jeff Hicks
Want to read the full issue?
GitHub
Bluesky
LinkedIn
Mastodon
https://jdhitso...
Powered by Buttondown, the easiest way to start and grow your newsletter.