Registry Cmdlets: Working with the Registry

Summary: Richard Siddaway investigates how to use CIM to manage the registry.

Honorary Scripting Guy, Richard Siddaway, here filling in for my good friend The Scripting Guy. Today, I’m starting a series about registry cmdlets by investigating how to work with the registry.

The bad news is that there aren’t any cmdlets for working with the registry. There’s a Registry provider, which means you can use the Item and ItemProperty cmdlets to manage the local registry—but there aren’t any specific registry cmdlets associated with the provider.

The good news is that we can adopt the approach that many teams at Microsoft have taken and create our own by using cmdlet definition XML (CDXML). A Common Information Model (CIM) class is wrapped in some fairly simple XML and published as a Windows PowerShell module. If you look in the Modules folder on a computer running Windows 8.1, Windows 8, Windows Server 2012 R2, or Windows Server 2012, you will find many files with a CDXML extension:

Get-ChildItem -Path C:WindowsSystem32WindowsPowerShellv1.0Modules -Filter *.CDXML -Recurse

These files are a great resource for figuring out how CDXML should be constructed. Other useful resources include:

By the end of this series, you will have a Registry module that will make working with the registry much easier, and you will have learned how to use CDXML so that you can create other modules based on your favorite CIM classes.

First though, we should have a quick recap of using CIM to work with the registry.

Note Although there is a technical difference between CIM and WMI, I will be using them interchangeably, which seems to be common practice.

The registry is accessed through the StdRegProv class. You can examine the class like this:

Get-CimClass -Namespace rootcimv2 -ClassName StdRegProv

  NameSpace: ROOT/cimv2

CimClassName            CimClassMethods   CimClassProperties

————            —————   ——————

