Training
Get a free hour of SANS training

Experience SANS training through course previews.

Learn More
Learning Paths
Can't find what you are looking for?

Let us help.

Contact us
Resources
Join the SANS Community

Become a member for instant access to our free resources.

Sign Up
For Organizations
Interested in developing a training plan to fit your organization’s needs?

We're here to help.

Contact Us
Talk with an expert

Month of PowerShell - Working with the Registry

The Windows Registry can be pretty frustrating. That is, until I discovered that you can treat the registry just like the file system in PowerShell.

Authored byJoshua Wright
Joshua Wright

In general, I find working with the Windows Registry pretty frustrating. It's organized like a file system, but not as accessible. That is, until I discovered that you can treat the registry just like the file system in PowerShell. Almost.

If you want the TL/DR version; press End/FN+DownArrow and skip to the bottom of this article for a table summary of commands!

To start, open PowerShell on Windows and run the [code]Get-PSDrive[/code] cmdlet:

PS C:\Users\Sec504> Get-PSDrive

Name           Used (GB)     Free (GB) Provider      Root                                  CurrentLocation
----           ---------     --------- --------      ----                                  ---------------
Alias                                  Alias
C                  29.81         10.19 FileSystem    C:\                                      Users\Sec504
Cert                                   Certificate   \
D                                      FileSystem    D:\
Env                                    Environment
Function                               Function
HKCU                                   Registry      HKEY_CURRENT_USER
HKLM                                   Registry      HKEY_LOCAL_MACHINE
Variable                               Variable
WSMan                                  WSMan

In PowerShell we have PowerShell providers, ".NET programs that provide access to specialized data stores for easier viewing and management." (source: about_Providers) This includes the Windows Registry. We can access all of the registry data by accessing the top-level registry keys HKCU and HKLM (for HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE) as drive letters:

PS C:\Users\Sec504> Set-Location HKLM:
PS HKLM:\>

List Registry Keys and Values

With the [code]HKLM:[/code] and [code]HKCU:[/code] drives, we can list the contents of registry keys using [code]Get-ChildItem[/code]:

PS HKLM:\> Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion


    Hive: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion


Name                           Property
----                           --------
AccountPicture
ActionCenter
AdvertisingInfo                Enabled : 0
App Management
App Paths
AppHost                        EnableWebContentEvaluation : 1
Applets
...

We can also use [code]Set-Location[/code] (e.g., [code]cd[/code]) to change to a working location:

PS HKLM:\> Set-Location HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion
PS HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion> Get-ChildItem


    Hive: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion


Name                           Property
----                           --------
AccountPicture
ActionCenter
AdvertisingInfo                Enabled : 0
App Management
App Paths
AppHost                        EnableWebContentEvaluation : 1
...

When we run [code]Get-ChildItem[/code], we'll see both registry keys and values. If you only want to see subkeys, use [code]Select-Object PSChildName[/code] in the pipeline:

PS HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion> Get-ChildItem | Select-Object PSChildName

PSChildName
-----------
AccountPicture
ActionCenter
AdvertisingInfo
App Management
App Paths
AppHost

If you only want to see values but not sub-keys, use [code]Get-ItemProperty[/code] (using the relative location [code].[/code] or the fully-qualified key location, shown here):

PS HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion> Get-ItemProperty .


ProgramFilesDir          : C:\Program Files
CommonFilesDir           : C:\Program Files\Common Files
ProgramFilesDir (x86)    : C:\Program Files (x86)
CommonFilesDir (x86)     : C:\Program Files (x86)\Common Files
CommonW6432Dir           : C:\Program Files\Common Files
DevicePath               : C:\WINDOWS\inf
MediaPathUnexpanded      : C:\WINDOWS\Media
ProgramFilesPath         : C:\Program Files
ProgramW6432Dir          : C:\Program Files
SM_ConfigureProgramsName : Set Program Access and Defaults
SM_GamesName             : Games
PSPath                   : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion
PSParentPath             : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
PSChildName              : CurrentVersion
PSDrive                  : HKLM
PSProvider               : Microsoft.PowerShell.Core\Registry

PS HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion> Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion


ProgramFilesDir          : C:\Program Files
CommonFilesDir           : C:\Program Files\Common Files
ProgramFilesDir (x86)    : C:\Program Files (x86)
CommonFilesDir (x86)     : C:\Program Files (x86)\Common Files
CommonW6432Dir           : C:\Program Files\Common Files
DevicePath               : C:\WINDOWS\inf
...

If you want to see the value of a specific registry key value, use [code]Get-ItemPropertyValue[/code], specifying both the registry key (as a default argument, or with the [code]-Path[/code] parameter), as well as the registry value name with the [code]-Name[/code] parameter (again in this example I use the relative location [code].[/code] and the fully-qualified location to show how both can be used):

