Powershell: Working with the Windows Registry

Here are some tips and trick on how to work on the Windows Registry with Powershell.


Basics

While the terminology of the Windows Registry is somewhat confusing, that’s what we just have to deal with…

$RootKey = "HKLM:\" # = HKEY_LOCAL_MACHINE
$Key     = $RootKey + "SYSTEM\CurrentControlSet\Control\FileSystem\"
$Value   = "LongPathsEnabled"

A value can store data as payload in different types, for example a string (REG_SZ: “Hello, world!”), or a 32-bit unsigned integer (REG_DWORD: 123), or some other format.

To get the item itself, use this:

Get-Item HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem\LongPathsEnabled
Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem\ -Name LongPathsEnabled

Or, to get just the actual data (payload) of a specific value, use this:

(Get-ItemProperty -Path $Key -Name $Value).Value   # Powershell < Version 5.
Get-ItemPropertyValue -Path $Key -Name $Value      # Powershell >= Version 5.

Gotcha: RegEdit vs. Powershell

While trying to automate a few work steps that I did before by hand for a remote computer, I stumbled upon an interesting difference between handling the Registry via the RegEdit program and a Powershell script:

When you run regedit.exe, you will see a User Account Control prompt asking for the administrator credentials (“Do you want to allow this app to make changes to your device?”). If you do not provide a password and do not confirm elevation, the app won’t start.

However, regedit should run as administrator by default when you open Registry Editor while signed in to an administrator account.
https://www.reddit.com/r/PowerShell/comments/13qznnf/weird_registry_permissions_issue/

That means RegEdit takes care of elevating privileges automatically, behind the scenes.

But Powershell does not. So the attemp to access the remote computer’s Registry directly presented two problems:

  1. While the reading of of a Value’s data was possible, the payload was different (i.e. wrong) when compared with RegEdit (and that was also obvious, because the behavior of the computer represented what RegEdit showedd, and not what Powershell returned).
  2. Trying to change the payload via Set-ItemProperty failed with “Requested registry access is not allowed”.

That means, with Powershell, oneself has to take care of getting the elevated privileges to be able to do the same work as one could with RegEdit (given that your user account has indeed these rights for the remote computer…).

Two common approaches for that:

Here’s a short and simple example for the second approach:

$Key = "HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System\"
$Value = "DontDisplayLockedUserId"
$Cred = Get-Credential -UserName $(whoami) -Message "Please enter your password"

# Create a new session to the remote computer (with elevated privileges, if the user account has the permissions):
$Session = New-PSSession ComputerName "client123.example.net" -Credential $Cred

# Run code on the remote client (with hopefully elevated privileges):
Invoke-Command Session $Session ScriptBlock {
    "$Value is currently set to {0}" -f (Get-ItemPropertyValue $Key -Name $Value)
    Set-ItemProperty $Key -Name $Value -Value 1
    "$Value is now set to {0}" -f (Get-ItemPropertyValue $Key -Name $Value)
}