class Chef::Win32::Registry

Attributes

architecture[R]
run_context[RW]

Public Class Methods

new(run_context = nil, user_architecture = :machine) click to toggle source
# File lib/chef/win32/registry.rb, line 46
def initialize(run_context = nil, user_architecture = :machine)
  @run_context = run_context
  self.architecture = user_architecture
end

Public Instance Methods

architecture=(user_architecture) click to toggle source
# File lib/chef/win32/registry.rb, line 51
def architecture=(user_architecture)
  @architecture = user_architecture.to_sym
  assert_architecture!
end
create_key(key_path, recursive) click to toggle source
# File lib/chef/win32/registry.rb, line 107
def create_key(key_path, recursive)
  Chef::Log.trace("Creating registry key #{key_path}")
  if keys_missing?(key_path)
    if recursive == true
      Chef::Log.trace("Registry key #{key_path} has missing subkeys, and recursive specified, creating them....")
      create_missing(key_path)
    else
      raise Chef::Exceptions::Win32RegNoRecursive, "Registry key #{key_path} has missing subkeys, and recursive not specified"
    end
  end
  if key_exists?(key_path)
    Chef::Log.trace("Registry key #{key_path} already exists, doing nothing")
  else
    hive, key = get_hive_and_key(key_path)
    hive.create(key, ::Win32::Registry::KEY_WRITE | registry_system_architecture)
    Chef::Log.trace("Registry key #{key_path} created")
  end
  true
end
data_exists!(key_path, value) click to toggle source
# File lib/chef/win32/registry.rb, line 236
def data_exists!(key_path, value)
  unless data_exists?(key_path, value)
    raise Chef::Exceptions::Win32RegDataMissing, "Registry key #{key_path} has no value named #{value[:name]}, containing type #{value[:type]} and data #{value[:data]}"
  end

  true
end
data_exists?(key_path, value) click to toggle source
# File lib/chef/win32/registry.rb, line 213
def data_exists?(key_path, value)
  key_exists!(key_path)
  hive, key = get_hive_and_key(key_path)
  hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg|
    reg.each do |val_name, val_type, val_data|
      if safely_downcase(val_name) == safely_downcase(value[:name]) &&
          val_type == get_type_from_name(value[:type]) &&
          val_data == value[:data]
        return true
      end
    end
  end
  false
end
delete_key(key_path, recursive) click to toggle source
# File lib/chef/win32/registry.rb, line 127
def delete_key(key_path, recursive)
  Chef::Log.trace("Deleting registry key #{key_path}")
  unless key_exists?(key_path)
    Chef::Log.trace("Registry key #{key_path}, does not exist, not deleting")
    return true
  end
  if has_subkeys?(key_path) && !recursive
    raise Chef::Exceptions::Win32RegNoRecursive, "Registry key #{key_path} has subkeys, and recursive not specified"
  end

  hive, key_including_parent = get_hive_and_key(key_path)
  # key_including_parent: Software\\Root\\Branch\\Fruit
  # key => Fruit
  # key_parent => Software\\Root\\Branch
  key_parts = key_including_parent.split("\\")
  key = key_parts.pop
  key_parent = key_parts.join("\\")
  hive.open(key_parent, ::Win32::Registry::KEY_WRITE | registry_system_architecture) do |reg|
    reg.delete_key(key, recursive)
  end
  Chef::Log.trace("Registry key #{key_path} deleted")
  true
end
delete_value(key_path, value) click to toggle source
# File lib/chef/win32/registry.rb, line 89
def delete_value(key_path, value)
  Chef::Log.trace("Deleting value #{value[:name]} from registry key #{key_path}")
  if value_exists?(key_path, value)
    begin
      hive, key = get_hive_and_key(key_path)
    rescue Chef::Exceptions::Win32RegKeyMissing
      return true
    end
    hive.open(key, ::Win32::Registry::KEY_SET_VALUE | registry_system_architecture) do |reg|
      reg.delete_value(value[:name])
      Chef::Log.trace("Deleted value #{value[:name]} from registry key #{key_path}")
    end
  else
    Chef::Log.trace("Value #{value[:name]} in registry key #{key_path} does not exist, not updated")
  end
  true
end
get_name_from_type(val_class) click to toggle source
# File lib/chef/win32/registry.rb, line 277
def get_name_from_type(val_class)
  _name_type_map[val_class]
end
get_subkeys(key_path) click to toggle source
# File lib/chef/win32/registry.rb, line 188
def get_subkeys(key_path)
  subkeys = []
  key_exists!(key_path)
  hive, key = get_hive_and_key(key_path)
  hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg|
    reg.each_key { |current_key| subkeys << current_key }
  end
  subkeys
end
get_type_from_name(val_type) click to toggle source
# File lib/chef/win32/registry.rb, line 273
def get_type_from_name(val_type)
  _type_name_map[val_type]