PS HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion> Get-ItemPropertyValue . -Name ProgramFilesDir
C:\Program Files
PS HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion> Get-ItemPropertyValue  HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion -Name ProgramFilesDir
C:\Program Files

Create Registry Keys

Let's take a look at creating registry keys. We'll stick with the non-privileged PowerShell session, and create (then later, remove) a temporary registry key in HKEY_CURRENT_USER. First, change to the [code]HKCU:[/code] drive provider and the [code]SOFTWARE[/code] key, then list the sub-keys:

PS HKLM:\> Set-Location HKCU:\SOFTWARE
PS HKCU:\SOFTWARE> Get-ChildItem | Select-Object -Property PSChildName

PSChildName
-----------
7-Zip
APN PIP
AppDataLow
Bogosoft
Cygwin
Google
Intel
JavaSoft
Local AppWizard-Generated Applications
Microsoft
Monobob2022
...

You can test if a registry key exists using [code]Test-Path[/code]. Let's see how this looks; run [code]Test-Path MyKey[/code]:

PS HKCU:\SOFTWARE> Test-Path MyKey
False

To create the key, use [code]New-Item[/code] with the [code]-Path[/code] and [code]-Name[/code] arguments.

PS HKCU:\SOFTWARE> New-Item -Path . -Name MyKey


    Hive: HKEY_CURRENT_USER\SOFTWARE


Name                           Property
----                           --------
MyKey


PS HKCU:\SOFTWARE> Test-Path MyKey
True

Set a Registry Value

