Module of the Week: puppetlabs/registry – Manage the Windows Registry

Purpose Manage the Windows Registry
Module puppetlabs/registry
Puppet Version Puppet 2.7+, Puppet Enterprise 2.5+
Platforms 32 and 64-bit versions of Windows 2003 and later
The puppetlabs/registry module allows Puppet users to manage the Windows Registry. On Windows operating systems, the registry is a database used to store configuration data for applications, drivers, and the operating system. It is analogous to the ‘/etc’ directory found in *nix systems. As such, managing the registry is an essential component of Windows configuration management. The following image of the Registry Editor shows a registry key and various registry values, each of which has a name, type, and data. If you are new to Puppet on Windows, please refer to the Puppet documentation for how to install and run Puppet agents on Windows. You will also need a Puppet master on a non-Windows platform. See the Puppet Enterprise Quickstart Guide for more information

Resource Overview

The registry module introduces two resource types, registry_key and registry_value. These resource types are ensurable, which just means Puppet can ensure the resource is present or absent. See the Puppet glossary for a description of Puppet resource types. Additionally, the registry_value resource type manages the value’s type and data. Puppet supports all of the standard Windows value types, e.g. REG_SZ, REG_EXPAND_SZ, etc. The registry_value resource type can also manage the default registry value for a key, which is simply the value whose name is the empty string. The registry module introduces a defined type, which provides a higher-level abstraction layer for specifying the desired state of registry keys and their values.

Installing the module

Complexity Easy
Installation Time 5 minutes
On the Puppet master, use the Puppet module tool to download the registry module and its dependencies:
# puppet module install puppetlabs/registry
Preparing to install into /etc/puppetlabs/puppet/modules ...
Downloading from http://forge.puppetlabs.com ...
Installing -- do not interrupt ...
/etc/puppetlabs/puppet/modules
└─┬ puppetlabs-registry (v0.1.1)
  └── puppetlabs-registry (v2.3.3)
Alternatively, you can specify your Puppet master’s modulepath in which to install the module:
# puppet module install [--modulepath <path>] puppetlabs/registry
See the Installing Modules section for more information.

Configuring the module

Complexity Easy
Installation Time 5 minutes
Using the Puppet Enterprise Console, assign the registry class to a Windows node or node group. The next time your Windows Puppet agents run, the pluginsync system will download the registry module and its dependencies. Normally, the Puppet agent runs in the background as a Windows service. However, we want to run examples interactively, so let's stop the Puppet agent service. From the Windows Start menu, select "Starting a Command Prompt with Puppet". As described in the documentation, make sure you right-click and select "Run as Administrator" on User Account Control (UAC) systems, so that you run with elevated privileges: Next stop the Puppet agent service:
C:>net stop puppet
The Puppet Agent service is stopping.
The Puppet Agent service was stopped successfully.
Manually trigger a Puppet agent run, which will download the registry and stdlib modules:
C:>puppet agent --onetime
...
info: Retrieving plugin
...
notice: /File[C:/ProgramData/PuppetLabs/puppet/var/lib/puppet/provider/registry_key/registry.rb]/ensure: defined content as '{md5}a994c343128b6331d62d1a09793ace76'
...
info: Loading downloaded plugin C:/ProgramData/PuppetLabs/puppet/var/lib/puppet/provider/registry_key/registry.rb
If Puppet downloads the modules into your user directory, e.g. C:/Users/%USERNAME%/.puppet, then you are not running with elevated privileges.

Example usage

This section describes how to manage different aspects of the registry. We start with the most simple example, a single registry key, and work up from there. Please note: we are not going to walk through modifying any real keys or values in this post, but rather go over all the information you need to know to manage your system. If you have specific things you'd like to see managed, please leave them in the comments and we can try and cover them in a follow-up post.

Registry Keys