end
get_values(key_path) click to toggle source
# File lib/chef/win32/registry.rb, line 56
def get_values(key_path)
  hive, key = get_hive_and_key(key_path)
  key_exists!(key_path)
  values = hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg|
    reg.map { |name, type, data| { name: name, type: get_name_from_type(type), data: data } }
  end
end
has_subkeys?(key_path) click to toggle source
# File lib/chef/win32/registry.rb, line 179
def has_subkeys?(key_path)
  key_exists!(key_path)
  hive, key = get_hive_and_key(key_path)
  hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg|
    reg.each_key { |key| return true }
  end
  false
end
hive_exists?(key_path) click to toggle source
# File lib/chef/win32/registry.rb, line 170
def hive_exists?(key_path)
  begin
    hive, key = get_hive_and_key(key_path)
  rescue Chef::Exceptions::Win32RegHiveMissing => e
    return false
  end
  true
end
key_exists!(key_path) click to toggle source
# File lib/chef/win32/registry.rb, line 162
def key_exists!(key_path)
  unless key_exists?(key_path)
    raise Chef::Exceptions::Win32RegKeyMissing, "Registry key #{key_path} does not exist"
  end

  true
end
key_exists?(key_path) click to toggle source
# File lib/chef/win32/registry.rb, line 151
def key_exists?(key_path)
  hive, key = get_hive_and_key(key_path)
  begin
    hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |current_key|
      return true
    end
  rescue ::Win32::Registry::Error => e
    false
  end
end
keys_missing?(key_path) click to toggle source
# File lib/chef/win32/registry.rb, line 266
def keys_missing?(key_path)
  missing_key_arr = key_path.split("\\")
  missing_key_arr.pop
  key = missing_key_arr.join("\\")
  !key_exists?(key)
end
registry_system_architecture() click to toggle source

32-bit chef clients running on 64-bit machines will default to reading the 64-bit registry

# File lib/chef/win32/registry.rb, line 199
def registry_system_architecture
  applied_arch = ( architecture == :machine ) ? machine_architecture : architecture
  ( applied_arch == :x86_64 ) ? 0x0100 : 0x0200
end
set_value(key_path, value) click to toggle source
# File lib/chef/win32/registry.rb, line 64
def set_value(key_path, value)
  data = value[:data]
  data = data.to_s if value[:type] == :string
  Chef::Log.trace("Updating value #{value[:name]} in registry key #{key_path} with type #{value[:type]} and data #{data}")
  key_exists!(key_path)
  hive, key = get_hive_and_key(key_path)
  if value_exists?(key_path, value)
    if data_exists?(key_path, value)
      Chef::Log.trace("Value #{value[:name]} in registry key #{key_path} already had those values, not updated")
      return false
    else
      hive.open(key, ::Win32::Registry::KEY_SET_VALUE | ::Win32::Registry::KEY_QUERY_VALUE | registry_system_architecture) do |reg|
        reg.write(value[:name], get_type_from_name(value[:type]), data)
      end
      Chef::Log.trace("Value #{value[:name]} in registry key #{key_path} updated")
    end
  else
    hive.open(key, ::Win32::Registry::KEY_SET_VALUE | ::Win32::Registry::KEY_QUERY_VALUE | registry_system_architecture) do |reg|
      reg.write(value[:name], get_type_from_name(value[:type]), data)
    end
    Chef::Log.trace("Value #{value[:name]} in registry key #{key_path} created")
  end
  true
end
type_matches!(key_path, value) click to toggle source
# File lib/chef/win32/registry.rb, line 260
def type_matches!(key_path, value)
  unless type_matches?(key_path, value)
    raise Chef::Exceptions::Win32RegTypesMismatch, "Registry key #{key_path} has a value #{value[:name]} with a type that is not #{value[:type]}"
  end
end
type_matches?(key_path, value) click to toggle source
# File lib/chef/win32/registry.rb, line 244
def type_matches?(key_path, value)
  value_exists!(key_path, value)
  hive, key = get_hive_and_key(key_path)
  hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg|
    reg.each do |val_name, val_type|
      if val_name == value[:name]
        type_new = get_type_from_name(value[:type])
        if val_type == type_new
          return true
        end
      end
    end
  end
  false
end
value_exists!(key_path, value) click to toggle source
# File lib/chef/win32/registry.rb, line 228
def value_exists!(key_path, value)
  unless value_exists?(key_path, value)
    raise Chef::Exceptions::Win32RegValueMissing, "Registry key #{key_path} has no value named #{value[:name]}"
  end

  true
end
value_exists?(key_path, value) click to toggle source
# File lib/chef/win32/registry.rb, line 204
def value_exists?(key_path, value)
  key_exists!(key_path)
  hive, key = get_hive_and_key(key_path)
  hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg|
    return true if reg.any? { |val| safely_downcase(val) == safely_downcase(value[:name]) }
  end
  false
