Remote Recursive Registry script (Part 1) [Update 12/13/2014]

Posted: November 29, 2014 in General, Uncategorized
Tags: , , ,

I know it has been several months since my last post, but I’ve been steadily increasing my powershell knowledge, and creating scripts that I can’t make public.

Recently, I had a need to make some registry changes by script. I found tons of examples on how to do this, however, none of them really seemed to address what happens if the registry key is not there.  Eventually, I did find one that did, however, the way it was written, it only tolerated 1 level missing. So, if you needed to create a registry path several levels deep that didn’t exist, it did not provide a way to do this.

This script is going to be a reusable tool that I will put in my toolkit, so the first few lines are my “typical” advanced function lines.

function Set-DRFRemoteRegistry
		[Parameter(Position = 0, Mandatory = $false, ValueFromPipeline=True, ValueFromPipelinebyName=$true)]
		[string[]]$ComputerName = $Env:COMPUTERNAME,

		[Parameter(Position = 1, Mandatory = $true)]
		[ValidateSet("ClassesRoot", "CurrentConfig", "CurrentUser", "DynData", "LocalMachine", "PerformanceData", "Users")]
		[string]$Hive = "LocalMachine",

		[Parameter(Position = 2, Mandatory = $true)]

		[Parameter(Position = 3, Mandatory = $true)]

		[Parameter(Position = 4, Mandatory = $true)]

		[Parameter(Position = 5, Mandatory = $true)]
		[ValidateSet("String", "ExpandString", "Binary", "DWord", "MultiString", "QWord", "Default")]

		[Parameter(Position = 6, Mandatory = $false)]

Most of this is pretty self explanatory.  I’m defining the function, using an approved verb set, and the noun starts with my initials to keep it unique – drf, and a descriptive name – remoteregistry.  And then of course the open brace and then the [CmdletBinding()].  CmdLetBinding tells powershell that the function should act like part of the shell, and to support some of the common parameters (Debug,ErrorAction,ErrorVariable,OutVariable,OutBuffer,Verbose,WarningAction,WarningVariable).  CmdletBinding has some parameters you can put inside the parenthesis, but I am not covering those here.

The next part is to setup my parameters.  Since I’m creating registry values.. I need several pieces of information

  • What Computer(s)?
  • What Registry Hive?
  • What Registry Path?
  • What Registry Value name?
  • What’s the data in the Value?
  • What’s the data type for that Value?
  • Do I need to build the entire path? (the real focus of this article)

Inside the Param( ) set, each parameter consists of a [Parameter()] tag with options inside the ( ) marks, a variable name for the parameter.

And here is the list of parameters inside of the Param( ) block

[Parameter(Position = 0, Mandatory = $false, ValueFromPipeline=True, ValueFromPipelinebyName=$true)]
[string[]]$ComputerName = $Env:COMPUTERNAME,

The first parameter is the name of the computer to apply the registry value to.  The first option is the Position parameter.  This tells Powershell that if the function is run and the parameter names are not specfied, then the first position (0) is going to be the ComputerName.  It’s typically bad form to not specify the parameter names, but in a pinch, this lets you do that.  Without it, the function will ignore that parameter.

The second option is Mandatory.  This option is pretty self-explanatory.  If a Mandatory = $true is specified, then the function will not run if that parameter is provided – it will prompt the user to provide a value if it is not provided.

The next two options ValueFromPipeline and ValueFromPipelineByPropertyName. allow the function to accept input from the pipeline.  They are different, and the difference is subtle.  I’d love to say I understand what the real difference is, but I don’t.

On the next line, I’m setting a .Net PropertyType accelerator – [string].  When you use this, then the variable immediately following it is forced to be a string type.  But, notice the interior brackets – [string[]].  These brackets tell powershell that it should expect to have multiple values for that particular parameter.  It’s also called an accelerator because it allows direct access to any of the .net properties of a string.

Next, we have another bracketed option – [Alias(“CN”)].  This line tells powershell that you have defined an alias to use inline for your named parameter.  So, instead of using the full variable name ($ComputerName), you can simply use -CN.  You can have mutliple aliases separated by commas inside the parenthesis.

Then we have the variable name ($ComputerName in this case), followed by an equals sign and a value.  This assignment (=) tells it that if the parameter is not supplied by the user, then this should be assumed to be the default. So, we are telling it that the $ComputerName should default to the local computername (by environment variable) if one is not supplied.

The next parameter is structured very similarly:

[Parameter(Position = 1, Mandatory = $true)]
[ValidateSet("ClassesRoot", "CurrentConfig", "CurrentUser", "DynData", "LocalMachine", "PerformanceData", "Users")]
[string]$Hive = "LocalMachine",

It is very similar to the first parameter, except we gave it the next position, and we use [ValidateSet()].

  • [ValidateSet()] This option allows you to force the parameter to only accept a value from your comma separated list.  It also gives the ability for powershell to know what the acceptable values are, so that when you type in the command, and enter the parameter, you can hit Tab and have the value filled in.  Powershell editors also use this to provide a form of intellisense.

We’ve pre-supplied the list of values that can be accepted.  These values are the names of the registry hives that are used by several .Net functions.  Most of the value names are pretty straight forward, but just in case:

  • “ClassesRoot” – this represents HKEY_CLASSES_ROOT
  • “CurrentConfig” – this represents HKEY_CURRENT_CONFIG
  • “CurrentUser” – this represents HKEY_CURRENT_USER
  • “DynData” – this represents HKEY_DYNAMIC_DATA
  • “LocalMachine” – this represents HKEY_LOCAL_MACHINE
  • “PerformanceData – this represents HKEY_PERFORMANCE_DATA
  • “Users” – this represents HKEY_USERS

There are plenty of other validation sets and options that can be used, but they are not part of this article.

Next is the parameter for the Registry key path. Since this is separate from the Hive, it is spelled out in a normal path fashion, such as Software\Microsoft\Windows. If the path has spaces in it, you’ll need to use quotes around the path. Such as ‘Software\Microsoft\Windows NT\CurrentVersion’. (And since it is powershell, we use single quotes when possible, since it tells powershell that there are no replaceable variables in the string. If there were going to be, we would use double quotes instead.

[Parameter(Position = 2, Mandatory = $true)]

Next we have parameters 3 & 4

[Parameter(Position = 3, Mandatory = $true)]

[Parameter(Position = 4, Mandatory = $true)]

This covers the name of the registry value to create and the data for the value. However, notice that the $ValueData parameter does not have a type accelerator. This is due to the fact that we don’t know exactly what kind of data we’ll be using, such as binary data, dwords, etc.

There is also another useful parameter type – [Switch]. This parameter either takes effect, or doesn’t depending on whether it exists.  In this case, I am using it to indicate force.  For this script, if the switch is present it will mean we forcibly create the full registry key path if it does not exist.

This is a lot of explanation just for the first part of the script, but, Part 2 will have the working body of the script.

Until then..

David Figueroa


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s