Here is a manifest for ensuring a registry key exists:
registry_key { 'hklmsoftwaremykey':
  ensure => present
}
There are a couple of things to note. The path of the key is specified as 'hklmsoftwaremykey'. Puppet accepts either HKEY_LOCAL_MACHINE or HKLM, and since registry key paths are case-insensitive, they are equivalent to hklm. The same is also true for HKEY_CLASSES_ROOT. The path is single-quoted, so it is not necessary to escape the backslashes. However, if you double-quote the path, then the backslashes must be escaped, e.g. "hklm\software\mykey". Now try applying the manifest on the Windows node using the execute option ('-e' or '--execute'):
C:>puppet apply -e "registry_key { 'hklmsoftwaremykey': ensure => present }"
notice: /Stage[main]//Registry_key[hklmsoftwaremykey]/ensure: created
notice: Finished catalog run in 0.11 seconds
Run the example again:
C:>puppet apply -e "registry_key { 'hklmsoftwaremykey': ensure => present }"
notice: Finished catalog run in 0.06 seconds
Note that no changes were made. This is an example of Puppet's idempotency. Also note how simple our manifest is. We didn't have to specify what to do if the registry key already exists. We just used Puppet's declarative language to express the desired state of the registry key, and Puppet made it so. Puppet can also ensure a registry key is absent:
registry_key { 'hklmsoftwaremykey':
  ensure => absent
}
When executed on a Windows node, you should see:
C:>puppet apply -e "registry_key { 'hklmsoftwaremykey': ensure => absent }"
notice: /Stage[main]//Registry_key[hklmsoftwaremykey]/ensure: removed
notice: Finished catalog run in 0.09 seconds
Puppet will not recursively delete a registry key so as to avoid accidentally rendering your system completely useless. So to delete a subtree, each registry key to be deleted must be declared.

Registry Values

Puppet can also manage registry values:
registry_key { 'hklmsoftwaremykey':
  ensure => present,
}

registry_value { 'hklmsoftwaremykeyvalue1':
  type => string,
  data => 'this is a value'
}
The example above declares the registry key ‘mykey’, and a registry value, named 'value1', within that key. The registry value is of type string (REG_SZ) and its data is 'this is a value'. We declare both the registry key and value so that Puppet will create the key if it doesn't exist. If you never want Puppet to create the key, then just omit the registry_key resource from the manifest. For brevity, place the above resources in a manifest, value1.pp. On the Windows node, execute:
C:>puppet apply value1.pp
notice: /Stage[main]//Registry_key[hklmsoftwaremykey]/ensure: created
notice: /Stage[main]//Registry_value[hklmsoftwaremykeyvalue1]/ensure: created
notice: Finished catalog run in 0.11 seconds
Notice that Puppet creates the registry key before the registry value. This occurs because Puppet automatically creates 'requires' relationships between the managed key and each of its values. Similarly, Puppet automatically creates 'requires' relationships between parent and child keys that it manages. See Puppet's documentation on Resource Ordering for more information. Puppet supports the following types of registry values:
  • REG_SZ
  • REG_MULTI_SZ
  • REG_EXPAND_SZ
  • REG_DWORD
  • REG_QWORD
  • REG_BINARY
See the registry_examples.pp manifest for examples of how to use these other registry value types. If you have the puppetlabs-registry module source, you can execute the manifest as:
C:>puppet apply c:modulespuppetlabs-registrytestsregistry_examples.pp
notice: ...[HKLMSoftwareVendor]/ensure: created
notice: ...[HKLMSoftwareVendorBar]/ensure: created
notice: ...[HKLMSoftwareVendorBarvaluedexpand1]/ensure: created
notice: ...[HKLMSoftwareVendorBarvaluearray1]/ensure: created
notice: ...[HKLMSoftwareVendorBarvaluedstring1]/ensure: created
notice: ...[HKLMSoftwareVendorBarvaluearray3]/ensure: created
notice: ...[HKLMSoftwareVendorBarvaluedbinary1]/ensure: created
notice: ...[HKLMSoftwareVendorBarvaluearray2]/ensure: created
notice: ...[HKLMSoftwareVendorBarvalueqword1]/ensure: created
notice: ...[HKLMSoftwareVendorBarvaluedword2]/ensure: created
notice: ...[HKLMSoftwareVendorBarvaluedbinary2]/ensure: created
notice: Finished catalog run in 0.25 seconds

Purging Values