Every registry key has a default value (this is a holdover from the days when a registry key could only hold one value per key. To specify a default value, use [code]New-Item[/code]:

PS HKCU:\SOFTWARE> Set-Item -Path .\MyKey\ -Value "My default key value"
PS HKCU:\SOFTWARE> Get-ItemProperty -Path .\MyKey\


(default)    : My default key value
PSPath       : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\MyKey\
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE
PSChildName  : MyKey
PSDrive      : HKCU
PSProvider   : Microsoft.PowerShell.Core\Registry

To add a new value in the key, use [code]New-ItemProperty[/code] with the [code]-Path[/code], [code]-Name[/code], and [code]-Value[/code] arguments:

PS HKCU:\SOFTWARE> New-ItemProperty -Path .\MyKey\ -Name MyCustomKeyValue -Value "My custom data"


MyCustomKeyValue : My custom data
PSPath           : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\MyKey\
PSParentPath     : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE
PSChildName      : MyKey
PSDrive          : HKCU
PSProvider       : Microsoft.PowerShell.Core\Registry



PS HKCU:\SOFTWARE> Get-ItemProperty -Path .\MyKey\


(default)        : My default key value
MyCustomKeyValue : My custom data
PSPath           : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\MyKey\
PSParentPath     : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE
PSChildName      : MyKey
PSDrive          : HKCU
PSProvider       : Microsoft.PowerShell.Core\Registry

So far, we've only been working with string objects. We can specify other data types, such as the DWORD integer type by adding [code]-PropertyType[/code]:

PS HKCU:\SOFTWARE> New-ItemProperty -Path .\MyKey\ -Name MyCustomKeyValueDWORD -PropertyType DWORD -Value 12345


MyCustomKeyValueDWORD : 12345
PSPath                : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\MyKey\
PSParentPath          : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE
PSChildName           : MyKey
PSDrive               : HKCU
PSProvider            : Microsoft.PowerShell.Core\Registry
PS HKCU:\SOFTWARE> Get-ItemProperty -Path .\MyKey\


(default)             : My default key value
MyCustomKeyValue      : My custom data
MyCustomKeyValueDWORD : 12345
PSPath                : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\MyKey\
PSParentPath          : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE
PSChildName           : MyKey
PSDrive               : HKCU
PSProvider            : Microsoft.PowerShell.Core\Registry

Delete a Registry Value

To delete a value in a registry key, use [code]Remove-ItemProperty[/code]:

PS HKCU:\SOFTWARE> Remove-ItemProperty -Path .\MyKey\ -Name MyCustomKeyValueDWORD
PS HKCU:\SOFTWARE> Get-ItemProperty -Path .\MyKey\


(default)        : My default key value
MyCustomKeyValue : My custom data
PSPath           : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\MyKey\
PSParentPath     : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE
PSChildName      : MyKey
PSDrive          : HKCU
PSProvider       : Microsoft.PowerShell.Core\Registry



PS HKCU:\SOFTWARE> Remove-ItemProperty -Path .\MyKey\ -Name MyCustomKeyValue
PS HKCU:\SOFTWARE> Get-ItemProperty -Path .\MyKey\


(default)    : My default key value
PSPath       : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\MyKey\
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE
PSChildName  : MyKey
PSDrive      : HKCU
PSProvider   : Microsoft.PowerShell.Core\Registry

Excellent!

Delete a Registry Key

To clean up, let's remove the registry key [code]MyKey[/code] with [code]Remove-Item[/code]. I've added the [code]-Confirm[/code] option for safety; you can delete the key without being prompted to confirm by omitting [code]-Confirm[/code].

PS HKCU:\SOFTWARE> Remove-Item .\MyKey\ -Confirm

Confirm
Are you sure you want to perform this action?
Performing the operation "Remove Key" on target "Item: HKEY_CURRENT_USER\SOFTWARE\MyKey\".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): y
PS HKCU:\SOFTWARE>

Search for a Registry Key

Next, let's take a look at the steps to search for a registry key. Let's search for a key named [code]BrowserEmulation[/code] (associated with Microsoft Edge, which everyone will have on their Windows systems).

Unfortunately, not all drive providers support the same parameters. While searching for a file on the file system with [code]Get-ChildItem[/code] is pretty straightforward ([code]Get-ChildItem -Path C:\ -Name mimikatz.exe -Recurse[/code] will find all files with the name [code]mimikatz.exe[/code], for example), this won't work with registry keys:

PS HKCU:\SOFTWARE> Get-ChildItem -Recurse -Path . -Name "BrowserEmulation"
Get-ChildItem : Cannot call method. The provider does not support the use of filters.
At line:1 char:1
+ Get-ChildItem -Recurse -Path . -Name "BrowserEmulation"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotImplemented: (:) [Get-ChildItem], PSNotSupportedException
    + FullyQualifiedErrorId : NotSupported,Microsoft.PowerShell.Commands.GetChildItemCommand

As an alternative, we can perform the recursive search for keys and use the pipeline to filter the results. This is not ideal for performance reasons, but it works reasonably well if you are patient:

PS HKCU:\SOFTWARE> Get-ChildItem -Recurse -Path . | Where-Object -Property Name -Like '*BrowserEmulation*' | Select-Object -Property PSPath

PSPath
------
Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\Microsoft\Internet Explorer\BrowserEmulation
Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\Microsoft\Internet Explorer\BrowserEmulation\LowMic
Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\Microsoft\MicrosoftEdge\BrowserEmulation
Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppContainer\Storage\microsoft.microsoftedge_8wekyb3d8bbwe\MicrosoftEdge\BrowserEmulation
Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppContainer\Storage\microsoft.microsoftedge_8wekyb3d8bbwe\MicrosoftEdge\BrowserEmulat...

Search for a Registry Value Name

If you want to find a registry value by name, we can use a similar [code]Get-ChildItem[/code] command, filtering by the [code]Property[/code] property instead of [code]Name[/code]. For example, to search for a registry value name called [code]LastLogonTime-Machine[/code], use the following command:

PS HKCU:\SOFTWARE> Get-ChildItem -Recurse -Path . | Where-Object -Property Property -EQ 'LastLogonTime-Machine'


    Hive: HKEY_CURRENT_USER\SOFTWARE\Microsoft


Name                           Property
----                           --------
EdgeUpdate                     LastLogonTime-Machine : 133009855555826276

Summary

Here's a summary of the commands we reviewed to access and manipulate the Windows Registry.

TaskCommand
Change location to HKEY_CURRENT_USER[code]Set-Location HKCU:[/code]
Change location to HKEY_LOCAL_MACHINE[code]Set-Location HKLM:[/code]
List registry subkeys and values[code]Get-ChildItem[/code]
List registry subkeys only[code]Get-ChildItem | Select-Object PSChildName[/code]
List registry values only[code]Get-ItemProperty .[/code]
Access the registry data for a specific value[code]Get-ItemPropertyValue[/code] (specify [code]-Path[/code] and [code]-Name[/code])
Test is a registry key exists[code]Test-Path[/code]
Create a registry key[code]New-Item[/code] (specify [code]-Path[/code] and [code]-Name[/code])
Set a default registry key value[code]Set-Item[/code] (specify [code]-Path[/code] and [code]-Value[/code], omitting [code]-Name[/code])
Set a named registry key value[code]Set-Item[/code] (specify [code]-Path[/code], [code]-Value[/code], and [code]-Name[/code])
Delete a registry value[code]Remove-ItemProperty[/code] (specify [code]-Path[/code] and [code]-Name[/code])
Delete a registry key[code]Remove-Item[/code]
Search for a registry key[code]Get-ChildItem -Recurse[/code] (specify [code]-Path[/code] and [code]-Name[/code] where [code]-Name[/code] uses wildcards)
Search for a registry value name[code]Get-ChildItem -Recurse -Path . | Where-Object -Property Property -EQ 'SearchValueName'[/code]

We'll continue to look at how to apply these commands to interrogate and manipulate the registry throughout the

-Joshua Wright

Return to Getting Started With PowerShell

Joshua Wright is the author of SANS SEC504: Hacker Tools, Techniques, and Incident Handling, a faculty fellow for the SANS Institute, and a senior technical director at Counter Hack.

Month of PowerShell - Working with the Registry | SANS Institute