StdRegProv             {CreateKey, Delet… {}

The class is also available in the rootdefault namespace. This is the only option if you are running Windows XP or Windows Server 2003. These versions are no longer supported, so we’ll use the rootcimv2 namespace for the remainder of the series. If you want to check if the classes are the same, you can examine the rootdefault version like this:

Get-CimClass -Namespace rootdefault -ClassName StdRegProv

When you look at the StdRegProv class, the first thing you notice is that it has no properties. The class provides methods only. To drill into the methods:

$class = Get-CimClass -Namespace rootcimv2 -ClassName StdRegProv

$class.CimClassMethods | select Name























As shown here, all the methods are static:

£> $class.CimClassMethods[“GetSTRINGvalue”] | Format-List

Name    : GetStringValue

ReturnType : UInt32

Parameters : {hDefKey, sSubKeyName, sValueName, sValue}

Qualifiers : {implemented, static}

This means that you don’t need an instance of the class to work with—you can simply use the methods. The parameters for these methods are relatively straightforward:

£> $class.CimClassMethods[“GetSTRINGvalue”].Parameters

Name               CimType Qualifiers

—-                        ——- ———-

hDefKey                  UInt32 {ID, IN}

sSubKeyName        String {ID, IN}

sValueName            String {ID, in}

sValue                      String {ID, out}

This is where we meet the first nasty bit. The hdefkey parameter defines the registry hive you want to work with. It’s an unsigned integer that can take the following values:

HKEY_CLASSES_ROOT = 2147483648 (0x80000000)

HKEY_CURRENT_USER = 2147483649 (0x80000001)

HKEY_LOCAL_MACHINE = 2147483650 (0x80000002)

HKEY_USERS = 2147483651 (0x80000003)

HKEY_CURRENT_CONFIG = 2147483653 (0x80000005)

HKEY_DYN_DATA = 2147483654 (0x80000006)

This list shows the hive and the related unsigned integer as a decimal and hexadecimal number. I have found that it’s easiest to define these values as variables. For instance, to work with the HKEY_LOCAL_MACHINE hive, use:

[uint32]$hklm = 2147483650

Let’s look at a little Windows PowerShell history for a moment…

When Windows PowerShell 1.0 launched, it immediately gave us a way to work with WMI (Get-WmiObject). That was a huge step forward from using VBScript. Unfortunately, we couldn’t use the StdRegProv class directly because of its static methods. The answer was to use the [wmiclass] type accelerator:

$reg = [wmiclass]”\.rootcimv2:StdRegprov”

Then you can use Get-Member like this:

$reg | Get-Member

Now you’ll see an object from the System.Management.ManagementClass:


I tend to use variables for things like registry keys and values because it makes my code reusable. A couple of relatively safe values to use are:

$subkey = “SOFTWAREMicrosoftInternet Explorer”

$value = “Version”

You can then call a method on the class:

$reg.GetSTRINGvalue($hklm, $subkey, $value)

The important parts of the results are:

ReturnValue   : 0

sValue      : 9.11.9600.17126

ReturnValue is the return code. A value of 0 in the ReturnValue is good. Anything else is bad, and could be very bad. Finding what the return code means can be difficult, but some information is available if you search WMI return values.

The sValue property holds the return value you want. You can access it directly by using standard techniques:

$reg.GetSTRINGvalue($hklm, $subkey, $value) | select -ExpandProperty sValue


($reg.GetSTRINGvalue($hklm, $subkey, $value)).sValue

This technique is still valid and works with the latest versions of Windows PowerShell. However, working with the registry became much easier in Windows PowerShell 2.0 when Invoke-WmiMethod joined the game. Our registry access code became:

Invoke-WmiMethod -Namespace rootcimv2 -Class StdRegProv -Name GetSTRINGvalue -ArgumentList $hklm, $subkey, $value

However, life is never straightforward…a bit of a problem dropped into our laps. To explain, I need to create a registry key to work with. I can use the $reg object that I created earlier:

$newkey = “SOFTWAREHSGtest”

$reg.CreateKey($hklm, $newkey)

And let’s add a value:

$newname = ‘Date’

$newvalue = ‘June 2013’

$reg.SetSTRINGvalue($hklm, $newkey, $newname, $newvalue)

And finally, let’s test that it’s created correctly:

$reg.GetSTRINGvalue($hklm, $newkey, $newname)

The truncated output shows:

ReturnValue      : 0

sValue           : June 2013

Oops! This where I realize that I’ve used the wrong data, so now I need to modify the data:

$newvalue = ‘June 2014’

And for a change, I’ll use Invoke-WmiMethod:

Invoke-WmiMethod -Namespace rootcimv2 -Class StdRegProv -Name SetSTRINGvalue $hklm, $newkey, $newname, $newvalue

A return code of 0 indicates that it worked. But let’s assume I’m a bit paranoid and I want to check the data:

$reg.GetSTRINGvalue($hklm, $newkey, $newname)

What I get is:

ReturnValue   : 0

sValue      : June 2013

In reality, the value hasn’t been changed. This isn’t a Windows PowerShell issue. It’s related to the underlying .NET classes. It turns out that when you are using Invoke-WmiMethod, the order of the arguments matters. The cmdlet expects them in alphabetical order, not the order the documentation shows (which is the order that you’d use if using the [wmiclass] approach).

This problem will be most noticeable if the arguments are different data types. You get a nice big juicy error message that states you have a type mismatch: code 2147749893. The quick way to check the correct order of arguments is to use Get-CimClass:

$class = Get-CimClass -Namespace rootcimv2 -ClassName StdRegProv


Examining the Name of the parameters shows this:







Let’s retry it in that order:

Invoke-WmiMethod -Namespace rootcimv2 -Class StdRegProv -Name SetSTRINGvalue $hklm, $newkey, $newvalue, $newname

$reg.GetSTRINGvalue($hklm, $newkey, $newname)

And it works.

One way to avoid this confusion is to use the CIM cmdlets, which were introduced in Windows PowerShell 3.0. The problem goes away because you have to give argument name and value pairs:

To set data:

$newvalue = ‘June 2015’

Invoke-CimMethod -Namespace rootcimv2 -ClassName StdRegProv -MethodName SetSTRINGvalue -Arguments @{hDefKey=$hklm; sSubKeyName=$newkey; sValueName=$newname; sValue=$newvalue}

And to read data:

Invoke-CimMethod -Namespace rootcimv2 -ClassName StdRegProv -MethodName GetSTRINGvalue -Arguments @{hDefKey=$hklm; sSubKeyName=$newkey; sValueName=$newname}

This still leaves us with a lot of typing. Wouldn’t it be better if we could do this:

Set-RegistrySTRING -Hive HKLM -SubKey $newkey -ValueName $newname -Value ‘April 2015’

Get-RegistrySTRING -Hive HKLM -SubKey $newkey -ValueName $newname

These are cmdlets from the module that I’m going to show you how to create in the next few posts, but for now I need to clean up my registry:

Remove-RegistryKey -Hive HKLM -SubKey $newkey

Bye for now. Next time, we’ll start digging into how we can use CDXML to create registry cmdlets.


Richard Siddaway is based out of the UK. He spends his time automating anything and everything, for Kelway, Ltd. A 7-year Windows PowerShell MVP, Richard is a prolific blogger, mainly about Windows PowerShell (see Richard Siddaway’s Blog). Richard has been a director at since the inception of that organization, and he is a frequent speaker at Windows PowerShell user groups and conferences. He has written a number of books: PowerShell in Practice, PowerShell and WMI, PowerShell in Depth (co-author), PowerShell Dive (co-editor), and Learn Active Directory Management in a Month of Lunches, which features lots of Windows PowerShell. All of the books are available from Manning Publications.

We invite you to follow The Scripting Guys on Twitter and Facebook. If you have any questions, send an email to The Scripting Guys at, or post your questions on the Official Scripting Guys Forum. Until then, remember eat your cmdlets every day with a dash of creativity.

Richard Siddaway, Windows PowerShell MVP and Honorary Scripting Guy

Comments (1)

  1. Great article! While I didn’t write a cool cdxml module like you did in the second part I was motivated to write a regular powershell module for working with the registry.

Skip to main content