end

Private Instance Methods

_name_type_map() click to toggle source
# File lib/chef/win32/registry.rb, line 344
def _name_type_map
  @_name_type_map ||= _type_name_map.invert
end
_type_name_map() click to toggle source
# File lib/chef/win32/registry.rb, line 332
def _type_name_map
  {
    binary: ::Win32::Registry::REG_BINARY,
    string: ::Win32::Registry::REG_SZ,
    multi_string: ::Win32::Registry::REG_MULTI_SZ,
    expand_string: ::Win32::Registry::REG_EXPAND_SZ,
    dword: ::Win32::Registry::REG_DWORD,
    dword_big_endian: ::Win32::Registry::REG_DWORD_BIG_ENDIAN,
    qword: ::Win32::Registry::REG_QWORD,
  }
end
assert_architecture!() click to toggle source
# File lib/chef/win32/registry.rb, line 303
def assert_architecture!
  if machine_architecture == :i386 && architecture == :x86_64
    raise Chef::Exceptions::Win32RegArchitectureIncorrect, "cannot access 64-bit registry on a 32-bit windows instance"
  end
end
create_missing(key_path) click to toggle source
# File lib/chef/win32/registry.rb, line 360
def create_missing(key_path)
  missing_key_arr = key_path.split("\\")
  hivename = missing_key_arr.shift
  missing_key_arr.pop
  existing_key_path = hivename
  hive, key = get_hive_and_key(key_path)
  missing_key_arr.each do |intermediate_key|
    existing_key_path = existing_key_path << "\\" << intermediate_key
    unless key_exists?(existing_key_path)
      Chef::Log.trace("Recursively creating registry key #{existing_key_path}")
      hive.create(get_key(existing_key_path), ::Win32::Registry::KEY_ALL_ACCESS | registry_system_architecture)
    end
  end
end
get_hive_and_key(path) click to toggle source
# File lib/chef/win32/registry.rb, line 309
def get_hive_and_key(path)
  reg_path = path.split("\\")
  hive_name = reg_path.shift
  key = reg_path.join("\\")

  hive = {
    "HKLM" => ::Win32::Registry::HKEY_LOCAL_MACHINE,
    "HKEY_LOCAL_MACHINE" => ::Win32::Registry::HKEY_LOCAL_MACHINE,
    "HKU" => ::Win32::Registry::HKEY_USERS,
    "HKEY_USERS" => ::Win32::Registry::HKEY_USERS,
    "HKCU" => ::Win32::Registry::HKEY_CURRENT_USER,
    "HKEY_CURRENT_USER" => ::Win32::Registry::HKEY_CURRENT_USER,
    "HKCR" => ::Win32::Registry::HKEY_CLASSES_ROOT,
    "HKEY_CLASSES_ROOT" => ::Win32::Registry::HKEY_CLASSES_ROOT,
    "HKCC" => ::Win32::Registry::HKEY_CURRENT_CONFIG,
    "HKEY_CURRENT_CONFIG" => ::Win32::Registry::HKEY_CURRENT_CONFIG,
  }[hive_name]

  raise Chef::Exceptions::Win32RegHiveMissing, "Registry Hive #{hive_name} does not exist" unless hive

  [hive, key]
end
get_key(path) click to toggle source
# File lib/chef/win32/registry.rb, line 375
def get_key(path)
  reg_path = path.split("\\")
  hive_name = reg_path.shift
  key = reg_path.join("\\")
end
get_type_from_num(val_type) click to toggle source
# File lib/chef/win32/registry.rb, line 348
def get_type_from_num(val_type)
  {
    3 => ::Win32::Registry::REG_BINARY,
    1 => ::Win32::Registry::REG_SZ,
    7 => ::Win32::Registry::REG_MULTI_SZ,
    2 => ::Win32::Registry::REG_EXPAND_SZ,
    4 => ::Win32::Registry::REG_DWORD,
    5 => ::Win32::Registry::REG_DWORD_BIG_ENDIAN,
    11 => ::Win32::Registry::REG_QWORD,
  }[val_type]
end
machine_architecture() click to toggle source
# File lib/chef/win32/registry.rb, line 295
def machine_architecture
  if node.nil?
    ::RbConfig::CONFIG["target_cpu"] == "x64" ? :x86_64 : :i386
  else
    node[:kernel][:machine].to_sym
  end
end
node() click to toggle source
# File lib/chef/win32/registry.rb, line 291
def node
  run_context && run_context.node
end
safely_downcase(val) click to toggle source
# File lib/chef/win32/registry.rb, line 283
def safely_downcase(val)
  if val.is_a? String
    return val.downcase
  end

  val
end