By default, Puppet will only manage registry values that you specify. If a registry key contains other registry values, Puppet will ignore them. This is useful when you only need to ensure the desired state for a specific registry value, e.g. install a license for a third-party application. However, if you want to ensure a registry key only contains the values you specify, and no others, then you can use the optional 'purge_values' parameter on the registry key declaration. As the name implies, 'purge_values' will only purge unmanaged values, but not subkeys. For example, create a manifest, purge.pp, with the following resources:
registry_key { 'hklmsoftwaremykey':
  ensure       => present,
  purge_values => true,
}
registry_value { 'hklmsoftwaremykeyvalue1':
  type         => string,
  data         => 'this is a value'
}
registry_value { 'hklmsoftwaremykeyvalue2':
  type         => dword,
  data         => 0xFFFFFFFF
}
Apply the manifest and you should see:
C:>puppet apply purge.pp
notice: /Stage[main]//Registry_key[hklmsoftwaremykey]/ensure: created
notice: /Stage[main]//Registry_value[hklmsoftwaremykeyvalue1]/ensure: created
notice: /Stage[main]//Registry_value[hklmsoftwaremykeyvalue2]/ensure: created
notice: Finished catalog run in 0.12 seconds
Now remove 'value2' from the manifest and re-apply the manifest. You should see:
C:>puppet apply purge.pp
notice: /Registry_value[hklmsoftwaremykeyvalue2]/ensure: removed
notice: Finished catalog run in 0.11 seconds

Defined Type

The registry module includes a 'registry::value' defined type. Let's rewrite the value1.pp manifest as:
registry::value { 'value1':
  key  => 'hklmsoftwaremykey',
  data => 'this is a value',
}
The defined type defaults to REG_SZ (string), but you can specify other types explicitly:
registry::value { 'value2':
  key  => 'hklmsoftwaremykey',
  type => binary,
  data => '00 01 02 03',
}
Note the defined type is declared using 'registry::value' syntax whereas the resource is declared using 'registry_value'. The defined type simplifies the process for declaring registry values by automatically declaring the registry key associated with the value(s), defaulting the value of the `type` property to 'string', and providing a cleaner interface for managing default values as we'll see below.

Default Values

Every registry key has a default value, whose name is the empty string. Puppet can manage default values in a manifest as:
registry_value { 'hklmsoftwaremykey\':
  type => string,
  data => 'this is the default value'
}
A backslash preceding a single-quote escapes the single-quote, so we have to escape the backslash. While this syntax works, it is less than optimal. Instead, the defined type provides a cleaner syntax for managing default values:
registry::value { '':
  key => 'hklmsoftwaremykey',
  data => 'this is the default value',
}

Registry Redirection

64-bit versions of Windows contain a Windows on Windows subsystem responsible for redirecting file and registry access based on the architecture of the calling process. In general, applications access the logical view that corresponds to their architecture, i.e. 64-bit applications access the 64-bit view; 32-bit applications, the 32-bit view. This is done so that both 32 and 64-bit applications can coexist on the same 64-bit OS. Puppet always accesses the native 64-bit registry view on 64-bit OS's. However, there may be situations where you want to manage keys/values in the 32-bit view. For example, create the following manifest, wow64.pp:
registry_key { '32:hklmsoftwaremykey':
  ensure       => present,
  purge_values => true,
}
registry_value { '32:hklmsoftwaremykeyvalue1':
  type => string,
  data => 'this is a value'
}
Apply the manifest:
C:>puppet apply wow64.pp
/Stage[main]//Registry_key[32:hklmsoftwaremykey]/ensure: created
/Stage[main]//Registry_value[32:hklmsoftwaremykeyvalue1]/ensure: created
And the appropriate key and value are created in HKLMSoftwareWow6432Nodemykey: In order to create manifests that work correctly on both 32 and 64-bit versions of Windows, you will likely need to use the 'architecture' fact in your manifest, which will either be 'x86' or 'x64' respectively. Make sure you are using facter 1.6.10 or later. For example, if you need to manage the registry settings for a 32-bit COM server on both 32 and 64-bit versions of Windows, you could add the following to your manifest:
prefix = ''
if $::architecture == 'x64'
  $prefix = '32:'
}

registry_key { "${prefix}hkcr\clsid\":
  ensure => present,
}

Conclusion

The registry module, when combined with Puppet's declarative syntax, makes it easy to manage registry keys and values. The module's ability to manage default values, purge unwanted values, and manage registry redirection on a per-key and value basis satisfy real world configuration management requirements. We welcome recommendations and contributions from our community to enhance this module. Learn More:
Puppet sites use proprietary and third-party cookies. By using our sites, you agree to our cookie policy.