Downgrade mysql cookbook for now

It doesn't play well with our current dev server setup
This commit is contained in:
Greg Karékinian
2017-06-16 22:43:51 +02:00
parent e39792ea36
commit bdfb3a1afb
398 changed files with 12716 additions and 10889 deletions

View File

@@ -1,57 +0,0 @@
class Chef
class Provider
class WindowsFeature
module Base
def action_install
unless installed?
install_feature(@new_resource.feature_name)
@new_resource.updated_by_last_action(true)
Chef::Log.info("#{@new_resource} installed feature")
else
Chef::Log.debug("#{@new_resource} is already installed - nothing to do")
end
end
def action_remove
if installed?
remove_feature(@new_resource.feature_name)
@new_resource.updated_by_last_action(true)
Chef::Log.info("#{@new_resource} removed")
else
Chef::Log.debug("#{@new_resource} feature does not exist - nothing to do")
end
end
def action_delete
if available?
delete_feature(@new_resource.feature_name)
@new_resource.updated_by_last_action(true)
Chef::Log.info("#{@new_resource} deleted")
else
Chef::Log.debug("#{@new_resource} feature is not installed - nothing to do")
end
end
def install_feature(_name)
fail Chef::Exceptions::UnsupportedAction, "#{self} does not support :install"
end
def remove_feature(_name)
fail Chef::Exceptions::UnsupportedAction, "#{self} does not support :remove"
end
def delete_feature(_name)
fail Chef::Exceptions::UnsupportedAction, "#{self} does not support :delete"
end
def installed?
fail Chef::Exceptions::Override, "You must override installed? in #{self}"
end
def available?
fail Chef::Exceptions::Override, "You must override available? in #{self}"
end
end
end
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -1,53 +1,53 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Cookbook Name:: windows
# Library:: helper
#
# Copyright:: 2011-2015, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/mixin/shell_out'
module Powershell
module Helper
include Chef::Mixin::ShellOut
def powershell_installed?
!powershell_version.nil?
end
def interpreter
# force 64-bit powershell from 32-bit ruby process
if ::File.exist?("#{ENV['WINDIR']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe")
"#{ENV['WINDIR']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe"
elsif ::File.exist?("#{ENV['WINDIR']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe")
"#{ENV['WINDIR']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe"
else
'powershell.exe'
end
end
def powershell_version
cmd = shell_out("#{interpreter} -InputFormat none -Command \"& echo $PSVersionTable.psversion.major\"")
if cmd.stdout.empty? # PowerShell 1.0 doesn't have a $PSVersionTable
1
else
Regexp.last_match(1).to_i if cmd.stdout =~ /^(\d+)/
end
rescue Errno::ENOENT
nil
end
end
end
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Cookbook:: windows
# Library:: helper
#
# Copyright:: 2011-2017, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/mixin/shell_out'
module Powershell
module Helper
include Chef::Mixin::ShellOut
def powershell_installed?
!powershell_version.nil?
end
def interpreter
# force 64-bit powershell from 32-bit ruby process
if ::File.exist?("#{ENV['WINDIR']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe")
"#{ENV['WINDIR']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe"
elsif ::File.exist?("#{ENV['WINDIR']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe")
"#{ENV['WINDIR']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe"
else
'powershell.exe'
end
end
def powershell_version
cmd = shell_out("#{interpreter} -InputFormat none -Command \"& echo $PSVersionTable.psversion.major\"")
if cmd.stdout.empty? # PowerShell 1.0 doesn't have a $PSVersionTable
1
else
Regexp.last_match(1).to_i if cmd.stdout =~ /^(\d+)/
end
rescue Errno::ENOENT
nil
end
end
end

View File

@@ -1,92 +0,0 @@
#
# WARNING
#
# THIS CODE HAS BEEN MOVED TO CORE CHEF. DO NOT SUMBIT PULL REQUESTS AGAINST THIS
# CODE. IT WILL BE REMOVED IN THE FUTURE.
#
unless defined? Chef::Mixin::PowershellOut
class Chef
module Mixin
module PowershellOut
include Chef::Mixin::ShellOut
begin
include Chef::Mixin::WindowsArchitectureHelper
rescue
# nothing to do, as the include will happen when windows_architecture_helper.rb
# is loaded. This is for ease of removal of that library when either
# powershell_out is core chef or powershell cookbook depends upon version
# of chef that has Chef::Mixin::WindowsArchitectureHelper in core chef
end
def powershell_out(*command_args)
Chef::Log.warn 'The powershell_out library in the windows cookbook is deprecated.'
Chef::Log.warn 'Please upgrade to Chef 12.4.0 or later where it is built-in to core chef.'
script = command_args.first
options = command_args.last.is_a?(Hash) ? command_args.last : nil
run_command(script, options)
end
def powershell_out!(*command_args)
cmd = powershell_out(*command_args)
cmd.error!
cmd
end
private
def run_command(script, options)
if options && options[:architecture]
architecture = options[:architecture]
options.delete(:architecture)
else
architecture = node_windows_architecture(node)
end
disable_redirection = wow64_architecture_override_required?(node, architecture)
if disable_redirection
original_redirection_state = disable_wow64_file_redirection(node)
end
command = build_command(script)
if options
cmd = shell_out(command, options)
else
cmd = shell_out(command)
end
if disable_redirection
restore_wow64_file_redirection(node, original_redirection_state)
end
cmd
end
def build_command(script)
flags = [
# Hides the copyright banner at startup.
'-NoLogo',
# Does not present an interactive prompt to the user.
'-NonInteractive',
# Does not load the Windows PowerShell profile.
'-NoProfile',
# always set the ExecutionPolicy flag
# see http://technet.microsoft.com/en-us/library/ee176961.aspx
'-ExecutionPolicy RemoteSigned',
# Powershell will hang if STDIN is redirected
# http://connect.microsoft.com/PowerShell/feedback/details/572313/powershell-exe-can-hang-if-stdin-is-redirected
'-InputFormat None'
]
command = "powershell.exe #{flags.join(' ')} -Command \"#{script}\""
command
end
end
end
end
end

View File

@@ -1,355 +1,356 @@
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Author:: Paul Morton (<pmorton@biaprotect.com>)
# Cookbook Name:: windows
# Provider:: registry
#
# Copyright:: 2010, VMware, Inc.
# Copyright:: 2011-2015, Chef Software, Inc.
# Copyright:: 2011, Business Intelligence Associates, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
if RUBY_PLATFORM =~ /mswin|mingw32|windows/
require 'win32/registry'
require_relative 'wmi_helper'
end
module Windows
module RegistryHelper
@@native_registry_constant = ENV['PROCESSOR_ARCHITEW6432'] == 'AMD64' ? 0x0100 : 0x0200
def get_hive_name(path)
Chef::Log.debug('Resolving registry shortcuts to full names')
reg_path = path.split('\\')
hive_name = reg_path.shift
hkey = {
'HKLM' => 'HKEY_LOCAL_MACHINE',
'HKCU' => 'HKEY_CURRENT_USER',
'HKU' => 'HKEY_USERS'
}[hive_name] || hive_name
Chef::Log.debug("Hive resolved to #{hkey}")
hkey
end
def get_hive(path)
Chef::Log.debug("Getting hive for #{path}")
reg_path = path.split('\\')
hive_name = reg_path.shift
hkey = get_hive_name(path)
hive = {
'HKEY_LOCAL_MACHINE' => ::Win32::Registry::HKEY_LOCAL_MACHINE,
'HKEY_USERS' => ::Win32::Registry::HKEY_USERS,
'HKEY_CURRENT_USER' => ::Win32::Registry::HKEY_CURRENT_USER
}[hkey]
unless hive
Chef::Application.fatal!("Unsupported registry hive '#{hive_name}'")
end
Chef::Log.debug("Registry hive resolved to #{hkey}")
hive
end
def unload_hive(path)
hive = get_hive(path)
if hive == ::Win32::Registry::HKEY_USERS
reg_path = path.split('\\')
priv = Chef::WindowsPrivileged.new
begin
priv.reg_unload_key(reg_path[1])
rescue
end
end
end
def set_value(mode, path, values, type = nil)
hive, reg_path, hive_name, root_key, hive_loaded = get_reg_path_info(path)
key_name = reg_path.join('\\')
Chef::Log.debug("Creating #{path}")
create_key(path) unless key_exists?(path, true)
hive.send(mode, key_name, ::Win32::Registry::KEY_ALL_ACCESS | @@native_registry_constant) do |reg|
changed_something = false
values.each do |k, val|
key = k.to_s # wtf. avoid "can't modify frozen string" in win32/registry.rb
cur_val = nil
begin
cur_val = reg[key]
rescue
# subkey does not exist (ok)
end
next unless cur_val != val
Chef::Log.debug("setting #{key}=#{val}")
type = :string if type.nil?
reg_type = {
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
}[type]
reg.write(key, reg_type, val)
ensure_hive_unloaded(hive_loaded)
changed_something = true
end
return changed_something
end
false
end
def get_value(path, value)
hive, reg_path, hive_name, root_key, hive_loaded = get_reg_path_info(path)
key = reg_path.join('\\')
hive.open(key, ::Win32::Registry::KEY_ALL_ACCESS | @@native_registry_constant) do |reg|
begin
return reg[value]
rescue
return nil
ensure
ensure_hive_unloaded(hive_loaded)
end
end
end
def get_values(path)
hive, reg_path, hive_name, root_key, hive_loaded = get_reg_path_info(path)
key = reg_path.join('\\')
hive.open(key, ::Win32::Registry::KEY_ALL_ACCESS | @@native_registry_constant) do |reg|
values = []
begin
reg.each_value do |name, type, data|
values << [name, type, data]
end
rescue
ensure
ensure_hive_unloaded(hive_loaded)
end
values
end
end
def delete_value(path, values)
hive, reg_path, hive_name, root_key, hive_loaded = get_reg_path_info(path)
key = reg_path.join('\\')
Chef::Log.debug("Deleting values in #{path}")
hive.open(key, ::Win32::Registry::KEY_ALL_ACCESS | @@native_registry_constant) do |reg|
values.each_key do |key|
name = key.to_s
# Ensure delete operation is idempotent.
if value_exists?(path, key)
Chef::Log.debug("Deleting value #{name} in #{path}")
reg.delete_value(name)
else
Chef::Log.debug("Value #{name} in #{path} does not exist, skipping.")
end
end
end
end
def create_key(path)
hive, reg_path, hive_name, root_key, hive_loaded = get_reg_path_info(path)
key = reg_path.join('\\')
Chef::Log.debug("Creating registry key #{path}")
hive.create(key)
end
def value_exists?(path, value)
if key_exists?(path, true)
hive, reg_path, hive_name, root_key, hive_loaded = get_reg_path_info(path)
key = reg_path.join('\\')
Chef::Log.debug("Attempting to open #{key}")
Chef::Log.debug("Native Constant #{@@native_registry_constant}")
Chef::Log.debug("Hive #{hive}")
hive.open(key, ::Win32::Registry::KEY_READ | @@native_registry_constant) do |reg|
begin
rtn_value = reg[value]
return true
rescue
return false
ensure
ensure_hive_unloaded(hive_loaded)
end
end
end
false
end
# TODO: Does not load user registry...
def key_exists?(path, load_hive = false)
if load_hive
hive, reg_path, hive_name, root_key, hive_loaded = get_reg_path_info(path)
key = reg_path.join('\\')
else
hive = get_hive(path)
reg_path = path.split('\\')
hive_name = reg_path.shift
root_key = reg_path[0]
key = reg_path.join('\\')
hive_loaded = false
end
begin
hive.open(key, ::Win32::Registry::Constants::KEY_READ | @@native_registry_constant)
return true
rescue
return false
ensure
ensure_hive_unloaded(hive_loaded)
end
end
def get_user_hive_location(sid)
reg_key = "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\#{sid}"
Chef::Log.debug("Looking for profile at #{reg_key}")
if key_exists?(reg_key)
return get_value(reg_key, 'ProfileImagePath')
else
return nil
end
end
def resolve_user_to_sid(username)
user_query = execute_wmi_query("select * from Win32_UserAccount where Name='#{username}'")
sid = nil
user_query.each do |user|
sid = wmi_object_property(user, 'sid')
break
end
Chef::Log.debug("Resolved user SID to #{sid}")
return sid
rescue
return nil
end
def hive_loaded?(path)
hive = get_hive(path)
reg_path = path.split('\\')
hive_name = reg_path.shift
user_hive = path[0]
if user_hive?(hive)
return key_exists?("#{hive_name}\\#{user_hive}")
else
return true
end
end
def user_hive?(hive)
if hive == ::Win32::Registry::HKEY_USERS
return true
else
return true
end
end
def get_reg_path_info(path)
hive = get_hive(path)
reg_path = path.split('\\')
hive_name = reg_path.shift
root_key = reg_path[0]
hive_loaded = false
if user_hive?(hive) && !key_exists?("#{hive_name}\\#{root_key}")
reg_path, hive_loaded = load_user_hive(hive, reg_path, root_key)
root_key = reg_path[0]
Chef::Log.debug("Resolved user (#{path}) to (#{reg_path.join('/')})")
end
[hive, reg_path, hive_name, root_key, hive_loaded]
end
def load_user_hive(hive, reg_path, user_hive)
Chef::Log.debug("Reg Path #{reg_path}")
# See if the hive is loaded. Logged in users will have a key that is named their SID
# if the user has specified the a path by SID and the user is logged in, this function
# should not be executed.
if user_hive?(hive) && !key_exists?("HKU\\#{user_hive}")
Chef::Log.debug('The user is not logged in and has not been specified by SID')
sid = resolve_user_to_sid(user_hive)
Chef::Log.debug("User SID resolved to (#{sid})")
# Now that the user has been resolved to a SID, check and see if the hive exists.
# If this exists by SID, the user is logged in and we should use that key.
# TODO: Replace the username with the sid and send it back because the username
# does not exist as the key location.
load_reg = false
if key_exists?("HKU\\#{sid}")
reg_path[0] = sid # use the active profile (user is logged on)
Chef::Log.debug("HKEY_USERS Mapped: #{user_hive} -> #{sid}")
else
Chef::Log.debug('User is not logged in')
load_reg = true
end
# The user is not logged in, so we should load the registry from disk
if load_reg
profile_path = get_user_hive_location(sid)
unless profile_path.nil?
ntuser_dat = "#{profile_path}\\NTUSER.DAT"
if ::File.exist?(ntuser_dat)
priv = Chef::WindowsPrivileged.new
if priv.reg_load_key(sid, ntuser_dat)
Chef::Log.debug("RegLoadKey(#{sid}, #{user_hive}, #{ntuser_dat})")
reg_path[0] = sid
else
Chef::Log.debug("Failed RegLoadKey(#{sid}, #{user_hive}, #{ntuser_dat})")
end
end
end
end
end
[reg_path, load_reg]
end
private
def ensure_hive_unloaded(hive_loaded = false)
if hive_loaded
Chef::Log.debug('Hive was loaded, we really should unload it')
unload_hive(path)
end
end
end
end
module Registry
module_function
extend Windows::RegistryHelper
end
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Author:: Paul Morton (<pmorton@biaprotect.com>)
# Cookbook:: windows
# Provider:: registry
#
# Copyright:: 2010-2017, VMware, Inc.
# Copyright:: 2011-2017, Chef Software, Inc.
# Copyright:: 2011-2017, Business Intelligence Associates, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
if RUBY_PLATFORM =~ /mswin|mingw32|windows/
require 'win32/registry'
require_relative 'wmi_helper'
end
module Windows
module RegistryHelper
@@native_registry_constant = if ENV['PROCESSOR_ARCHITECTURE'] == 'AMD64' ||
ENV['PROCESSOR_ARCHITEW6432'] == 'AMD64'
0x0100
else
0x0200
end
def get_hive_name(path)
Chef::Log.debug('Resolving registry shortcuts to full names')
reg_path = path.split('\\')
hive_name = reg_path.shift
hkey = {
'HKLM' => 'HKEY_LOCAL_MACHINE',
'HKCU' => 'HKEY_CURRENT_USER',
'HKU' => 'HKEY_USERS',
}[hive_name] || hive_name
Chef::Log.debug("Hive resolved to #{hkey}")
hkey
end
def get_hive(path)
Chef::Log.debug("Getting hive for #{path}")
reg_path = path.split('\\')
hive_name = reg_path.shift
hkey = get_hive_name(path)
hive = {
'HKEY_LOCAL_MACHINE' => ::Win32::Registry::HKEY_LOCAL_MACHINE,
'HKEY_USERS' => ::Win32::Registry::HKEY_USERS,
'HKEY_CURRENT_USER' => ::Win32::Registry::HKEY_CURRENT_USER,
}[hkey]
unless hive
Chef::Application.fatal!("Unsupported registry hive '#{hive_name}'")
end
Chef::Log.debug("Registry hive resolved to #{hkey}")
hive
end
def unload_hive(path)
hive = get_hive(path)
if hive == ::Win32::Registry::HKEY_USERS
reg_path = path.split('\\')
priv = Chef::WindowsPrivileged.new
begin
priv.reg_unload_key(reg_path[1])
rescue
end
end
end
def set_value(mode, path, values, type = nil)
hive, reg_path, hive_name, root_key, hive_loaded = get_reg_path_info(path)
key_name = reg_path.join('\\')
Chef::Log.debug("Creating #{path}")
create_key(path) unless key_exists?(path, true)
hive.send(mode, key_name, ::Win32::Registry::KEY_ALL_ACCESS | @@native_registry_constant) do |reg|
changed_something = false
values.each do |k, val|
key = k.to_s # wtf. avoid "can't modify frozen string" in win32/registry.rb
cur_val = nil
begin
cur_val = reg[key]
rescue
# subkey does not exist (ok)
end
next unless cur_val != val
Chef::Log.debug("setting #{key}=#{val}")
type = :string if type.nil?
reg_type = {
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,
}[type]
reg.write(key, reg_type, val)
ensure_hive_unloaded(hive_loaded)
changed_something = true
end
return changed_something
end
false
end
def get_value(path, value)
hive, reg_path, hive_name, root_key, hive_loaded = get_reg_path_info(path)
key = reg_path.join('\\')
hive.open(key, ::Win32::Registry::KEY_ALL_ACCESS | @@native_registry_constant) do |reg|
begin
return reg[value]
rescue
return nil
ensure
ensure_hive_unloaded(hive_loaded)
end
end
end
def get_values(path)
hive, reg_path, hive_name, root_key, hive_loaded = get_reg_path_info(path)
key = reg_path.join('\\')
hive.open(key, ::Win32::Registry::KEY_ALL_ACCESS | @@native_registry_constant) do |reg|
values = []
begin
reg.each_value do |name, type, data|
values << [name, type, data]
end
rescue
ensure
ensure_hive_unloaded(hive_loaded)
end
values
end
end
def delete_value(path, values)
hive, reg_path, hive_name, root_key, hive_loaded = get_reg_path_info(path)
key = reg_path.join('\\')
Chef::Log.debug("Deleting values in #{path}")
hive.open(key, ::Win32::Registry::KEY_ALL_ACCESS | @@native_registry_constant) do |reg|
values.each_key do |key|
name = key.to_s
# Ensure delete operation is idempotent.
if value_exists?(path, key)
Chef::Log.debug("Deleting value #{name} in #{path}")
reg.delete_value(name)
else
Chef::Log.debug("Value #{name} in #{path} does not exist, skipping.")
end
end
end
end
def create_key(path)
hive, reg_path, hive_name, root_key, hive_loaded = get_reg_path_info(path)
key = reg_path.join('\\')
Chef::Log.debug("Creating registry key #{path}")
hive.create(key)
end
def value_exists?(path, value)
if key_exists?(path, true)
hive, reg_path, hive_name, root_key, hive_loaded = get_reg_path_info(path)
key = reg_path.join('\\')
Chef::Log.debug("Attempting to open #{key}")
Chef::Log.debug("Native Constant #{@@native_registry_constant}")
Chef::Log.debug("Hive #{hive}")
hive.open(key, ::Win32::Registry::KEY_READ | @@native_registry_constant) do |reg|
begin
rtn_value = reg[value]
return true
rescue
return false
ensure
ensure_hive_unloaded(hive_loaded)
end
end
end
false
end
# TODO: Does not load user registry...
def key_exists?(path, load_hive = false)
if load_hive
hive, reg_path, hive_name, root_key, hive_loaded = get_reg_path_info(path)
key = reg_path.join('\\')
else
hive = get_hive(path)
reg_path = path.split('\\')
hive_name = reg_path.shift
root_key = reg_path[0]
key = reg_path.join('\\')
hive_loaded = false
end
begin
hive.open(key, ::Win32::Registry::Constants::KEY_READ | @@native_registry_constant)
return true
rescue
return false
ensure
ensure_hive_unloaded(hive_loaded)
end
end
def get_user_hive_location(sid)
reg_key = "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\#{sid}"
Chef::Log.debug("Looking for profile at #{reg_key}")
if key_exists?(reg_key)
return get_value(reg_key, 'ProfileImagePath')
else
return nil
end
end
def resolve_user_to_sid(username)
user_query = execute_wmi_query("select * from Win32_UserAccount where Name='#{username}'")
sid = nil
user_query.each do |user|
sid = wmi_object_property(user, 'sid')
break
end
Chef::Log.debug("Resolved user SID to #{sid}")
return sid
rescue
return nil
end
def hive_loaded?(path)
hive = get_hive(path)
reg_path = path.split('\\')
hive_name = reg_path.shift
user_hive = path[0]
if user_hive?(hive)
return key_exists?("#{hive_name}\\#{user_hive}")
else
return true
end
end
def user_hive?(hive)
hive == ::Win32::Registry::HKEY_USERS
end
def get_reg_path_info(path)
hive = get_hive(path)
reg_path = path.split('\\')
hive_name = reg_path.shift
root_key = reg_path[0]
hive_loaded = false
if user_hive?(hive) && !key_exists?("#{hive_name}\\#{root_key}")
reg_path, hive_loaded = load_user_hive(hive, reg_path, root_key)
root_key = reg_path[0]
Chef::Log.debug("Resolved user (#{path}) to (#{reg_path.join('/')})")
end
[hive, reg_path, hive_name, root_key, hive_loaded]
end
def load_user_hive(hive, reg_path, user_hive)
Chef::Log.debug("Reg Path #{reg_path}")
# See if the hive is loaded. Logged in users will have a key that is named their SID
# if the user has specified the a path by SID and the user is logged in, this function
# should not be executed.
if user_hive?(hive) && !key_exists?("HKU\\#{user_hive}")
Chef::Log.debug('The user is not logged in and has not been specified by SID')
sid = resolve_user_to_sid(user_hive)
Chef::Log.debug("User SID resolved to (#{sid})")
# Now that the user has been resolved to a SID, check and see if the hive exists.
# If this exists by SID, the user is logged in and we should use that key.
# TODO: Replace the username with the sid and send it back because the username
# does not exist as the key location.
load_reg = false
if key_exists?("HKU\\#{sid}")
reg_path[0] = sid # use the active profile (user is logged on)
Chef::Log.debug("HKEY_USERS Mapped: #{user_hive} -> #{sid}")
else
Chef::Log.debug('User is not logged in')
load_reg = true
end
# The user is not logged in, so we should load the registry from disk
if load_reg
profile_path = get_user_hive_location(sid)
unless profile_path.nil?
ntuser_dat = "#{profile_path}\\NTUSER.DAT"
if ::File.exist?(ntuser_dat)
priv = Chef::WindowsPrivileged.new
if priv.reg_load_key(sid, ntuser_dat)
Chef::Log.debug("RegLoadKey(#{sid}, #{user_hive}, #{ntuser_dat})")
reg_path[0] = sid
else
Chef::Log.debug("Failed RegLoadKey(#{sid}, #{user_hive}, #{ntuser_dat})")
end
end
end
end
end
[reg_path, load_reg]
end
private
def ensure_hive_unloaded(hive_loaded = false)
if hive_loaded
Chef::Log.debug('Hive was loaded, we really should unload it')
unload_hive(path)
end
end
end
end
module Registry
module_function
extend Windows::RegistryHelper
end

View File

@@ -1,207 +1,207 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Cookbook Name:: windows
# Library:: version
#
# Copyright:: 2011-2015, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
if RUBY_PLATFORM =~ /mswin|mingw32|windows/
require_relative 'wmi_helper'
require 'Win32API'
end
module Windows
class Version
# http://msdn.microsoft.com/en-us/library/ms724833(v=vs.85).aspx
# Suite Masks
# Microsoft BackOffice components are installed.
VER_SUITE_BACKOFFICE = 0x00000004 unless defined?(VER_SUITE_BACKOFFICE)
# Windows Server 2003, Web Edition is installed.
VER_SUITE_BLADE = 0x00000400 unless defined?(VER_SUITE_BLADE)
# Windows Server 2003, Compute Cluster Edition is installed.
VER_SUITE_COMPUTE_SERVER = 0x00004000 unless defined?(VER_SUITE_COMPUTE_SERVER)
# Windows Server 2008 Datacenter, Windows Server 2003, Datacenter Edition, or Windows 2000 Datacenter Server is installed.
VER_SUITE_DATACENTER = 0x00000080 unless defined?(VER_SUITE_DATACENTER)
# Windows Server 2008 Enterprise, Windows Server 2003, Enterprise Edition, or Windows 2000 Advanced Server is installed. Refer to the Remarks section for more information about this bit flag.
VER_SUITE_ENTERPRISE = 0x00000002 unless defined?(VER_SUITE_ENTERPRISE)
# Windows XP Embedded is installed.
VER_SUITE_EMBEDDEDNT = 0x00000040 unless defined?(VER_SUITE_EMBEDDEDNT)
# Windows Vista Home Premium, Windows Vista Home Basic, or Windows XP Home Edition is installed.
VER_SUITE_PERSONAL = 0x00000200 unless defined?(VER_SUITE_PERSONAL)
# Remote Desktop is supported, but only one interactive session is supported. This value is set unless the system is running in application server mode.
VER_SUITE_SINGLEUSERTS = 0x00000100 unless defined?(VER_SUITE_SINGLEUSERTS)
# Microsoft Small Business Server was once installed on the system, but may have been upgraded to another version of Windows. Refer to the Remarks section for more information about this bit flag.
VER_SUITE_SMALLBUSINESS = 0x00000001 unless defined?(VER_SUITE_SMALLBUSINESS)
# Microsoft Small Business Server is installed with the restrictive client license in force. Refer to the Remarks section for more information about this bit flag.
VER_SUITE_SMALLBUSINESS_RESTRICTED = 0x00000020 unless defined?(VER_SUITE_SMALLBUSINESS_RESTRICTED)
# Windows Storage Server 2003 R2 or Windows Storage Server 2003is installed.
VER_SUITE_STORAGE_SERVER = 0x00002000 unless defined?(VER_SUITE_STORAGE_SERVER)
# Terminal Services is installed. This value is always set.
# If VER_SUITE_TERMINAL is set but VER_SUITE_SINGLEUSERTS is not set, the system is running in application server mode.
VER_SUITE_TERMINAL = 0x00000010 unless defined?(VER_SUITE_TERMINAL)
# Windows Home Server is installed.
VER_SUITE_WH_SERVER = 0x00008000 unless defined?(VER_SUITE_WH_SERVER)
# Product Type
# The system is a domain controller and the operating system is Windows Server 2012, Windows Server 2008 R2, Windows Server 2008, Windows Server 2003, or Windows 2000 Server.
VER_NT_DOMAIN_CONTROLLER = 0x0000002 unless defined?(VER_NT_DOMAIN_CONTROLLER)
# The operating system is Windows Server 2012, Windows Server 2008 R2, Windows Server 2008, Windows Server 2003, or Windows 2000 Server.
# Note that a server that is also a domain controller is reported as VER_NT_DOMAIN_CONTROLLER, not VER_NT_SERVER.
VER_NT_SERVER = 0x0000003 unless defined?(VER_NT_SERVER)
# The operating system is Windows 7, Windows Vista, Windows XP Professional, Windows XP Home Edition, or Windows 2000 Professional.
VER_NT_WORKSTATION = 0x0000001 unless defined?(VER_NT_WORKSTATION)
# GetSystemMetrics
# The build number if the system is Windows Server 2003 R2; otherwise, 0.
SM_SERVERR2 = 89 unless defined?(SM_SERVERR2)
# http://msdn.microsoft.com/en-us/library/ms724358(v=vs.85).aspx
SKU = {
0x00000006 => { ms_const: 'PRODUCT_BUSINESS', name: 'Business' },
0x00000010 => { ms_const: 'PRODUCT_BUSINESS_N', name: 'Business N' },
0x00000012 => { ms_const: 'PRODUCT_CLUSTER_SERVER', name: 'HPC Edition' },
0x00000008 => { ms_const: 'PRODUCT_DATACENTER_SERVER', name: 'Server Datacenter (full installation)' },
0x0000000C => { ms_const: 'PRODUCT_DATACENTER_SERVER_CORE', name: 'Server Datacenter (core installation)' },
0x00000027 => { ms_const: 'PRODUCT_DATACENTER_SERVER_CORE_V', name: 'Server Datacenter without Hyper-V (core installation)' },
0x00000025 => { ms_const: 'PRODUCT_DATACENTER_SERVER_V', name: 'Server Datacenter without Hyper-V (full installation)' },
0x00000004 => { ms_const: 'PRODUCT_ENTERPRISE', name: 'Enterprise' },
0x00000046 => { ms_const: 'PRODUCT_ENTERPRISE_E', name: 'Not supported' },
0x0000001B => { ms_const: 'PRODUCT_ENTERPRISE_N', name: 'Enterprise N' },
0x0000000A => { ms_const: 'PRODUCT_ENTERPRISE_SERVER', name: 'Server Enterprise (full installation)' },
0x0000000E => { ms_const: 'PRODUCT_ENTERPRISE_SERVER_CORE', name: 'Server Enterprise (core installation)' },
0x00000029 => { ms_const: 'PRODUCT_ENTERPRISE_SERVER_CORE_V', name: 'Server Enterprise without Hyper-V (core installation)' },
0x0000000F => { ms_const: 'PRODUCT_ENTERPRISE_SERVER_IA64', name: 'Server Enterprise for Itanium-based Systems' },
0x00000026 => { ms_const: 'PRODUCT_ENTERPRISE_SERVER_V', name: 'Server Enterprise without Hyper-V (full installation)' },
0x00000002 => { ms_const: 'PRODUCT_HOME_BASIC', name: 'Home Basic' },
0x00000043 => { ms_const: 'PRODUCT_HOME_BASIC_E', name: 'Not supported' },
0x00000005 => { ms_const: 'PRODUCT_HOME_BASIC_N', name: 'Home Basic N' },
0x00000003 => { ms_const: 'PRODUCT_HOME_PREMIUM', name: 'Home Premium' },
0x00000044 => { ms_const: 'PRODUCT_HOME_PREMIUM_E', name: 'Not supported' },
0x0000001A => { ms_const: 'PRODUCT_HOME_PREMIUM_N', name: 'Home Premium N' },
0x0000002A => { ms_const: 'PRODUCT_HYPERV', name: 'Microsoft Hyper-V Server' },
0x0000001E => { ms_const: 'PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT', name: 'Windows Essential Business Server Management Server' },
0x00000020 => { ms_const: 'PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING', name: 'Windows Essential Business Server Messaging Server' },
0x0000001F => { ms_const: 'PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY', name: 'Windows Essential Business Server Security Server' },
0x00000030 => { ms_const: 'PRODUCT_PROFESSIONAL', name: 'Professional' },
0x00000045 => { ms_const: 'PRODUCT_PROFESSIONAL_E', name: 'Not supported' },
0x00000031 => { ms_const: 'PRODUCT_PROFESSIONAL_N', name: 'Professional N' },
0x00000067 => { ms_const: 'PRODUCT_PROFESSIONAL_WMC', name: 'Professional with Media Center' },
0x00000018 => { ms_const: 'PRODUCT_SERVER_FOR_SMALLBUSINESS', name: 'Windows Server 2008 for Windows Essential Server Solutions' },
0x00000023 => { ms_const: 'PRODUCT_SERVER_FOR_SMALLBUSINESS_V', name: 'Windows Server 2008 without Hyper-V for Windows Essential Server Solutions' },
0x00000021 => { ms_const: 'PRODUCT_SERVER_FOUNDATION', name: 'Server Foundation' },
0x00000022 => { ms_const: 'PRODUCT_HOME_PREMIUM_SERVER', name: 'Windows Home Server 2011' },
0x00000032 => { ms_const: 'PRODUCT_SB_SOLUTION_SERVER', name: 'Windows Small Business Server 2011 Essentials' },
0x00000013 => { ms_const: 'PRODUCT_HOME_SERVER', name: 'Windows Storage Server 2008 R2 Essentials' },
0x00000009 => { ms_const: 'PRODUCT_SMALLBUSINESS_SERVER', name: 'Windows Small Business Server' },
0x00000038 => { ms_const: 'PRODUCT_SOLUTION_EMBEDDEDSERVER', name: 'Windows MultiPoint Server' },
0x00000007 => { ms_const: 'PRODUCT_STANDARD_SERVER', name: 'Server Standard (full installation)' },
0x0000000D => { ms_const: 'PRODUCT_STANDARD_SERVER_CORE', name: 'Server Standard (core installation)' },
0x00000028 => { ms_const: 'PRODUCT_STANDARD_SERVER_CORE_V', name: 'Server Standard without Hyper-V (core installation)' },
0x00000024 => { ms_const: 'PRODUCT_STANDARD_SERVER_V', name: 'Server Standard without Hyper-V (full installation)' },
0x0000000B => { ms_const: 'PRODUCT_STARTER', name: 'Starter' },
0x00000042 => { ms_const: 'PRODUCT_STARTER_E', name: 'Not supported' },
0x0000002F => { ms_const: 'PRODUCT_STARTER_N', name: 'Starter N' },
0x00000017 => { ms_const: 'PRODUCT_STORAGE_ENTERPRISE_SERVER', name: 'Storage Server Enterprise' },
0x00000014 => { ms_const: 'PRODUCT_STORAGE_EXPRESS_SERVER', name: 'Storage Server Express' },
0x00000015 => { ms_const: 'PRODUCT_STORAGE_STANDARD_SERVER', name: 'Storage Server Standard' },
0x00000016 => { ms_const: 'PRODUCT_STORAGE_WORKGROUP_SERVER', name: 'Storage Server Workgroup' },
0x00000000 => { ms_const: 'PRODUCT_UNDEFINED', name: 'An unknown product' },
0x00000001 => { ms_const: 'PRODUCT_ULTIMATE', name: 'Ultimate' },
0x00000047 => { ms_const: 'PRODUCT_ULTIMATE_E', name: 'Not supported' },
0x0000001C => { ms_const: 'PRODUCT_ULTIMATE_N', name: 'Ultimate N' },
0x00000011 => { ms_const: 'PRODUCT_WEB_SERVER', name: 'Web Server (full installation)' },
0x0000001D => { ms_const: 'PRODUCT_WEB_SERVER_CORE', name: 'Web Server (core installation)' }
}.freeze unless defined?(SKU)
attr_reader :major_version, :minor_version, :build_number, :service_pack_major_version, :service_pack_minor_version
attr_reader :version, :product_type, :product_suite, :sku
def initialize
unless RUBY_PLATFORM =~ /mswin|mingw32|windows/
fail NotImplementedError, 'only valid on Windows platform'
end
@version, @product_type, @product_suite, @sku, @service_pack_major_version, @service_pack_minor_version = get_os_info
@major_version, @minor_version, @build_number = version.split('.').map(&:to_i)
end
WIN_VERSIONS = {
'Windows Server 2012 R2' => { major: 6, minor: 3, callable: -> { @product_type != VER_NT_WORKSTATION } },
'Windows 8' => { major: 6, minor: 2, callable: -> { @product_type == VER_NT_WORKSTATION } },
'Windows Server 2012' => { major: 6, minor: 2, callable: -> { @product_type != VER_NT_WORKSTATION } },
'Windows 7' => { major: 6, minor: 1, callable: -> { @product_type == VER_NT_WORKSTATION } },
'Windows Server 2008 R2' => { major: 6, minor: 1, callable: -> { @product_type != VER_NT_WORKSTATION } },
'Windows Server 2008' => { major: 6, minor: 0, callable: -> { @product_type != VER_NT_WORKSTATION } },
'Windows Vista' => { major: 6, minor: 0, callable: -> { @product_type == VER_NT_WORKSTATION } },
'Windows Server 2003 R2' => { major: 5, minor: 2, callable: -> { Win32API.new('user32', 'GetSystemMetrics', 'I', 'I').call(SM_SERVERR2) != 0 } },
'Windows Home Server' => { major: 5, minor: 2, callable: -> { (@product_suite & VER_SUITE_WH_SERVER) == VER_SUITE_WH_SERVER } },
'Windows Server 2003' => { major: 5, minor: 2, callable: -> { Win32API.new('user32', 'GetSystemMetrics', 'I', 'I').call(SM_SERVERR2) == 0 } },
'Windows XP' => { major: 5, minor: 1 },
'Windows 2000' => { major: 5, minor: 0 }
}.freeze unless defined?(WIN_VERSIONS)
marketing_names = []
# General Windows checks
WIN_VERSIONS.each do |k, v|
method_name = "#{k.gsub(/\s/, '_').downcase}?"
define_method(method_name) do
(@major_version == v[:major]) &&
(@minor_version == v[:minor]) &&
(v[:callable] ? v[:callable].call : true)
end
marketing_names << [k, method_name]
end
define_method(:marketing_name) do
marketing_names.each do |mn|
break mn[0] if send(mn[1])
end
end
# Server Type checks
%w( core full datacenter ).each do |m|
define_method("server_#{m}?") do
if @sku
!(SKU[@sku][:name] =~ /#{m}/i).nil?
else
false
end
end
end
private
# Win32API call to GetSystemMetrics(SM_SERVERR2)
# returns: The build number if the system is Windows Server 2003 R2; otherwise, 0.
def sm_serverr2
@sm_serverr2 ||= Win32API.new('user32', 'GetSystemMetrics', 'I', 'I').call(SM_SERVERR2)
end
# query WMI Win32_OperatingSystem for required OS info
def get_os_info
cols = %w( Version ProductType OSProductSuite OperatingSystemSKU ServicePackMajorVersion ServicePackMinorVersion )
os_info = execute_wmi_query('select * from Win32_OperatingSystem').each.next
cols.map do |c|
begin
wmi_object_property(os_info, c)
rescue # OperatingSystemSKU doesn't exist in all versions of Windows
nil
end
end
end
end
end
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Cookbook:: windows
# Library:: version
#
# Copyright:: 2011-2017, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
if RUBY_PLATFORM =~ /mswin|mingw32|windows/
require_relative 'wmi_helper'
require 'Win32API'
end
module Windows
class Version
# http://msdn.microsoft.com/en-us/library/ms724833(v=vs.85).aspx
# Suite Masks
# Microsoft BackOffice components are installed.
VER_SUITE_BACKOFFICE = 0x00000004 unless defined?(VER_SUITE_BACKOFFICE)
# Windows Server 2003, Web Edition is installed.
VER_SUITE_BLADE = 0x00000400 unless defined?(VER_SUITE_BLADE)
# Windows Server 2003, Compute Cluster Edition is installed.
VER_SUITE_COMPUTE_SERVER = 0x00004000 unless defined?(VER_SUITE_COMPUTE_SERVER)
# Windows Server 2008 Datacenter, Windows Server 2003, Datacenter Edition, or Windows 2000 Datacenter Server is installed.
VER_SUITE_DATACENTER = 0x00000080 unless defined?(VER_SUITE_DATACENTER)
# Windows Server 2008 Enterprise, Windows Server 2003, Enterprise Edition, or Windows 2000 Advanced Server is installed. Refer to the Remarks section for more information about this bit flag.
VER_SUITE_ENTERPRISE = 0x00000002 unless defined?(VER_SUITE_ENTERPRISE)
# Windows XP Embedded is installed.
VER_SUITE_EMBEDDEDNT = 0x00000040 unless defined?(VER_SUITE_EMBEDDEDNT)
# Windows Vista Home Premium, Windows Vista Home Basic, or Windows XP Home Edition is installed.
VER_SUITE_PERSONAL = 0x00000200 unless defined?(VER_SUITE_PERSONAL)
# Remote Desktop is supported, but only one interactive session is supported. This value is set unless the system is running in application server mode.
VER_SUITE_SINGLEUSERTS = 0x00000100 unless defined?(VER_SUITE_SINGLEUSERTS)
# Microsoft Small Business Server was once installed on the system, but may have been upgraded to another version of Windows. Refer to the Remarks section for more information about this bit flag.
VER_SUITE_SMALLBUSINESS = 0x00000001 unless defined?(VER_SUITE_SMALLBUSINESS)
# Microsoft Small Business Server is installed with the restrictive client license in force. Refer to the Remarks section for more information about this bit flag.
VER_SUITE_SMALLBUSINESS_RESTRICTED = 0x00000020 unless defined?(VER_SUITE_SMALLBUSINESS_RESTRICTED)
# Windows Storage Server 2003 R2 or Windows Storage Server 2003is installed.
VER_SUITE_STORAGE_SERVER = 0x00002000 unless defined?(VER_SUITE_STORAGE_SERVER)
# Terminal Services is installed. This value is always set.
# If VER_SUITE_TERMINAL is set but VER_SUITE_SINGLEUSERTS is not set, the system is running in application server mode.
VER_SUITE_TERMINAL = 0x00000010 unless defined?(VER_SUITE_TERMINAL)
# Windows Home Server is installed.
VER_SUITE_WH_SERVER = 0x00008000 unless defined?(VER_SUITE_WH_SERVER)
# Product Type
# The system is a domain controller and the operating system is Windows Server 2012, Windows Server 2008 R2, Windows Server 2008, Windows Server 2003, or Windows 2000 Server.
VER_NT_DOMAIN_CONTROLLER = 0x0000002 unless defined?(VER_NT_DOMAIN_CONTROLLER)
# The operating system is Windows Server 2012, Windows Server 2008 R2, Windows Server 2008, Windows Server 2003, or Windows 2000 Server.
# Note that a server that is also a domain controller is reported as VER_NT_DOMAIN_CONTROLLER, not VER_NT_SERVER.
VER_NT_SERVER = 0x0000003 unless defined?(VER_NT_SERVER)
# The operating system is Windows 7, Windows Vista, Windows XP Professional, Windows XP Home Edition, or Windows 2000 Professional.
VER_NT_WORKSTATION = 0x0000001 unless defined?(VER_NT_WORKSTATION)
# GetSystemMetrics
# The build number if the system is Windows Server 2003 R2; otherwise, 0.
SM_SERVERR2 = 89 unless defined?(SM_SERVERR2)
# http://msdn.microsoft.com/en-us/library/ms724358(v=vs.85).aspx
SKU = {
0x00000006 => { ms_const: 'PRODUCT_BUSINESS', name: 'Business' },
0x00000010 => { ms_const: 'PRODUCT_BUSINESS_N', name: 'Business N' },
0x00000012 => { ms_const: 'PRODUCT_CLUSTER_SERVER', name: 'HPC Edition' },
0x00000008 => { ms_const: 'PRODUCT_DATACENTER_SERVER', name: 'Server Datacenter (full installation)' },
0x0000000C => { ms_const: 'PRODUCT_DATACENTER_SERVER_CORE', name: 'Server Datacenter (core installation)' },
0x00000027 => { ms_const: 'PRODUCT_DATACENTER_SERVER_CORE_V', name: 'Server Datacenter without Hyper-V (core installation)' },
0x00000025 => { ms_const: 'PRODUCT_DATACENTER_SERVER_V', name: 'Server Datacenter without Hyper-V (full installation)' },
0x00000004 => { ms_const: 'PRODUCT_ENTERPRISE', name: 'Enterprise' },
0x00000046 => { ms_const: 'PRODUCT_ENTERPRISE_E', name: 'Not supported' },
0x0000001B => { ms_const: 'PRODUCT_ENTERPRISE_N', name: 'Enterprise N' },
0x0000000A => { ms_const: 'PRODUCT_ENTERPRISE_SERVER', name: 'Server Enterprise (full installation)' },
0x0000000E => { ms_const: 'PRODUCT_ENTERPRISE_SERVER_CORE', name: 'Server Enterprise (core installation)' },
0x00000029 => { ms_const: 'PRODUCT_ENTERPRISE_SERVER_CORE_V', name: 'Server Enterprise without Hyper-V (core installation)' },
0x0000000F => { ms_const: 'PRODUCT_ENTERPRISE_SERVER_IA64', name: 'Server Enterprise for Itanium-based Systems' },
0x00000026 => { ms_const: 'PRODUCT_ENTERPRISE_SERVER_V', name: 'Server Enterprise without Hyper-V (full installation)' },
0x00000002 => { ms_const: 'PRODUCT_HOME_BASIC', name: 'Home Basic' },
0x00000043 => { ms_const: 'PRODUCT_HOME_BASIC_E', name: 'Not supported' },
0x00000005 => { ms_const: 'PRODUCT_HOME_BASIC_N', name: 'Home Basic N' },
0x00000003 => { ms_const: 'PRODUCT_HOME_PREMIUM', name: 'Home Premium' },
0x00000044 => { ms_const: 'PRODUCT_HOME_PREMIUM_E', name: 'Not supported' },
0x0000001A => { ms_const: 'PRODUCT_HOME_PREMIUM_N', name: 'Home Premium N' },
0x0000002A => { ms_const: 'PRODUCT_HYPERV', name: 'Microsoft Hyper-V Server' },
0x0000001E => { ms_const: 'PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT', name: 'Windows Essential Business Server Management Server' },
0x00000020 => { ms_const: 'PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING', name: 'Windows Essential Business Server Messaging Server' },
0x0000001F => { ms_const: 'PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY', name: 'Windows Essential Business Server Security Server' },
0x00000030 => { ms_const: 'PRODUCT_PROFESSIONAL', name: 'Professional' },
0x00000045 => { ms_const: 'PRODUCT_PROFESSIONAL_E', name: 'Not supported' },
0x00000031 => { ms_const: 'PRODUCT_PROFESSIONAL_N', name: 'Professional N' },
0x00000067 => { ms_const: 'PRODUCT_PROFESSIONAL_WMC', name: 'Professional with Media Center' },
0x00000018 => { ms_const: 'PRODUCT_SERVER_FOR_SMALLBUSINESS', name: 'Windows Server 2008 for Windows Essential Server Solutions' },
0x00000023 => { ms_const: 'PRODUCT_SERVER_FOR_SMALLBUSINESS_V', name: 'Windows Server 2008 without Hyper-V for Windows Essential Server Solutions' },
0x00000021 => { ms_const: 'PRODUCT_SERVER_FOUNDATION', name: 'Server Foundation' },
0x00000022 => { ms_const: 'PRODUCT_HOME_PREMIUM_SERVER', name: 'Windows Home Server 2011' },
0x00000032 => { ms_const: 'PRODUCT_SB_SOLUTION_SERVER', name: 'Windows Small Business Server 2011 Essentials' },
0x00000013 => { ms_const: 'PRODUCT_HOME_SERVER', name: 'Windows Storage Server 2008 R2 Essentials' },
0x00000009 => { ms_const: 'PRODUCT_SMALLBUSINESS_SERVER', name: 'Windows Small Business Server' },
0x00000038 => { ms_const: 'PRODUCT_SOLUTION_EMBEDDEDSERVER', name: 'Windows MultiPoint Server' },
0x00000007 => { ms_const: 'PRODUCT_STANDARD_SERVER', name: 'Server Standard (full installation)' },
0x0000000D => { ms_const: 'PRODUCT_STANDARD_SERVER_CORE', name: 'Server Standard (core installation)' },
0x00000028 => { ms_const: 'PRODUCT_STANDARD_SERVER_CORE_V', name: 'Server Standard without Hyper-V (core installation)' },
0x00000024 => { ms_const: 'PRODUCT_STANDARD_SERVER_V', name: 'Server Standard without Hyper-V (full installation)' },
0x0000000B => { ms_const: 'PRODUCT_STARTER', name: 'Starter' },
0x00000042 => { ms_const: 'PRODUCT_STARTER_E', name: 'Not supported' },
0x0000002F => { ms_const: 'PRODUCT_STARTER_N', name: 'Starter N' },
0x00000017 => { ms_const: 'PRODUCT_STORAGE_ENTERPRISE_SERVER', name: 'Storage Server Enterprise' },
0x00000014 => { ms_const: 'PRODUCT_STORAGE_EXPRESS_SERVER', name: 'Storage Server Express' },
0x00000015 => { ms_const: 'PRODUCT_STORAGE_STANDARD_SERVER', name: 'Storage Server Standard' },
0x00000016 => { ms_const: 'PRODUCT_STORAGE_WORKGROUP_SERVER', name: 'Storage Server Workgroup' },
0x00000000 => { ms_const: 'PRODUCT_UNDEFINED', name: 'An unknown product' },
0x00000001 => { ms_const: 'PRODUCT_ULTIMATE', name: 'Ultimate' },
0x00000047 => { ms_const: 'PRODUCT_ULTIMATE_E', name: 'Not supported' },
0x0000001C => { ms_const: 'PRODUCT_ULTIMATE_N', name: 'Ultimate N' },
0x00000011 => { ms_const: 'PRODUCT_WEB_SERVER', name: 'Web Server (full installation)' },
0x0000001D => { ms_const: 'PRODUCT_WEB_SERVER_CORE', name: 'Web Server (core installation)' },
}.freeze unless defined?(SKU)
attr_reader :major_version, :minor_version, :build_number, :service_pack_major_version, :service_pack_minor_version
attr_reader :version, :product_type, :product_suite, :sku
def initialize
unless RUBY_PLATFORM =~ /mswin|mingw32|windows/
raise NotImplementedError, 'only valid on Windows platform'
end
@version, @product_type, @product_suite, @sku, @service_pack_major_version, @service_pack_minor_version = get_os_info
@major_version, @minor_version, @build_number = version.split('.').map(&:to_i)
end
WIN_VERSIONS = {
'Windows Server 2012 R2' => { major: 6, minor: 3, callable: -> { @product_type != VER_NT_WORKSTATION } },
'Windows 8' => { major: 6, minor: 2, callable: -> { @product_type == VER_NT_WORKSTATION } },
'Windows Server 2012' => { major: 6, minor: 2, callable: -> { @product_type != VER_NT_WORKSTATION } },
'Windows 7' => { major: 6, minor: 1, callable: -> { @product_type == VER_NT_WORKSTATION } },
'Windows Server 2008 R2' => { major: 6, minor: 1, callable: -> { @product_type != VER_NT_WORKSTATION } },
'Windows Server 2008' => { major: 6, minor: 0, callable: -> { @product_type != VER_NT_WORKSTATION } },
'Windows Vista' => { major: 6, minor: 0, callable: -> { @product_type == VER_NT_WORKSTATION } },
'Windows Server 2003 R2' => { major: 5, minor: 2, callable: -> { Win32API.new('user32', 'GetSystemMetrics', 'I', 'I').call(SM_SERVERR2) != 0 } },
'Windows Home Server' => { major: 5, minor: 2, callable: -> { (@product_suite & VER_SUITE_WH_SERVER) == VER_SUITE_WH_SERVER } },
'Windows Server 2003' => { major: 5, minor: 2, callable: -> { Win32API.new('user32', 'GetSystemMetrics', 'I', 'I').call(SM_SERVERR2) == 0 } },
'Windows XP' => { major: 5, minor: 1 },
'Windows 2000' => { major: 5, minor: 0 },
}.freeze unless defined?(WIN_VERSIONS)
marketing_names = []
# General Windows checks
WIN_VERSIONS.each do |k, v|
method_name = "#{k.gsub(/\s/, '_').downcase}?"
define_method(method_name) do
(@major_version == v[:major]) &&
(@minor_version == v[:minor]) &&
(v[:callable] ? v[:callable].call : true)
end
marketing_names << [k, method_name]
end
define_method(:marketing_name) do
marketing_names.each do |mn|
break mn[0] if send(mn[1])
end
end
# Server Type checks
%w( core full datacenter ).each do |m|
define_method("server_#{m}?") do
if @sku
!(SKU[@sku][:name] =~ /#{m}/i).nil?
else
false
end
end
end
private
# Win32API call to GetSystemMetrics(SM_SERVERR2)
# returns: The build number if the system is Windows Server 2003 R2; otherwise, 0.
def sm_serverr2
@sm_serverr2 ||= Win32API.new('user32', 'GetSystemMetrics', 'I', 'I').call(SM_SERVERR2)
end
# query WMI Win32_OperatingSystem for required OS info
def get_os_info
cols = %w( Version ProductType OSProductSuite OperatingSystemSKU ServicePackMajorVersion ServicePackMinorVersion )
os_info = execute_wmi_query('select * from Win32_OperatingSystem').each.next
cols.map do |c|
begin
wmi_object_property(os_info, c)
rescue # OperatingSystemSKU doesn't exist in all versions of Windows
nil
end
end
end
end
end

View File

@@ -0,0 +1,79 @@
#
# Cookbook:: windows
# Library:: version_helper
# Author:: Baptiste Courtois (<b.courtois@criteo.com>)
#
# Copyright:: 2015-2017, Criteo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
module Windows
# Module based on windows ohai kernel.cs_info providing version helpers
module VersionHelper
# Module referencing CORE SKU contants from product type
# see. https://msdn.microsoft.com/windows/desktop/ms724358#PRODUCT_DATACENTER_SERVER_CORE
# n.b. Prefix - PRODUCT_ - and suffix - _CORE- have been removed
module CoreSKU
# Server Datacenter Core
DATACENTER_SERVER = 0x0C unless constants.include?(:DATACENTER_SERVER)
# Server Datacenter without Hyper-V Core
DATACENTER_SERVER_V = 0x27 unless constants.include?(:DATACENTER_SERVER_V)
# Server Enterprise Core
ENTERPRISE_SERVER = 0x0E unless constants.include?(:ENTERPRISE_SERVER)
# Server Enterprise without Hyper-V Core
ENTERPRISE_SERVER_V = 0x29 unless constants.include?(:ENTERPRISE_SERVER_V)
# Server Standard Core
STANDARD_SERVER = 0x0D unless constants.include?(:STANDARD_SERVER)
# Server Standard without Hyper-V Core
STANDARD_SERVER_V = 0x28 unless constants.include?(:STANDARD_SERVER_V)
end
# Module referencing product type contants
# see. https://msdn.microsoft.com/windows/desktop/ms724833#VER_NT_SERVER
# n.b. Prefix - VER_NT_ - has been removed
module ProductType
WORKSTATION = 0x1 unless constants.include?(:WORKSTATION)
DOMAIN_CONTROLLER = 0x2 unless constants.include?(:DOMAIN_CONTROLLER)
SERVER = 0x3 unless constants.include?(:SERVER)
end
# Determines whether current node is running a windows Core version
def self.core_version?(node)
validate_platform node
CoreSKU.constants.any? { |c| CoreSKU.const_get(c) == node['kernel']['os_info']['operating_system_sku'] }
end
# Determines whether current node is a workstation version
def self.workstation_version?(node)
validate_platform node
node['kernel']['os_info']['product_type'] == ProductType::WORKSTATION
end
# Determines whether current node is a server version
def self.server_version?(node)
!workstation_version?(node)
end
# Determines NT version of the current node
def self.nt_version(node)
validate_platform node
node['platform_version'].to_f
end
def self.validate_platform(node)
raise 'Windows helper are only supported on windows platform!' if node['platform'] != 'windows'
end
end
end

View File

@@ -1,86 +0,0 @@
# Try to include from core chef, if error then monkey patch it in.
begin
include Chef::Mixin::WindowsArchitectureHelper
rescue
Chef::Log.debug('Chef::Mixin::WindowsArchitectureHelper not in core version, Monkey patching in.')
require 'chef/exceptions'
require 'win32/api' if Chef::Platform.windows?
class Chef
module Mixin
module WindowsArchitectureHelper
def node_windows_architecture(node)
node['kernel']['machine'].to_sym
end
def wow64_architecture_override_required?(node, desired_architecture)
i386_windows_process? &&
node_windows_architecture(node) == :x86_64 &&
desired_architecture == :x86_64
end
def node_supports_windows_architecture?(node, desired_architecture)
assert_valid_windows_architecture!(desired_architecture)
(node_windows_architecture(node) == :x86_64 ||
desired_architecture == :i386) ? true : false
end
def valid_windows_architecture?(architecture)
(architecture == :x86_64) || (architecture == :i386)
end
def assert_valid_windows_architecture!(architecture)
unless valid_windows_architecture?(architecture)
raise Chef::Exceptions::Win32ArchitectureIncorrect,
'The specified architecture was not valid. It must be one of :i386 or :x86_64'
end
end
def i386_windows_process?
Chef::Platform.windows? && 'X86'.casecmp(ENV['PROCESSOR_ARCHITECTURE']) == 0
end
def disable_wow64_file_redirection(node)
original_redirection_state = ['0'].pack('P')
if (node_windows_architecture(node) == :x86_64) && ::Chef::Platform.windows?
win32_wow_64_disable_wow_64_fs_redirection =
::Win32::API.new('Wow64DisableWow64FsRedirection', 'P', 'L', 'kernel32')
succeeded = win32_wow_64_disable_wow_64_fs_redirection.call(original_redirection_state)
if succeeded == 0
raise Win32APIError 'Failed to disable Wow64 file redirection'
end
end
original_redirection_state
end
def restore_wow64_file_redirection(node, original_redirection_state)
if (node_windows_architecture(node) == :x86_64) && ::Chef::Platform.windows?
win32_wow_64_revert_wow_64_fs_redirection =
::Win32::API.new('Wow64RevertWow64FsRedirection', 'P', 'L', 'kernel32')
succeeded = win32_wow_64_revert_wow_64_fs_redirection.call(original_redirection_state)
if succeeded == 0
raise Win32APIError 'Failed to revert Wow64 file redirection'
end
end
end
end
end
end
end
# Making sure this library is available to Chef::Mixin::PowershellOut
# Required for clients that don't have Chef::Mixin::WindowsArchitectureHelper in
# core chef.
if ::Chef::Platform.windows?
require_relative 'powershell_out'
Chef::Mixin::PowershellOut.send(:include, Chef::Mixin::WindowsArchitectureHelper)
end

View File

@@ -1,168 +1,174 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Cookbook Name:: windows
# Library:: helper
#
# Copyright:: 2011-2015, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require 'uri'
require 'Win32API' if Chef::Platform.windows?
require 'chef/exceptions'
module Windows
module Helper
AUTO_RUN_KEY = 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run'.freeze unless defined?(AUTO_RUN_KEY)
ENV_KEY = 'HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment'.freeze unless defined?(ENV_KEY)
ExpandEnvironmentStrings = Win32API.new('kernel32', 'ExpandEnvironmentStrings', %w(P P L), 'L') if Chef::Platform.windows? && !defined?(ExpandEnvironmentStrings)
# returns windows friendly version of the provided path,
# ensures backslashes are used everywhere
def win_friendly_path(path)
path.gsub(::File::SEPARATOR, ::File::ALT_SEPARATOR || '\\') if path
end
# account for Window's wacky File System Redirector
# http://msdn.microsoft.com/en-us/library/aa384187(v=vs.85).aspx
# especially important for 32-bit processes (like Ruby) on a
# 64-bit instance of Windows.
def locate_sysnative_cmd(cmd)
if ::File.exist?("#{ENV['WINDIR']}\\sysnative\\#{cmd}")
"#{ENV['WINDIR']}\\sysnative\\#{cmd}"
elsif ::File.exist?("#{ENV['WINDIR']}\\system32\\#{cmd}")
"#{ENV['WINDIR']}\\system32\\#{cmd}"
else
cmd
end
end
# Create a feature provider dependent value object.
# mainly created becasue Windows Feature names are
# different based on whether dism.exe or servicemanagercmd.exe
# is used for installation
def value_for_feature_provider(provider_hash)
p = Chef::Platform.find_provider_for_node(node, :windows_feature)
key = p.to_s.downcase.split('::').last
provider_hash[key] || provider_hash[key.to_sym]
end
# singleton instance of the Windows Version checker
def win_version
@win_version ||= Windows::Version.new
end
# Helper function to properly parse a URI
def as_uri(source)
URI.parse(source)
rescue URI::InvalidURIError
Chef::Log.warn("#{source} was an invalid URI. Trying to escape invalid characters")
URI.parse(URI.escape(source))
end
# if a file is local it returns a windows friendly path version
# if a file is remote it caches it locally
def cached_file(source, checksum = nil, windows_path = true)
@installer_file_path ||= begin
if source =~ /^(file|ftp|http|https):\/\//
uri = as_uri(source)
cache_file_path = "#{Chef::Config[:file_cache_path]}/#{::File.basename(::URI.unescape(uri.path))}"
Chef::Log.debug("Caching a copy of file #{source} at #{cache_file_path}")
r = Chef::Resource::RemoteFile.new(cache_file_path, run_context)
r.source(source)
r.backup(false)
r.checksum(checksum) if checksum
r.run_action(:create)
else
cache_file_path = source
end
windows_path ? win_friendly_path(cache_file_path) : cache_file_path
end
end
# Expands the environment variables
def expand_env_vars(path)
# We pick 32k because that is the largest it could be:
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms724265%28v=vs.85%29.aspx
buf = 0.chr * 32 * 1024 # 32k
if ExpandEnvironmentStrings.call(path.dup, buf, buf.length) == 0
fail Chef::Exceptions::Win32APIError, 'Failed calling ExpandEnvironmentStrings (received 0)'
end
buf.strip
end
def is_package_installed?(package_name) # rubocop:disable Style/PredicateName
installed_packages.include?(package_name)
end
def installed_packages
@installed_packages || begin
installed_packages = {}
# Computer\HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall
installed_packages.merge!(extract_installed_packages_from_key(::Win32::Registry::HKEY_LOCAL_MACHINE)) # rescue nil
# 64-bit registry view
# Computer\HKEY_LOCAL_MACHINE\Software\Wow6464Node\Microsoft\Windows\CurrentVersion\Uninstall
installed_packages.merge!(extract_installed_packages_from_key(::Win32::Registry::HKEY_LOCAL_MACHINE, (::Win32::Registry::Constants::KEY_READ | 0x0100))) # rescue nil
# 32-bit registry view
# Computer\HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
installed_packages.merge!(extract_installed_packages_from_key(::Win32::Registry::HKEY_LOCAL_MACHINE, (::Win32::Registry::Constants::KEY_READ | 0x0200))) # rescue nil
# Computer\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Uninstall
installed_packages.merge!(extract_installed_packages_from_key(::Win32::Registry::HKEY_CURRENT_USER)) # rescue nil
installed_packages
end
end
private
def extract_installed_packages_from_key(hkey = ::Win32::Registry::HKEY_LOCAL_MACHINE, desired = ::Win32::Registry::Constants::KEY_READ)
uninstall_subkey = 'Software\Microsoft\Windows\CurrentVersion\Uninstall'
packages = {}
begin
::Win32::Registry.open(hkey, uninstall_subkey, desired) do |reg|
reg.each_key do |key, _wtime|
begin
k = reg.open(key, desired)
display_name = begin
k['DisplayName']
rescue
nil
end
version = begin
k['DisplayVersion']
rescue
'NO VERSION'
end
uninstall_string = begin
k['UninstallString']
rescue
nil
end
if display_name
packages[display_name] = { name: display_name,
version: version,
uninstall_string: uninstall_string }
end
rescue ::Win32::Registry::Error
end
end
end
rescue ::Win32::Registry::Error
end
packages
end
end
end
Chef::Recipe.send(:include, Windows::Helper)
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Cookbook:: windows
# Library:: helper
#
# Copyright:: 2011-2017, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require 'uri'
require 'Win32API' if Chef::Platform.windows?
require 'chef/exceptions'
module Windows
module Helper
AUTO_RUN_KEY = 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run'.freeze unless defined?(AUTO_RUN_KEY)
ENV_KEY = 'HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment'.freeze unless defined?(ENV_KEY)
ExpandEnvironmentStrings = Win32API.new('kernel32', 'ExpandEnvironmentStrings', %w(P P L), 'L') if Chef::Platform.windows? && !defined?(ExpandEnvironmentStrings)
# returns windows friendly version of the provided path,
# ensures backslashes are used everywhere
def win_friendly_path(path)
path.gsub(::File::SEPARATOR, ::File::ALT_SEPARATOR || '\\') if path
end
# account for Window's wacky File System Redirector
# http://msdn.microsoft.com/en-us/library/aa384187(v=vs.85).aspx
# especially important for 32-bit processes (like Ruby) on a
# 64-bit instance of Windows.
def locate_sysnative_cmd(cmd)
if ::File.exist?("#{ENV['WINDIR']}\\sysnative\\#{cmd}")
"#{ENV['WINDIR']}\\sysnative\\#{cmd}"
elsif ::File.exist?("#{ENV['WINDIR']}\\system32\\#{cmd}")
"#{ENV['WINDIR']}\\system32\\#{cmd}"
else
cmd
end
end
# Create a feature provider dependent value object.
# mainly created becasue Windows Feature names are
# different based on whether dism.exe or servicemanagercmd.exe
# is used for installation
def value_for_feature_provider(provider_hash)
p = Chef::Platform.find_provider_for_node(node, :windows_feature)
key = p.to_s.downcase.split('::').last
provider_hash[key] || provider_hash[key.to_sym]
end
# singleton instance of the Windows Version checker
def win_version
@win_version ||= Windows::Version.new
end
# Helper function to properly parse a URI
def as_uri(source)
URI.parse(source)
rescue URI::InvalidURIError
Chef::Log.warn("#{source} was an invalid URI. Trying to escape invalid characters")
URI.parse(URI.escape(source))
end
# if a file is local it returns a windows friendly path version
# if a file is remote it caches it locally
def cached_file(source, checksum = nil, windows_path = true)
@installer_file_path ||= begin
if source =~ %r{^(file|ftp|http|https):\/\/}
uri = as_uri(source)
cache_file_path = "#{Chef::Config[:file_cache_path]}/#{::File.basename(::URI.unescape(uri.path))}"
Chef::Log.debug("Caching a copy of file #{source} at #{cache_file_path}")
remote_file cache_file_path do
source source
backup false
checksum checksum unless checksum.nil?
end.run_action(:create)
else
cache_file_path = source
end
windows_path ? win_friendly_path(cache_file_path) : cache_file_path
end
end
# Expands the environment variables
def expand_env_vars(path)
# We pick 32k because that is the largest it could be:
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms724265%28v=vs.85%29.aspx
buf = 0.chr * 32 * 1024 # 32k
if ExpandEnvironmentStrings.call(path.dup, buf, buf.length) == 0
raise Chef::Exceptions::Win32APIError, 'Failed calling ExpandEnvironmentStrings (received 0)'
end
buf.strip
end
def is_package_installed?(package_name) # rubocop:disable Style/PredicateName
installed_packages.include?(package_name)
end
def installed_packages
@installed_packages || begin
installed_packages = {}
# Computer\HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall
installed_packages.merge!(extract_installed_packages_from_key(::Win32::Registry::HKEY_LOCAL_MACHINE)) # rescue nil
# 64-bit registry view
# Computer\HKEY_LOCAL_MACHINE\Software\Wow6464Node\Microsoft\Windows\CurrentVersion\Uninstall
installed_packages.merge!(extract_installed_packages_from_key(::Win32::Registry::HKEY_LOCAL_MACHINE, (::Win32::Registry::Constants::KEY_READ | 0x0100))) # rescue nil
# 32-bit registry view
# Computer\HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
installed_packages.merge!(extract_installed_packages_from_key(::Win32::Registry::HKEY_LOCAL_MACHINE, (::Win32::Registry::Constants::KEY_READ | 0x0200))) # rescue nil
# Computer\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Uninstall
installed_packages.merge!(extract_installed_packages_from_key(::Win32::Registry::HKEY_CURRENT_USER)) # rescue nil
installed_packages
end
end
# Returns an array
def to_array(var)
var = var.is_a?(Array) ? var : [var]
var.reject(&:nil?)
end
private
def extract_installed_packages_from_key(hkey = ::Win32::Registry::HKEY_LOCAL_MACHINE, desired = ::Win32::Registry::Constants::KEY_READ)
uninstall_subkey = 'Software\Microsoft\Windows\CurrentVersion\Uninstall'
packages = {}
begin
::Win32::Registry.open(hkey, uninstall_subkey, desired) do |reg|
reg.each_key do |key, _wtime|
begin
k = reg.open(key, desired)
display_name = begin
k['DisplayName']
rescue
nil
end
version = begin
k['DisplayVersion']
rescue
'NO VERSION'
end
uninstall_string = begin
k['UninstallString']
rescue
nil
end
if display_name
packages[display_name] = { name: display_name,
version: version,
uninstall_string: uninstall_string }
end
rescue ::Win32::Registry::Error
end
end
end
rescue ::Win32::Registry::Error
end
packages
end
end
end
Chef::Recipe.send(:include, Windows::Helper)

View File

@@ -1,226 +0,0 @@
require 'chef/resource/lwrp_base'
require 'chef/provider/lwrp_base'
require 'win32/registry' if RUBY_PLATFORM =~ /mswin|mingw32|windows/
require 'chef/mixin/shell_out'
require 'chef/mixin/language'
class Chef
class Provider
class WindowsCookbookPackage < Chef::Provider::LWRPBase
include Chef::Mixin::ShellOut
include Windows::Helper
# the logic in all action methods mirror that of
# the Chef::Provider::Package which will make
# refactoring into core chef easy
action :install do
# If we specified a version, and it's not the current version, move to the specified version
if !@new_resource.version.nil? && @new_resource.version != @current_resource.version
install_version = @new_resource.version
# If it's not installed at all, install it
elsif @current_resource.version.nil?
install_version = candidate_version
end
if install_version
Chef::Log.info("Installing #{@new_resource} version #{install_version}")
status = install_package(@new_resource.package_name, install_version)
new_resource.updated_by_last_action(true) if status
end
end
action :upgrade do
if @current_resource.version != candidate_version
orig_version = @current_resource.version || 'uninstalled'
Chef::Log.info("Upgrading #{@new_resource} version from #{orig_version} to #{candidate_version}")
status = upgrade_package(@new_resource.package_name, candidate_version)
new_resource.updated_by_last_action(true) if status
end
end
action :remove do
if removing_package?
Chef::Log.info("Removing #{@new_resource}")
remove_package(@current_resource.package_name, @new_resource.version)
new_resource.updated_by_last_action(true)
end
end
def removing_package?
if @current_resource.version.nil?
false # nothing to remove
elsif @new_resource.version.nil?
true # remove any version of a package
elsif @new_resource.version == @current_resource.version
true # remove the version we have
else
false # we don't have the version we want to remove
end
end
def expand_options(options)
options ? " #{options}" : ''
end
# these methods are the required overrides of
# a provider that extends from Chef::Provider::Package
# so refactoring into core Chef should be easy
def load_current_resource
@current_resource = Chef::Resource::WindowsPackage.new(@new_resource.name)
@current_resource.package_name(@new_resource.package_name)
@current_resource.version(nil)
unless current_installed_version.nil?
@current_resource.version(current_installed_version)
end
@current_resource
end
def current_installed_version
@current_installed_version ||= begin
if installed_packages.include?(@new_resource.package_name)
installed_packages[@new_resource.package_name][:version]
end
end
end
def candidate_version
@candidate_version ||= begin
@new_resource.version || 'latest'
end
end
def install_package(_name, _version)
Chef::Log.debug("Processing #{@new_resource} as a #{installer_type} installer.")
install_args = [cached_file(@new_resource.source, @new_resource.checksum), expand_options(unattended_installation_flags), expand_options(@new_resource.options)]
Chef::Log.info('Starting installation...this could take awhile.')
Chef::Log.debug "Install command: #{sprintf(install_command_template, *install_args)}"
shell_out!(sprintf(install_command_template, *install_args), timeout: @new_resource.timeout, returns: @new_resource.success_codes)
end
def remove_package(_name, _version)
uninstall_string = installed_packages[@new_resource.package_name][:uninstall_string]
Chef::Log.info("Registry provided uninstall string for #{@new_resource} is '#{uninstall_string}'")
uninstall_command = begin
if uninstall_string =~ /msiexec/i
"#{uninstall_string} /qn"
else
uninstall_string.delete!('"')
"start \"\" /wait /d\"#{::File.dirname(uninstall_string)}\" #{::File.basename(uninstall_string)}#{expand_options(@new_resource.options)} /S & exit %%%%ERRORLEVEL%%%%"
end
end
Chef::Log.info("Removing #{@new_resource} with uninstall command '#{uninstall_command}'")
shell_out!(uninstall_command, { returns: @new_resource.success_codes })
end
private
def install_command_template
case installer_type
when :msi
"msiexec%2$s \"%1$s\"%3$s"
else
"start \"\" /wait \"%1$s\"%2$s%3$s & exit %%%%ERRORLEVEL%%%%"
end
end
# http://unattended.sourceforge.net/installers.php
def unattended_installation_flags
case installer_type
when :msi
# this is no-ui
'/qn /i'
when :installshield
'/s /sms'
when :nsis
'/S /NCRC'
when :inno
# "/sp- /silent /norestart"
'/verysilent /norestart'
when :wise
'/s'
end
end
def installer_type
@installer_type || begin
if @new_resource.installer_type
@new_resource.installer_type
else
basename = ::File.basename(cached_file(@new_resource.source, @new_resource.checksum))
if basename.split('.').last.downcase == 'msi' # Microsoft MSI
:msi
else
# search the binary file for installer type
contents = ::Kernel.open(::File.expand_path(cached_file(@new_resource.source)), 'rb', &:read) # TODO: limit data read in
case contents
when /inno/i # Inno Setup
:inno
when /wise/i # Wise InstallMaster
:wise
when /nsis/i # Nullsoft Scriptable Install System
:nsis
else
# if file is named 'setup.exe' assume installshield
if basename == 'setup.exe'
:installshield
else
fail Chef::Exceptions::AttributeNotFound, 'installer_type could not be determined, please set manually'
end
end
end
end
end
end
end
end
end
class Chef
class Resource
class WindowsCookbookPackage < Chef::Resource::LWRPBase
if Gem::Version.new(Chef::VERSION) >= Gem::Version.new('12.4.0')
provides :windows_package, os: 'windows', override: true
elsif Gem::Version.new(Chef::VERSION) >= Gem::Version.new('12')
provides :windows_package, os: 'windows'
end
actions :install, :remove
default_action :install
attribute :package_name, kind_of: String, name_attribute: true
attribute :source, kind_of: String, required: true
attribute :version, kind_of: String
attribute :options, kind_of: String
attribute :installer_type, kind_of: Symbol, default: nil, equal_to: [:msi, :inno, :nsis, :wise, :installshield, :custom]
attribute :checksum, kind_of: String
attribute :timeout, kind_of: Integer, default: 600
attribute :success_codes, kind_of: Array, default: [0, 42, 127]
self.resource_name = 'windows_package'
def initialize(*args)
super
@provider = Chef::Provider::WindowsCookbookPackage
end
end
end
end
if Gem::Version.new(Chef::VERSION) < Gem::Version.new('12')
# this wires up the cookbook version of the windows_package resource as Chef::Resource::WindowsPackage,
# which is kinda hella janky
Chef::Resource.send(:remove_const, :WindowsPackage) if defined? Chef::Resource::WindowsPackage
Chef::Resource.const_set('WindowsPackage', Chef::Resource::WindowsCookbookPackage)
else
if Chef.respond_to?(:set_resource_priority_array)
# this wires up the dynamic resource resolver to favor the cookbook version of windows_package over
# the internal version (but the internal Chef::Resource::WindowsPackage is still the internal version
# and a wrapper cookbook can override this e.g. for users that want to use the windows cookbook but
# want the internal windows_package resource)
Chef.set_resource_priority_array(:windows_package, [Chef::Resource::WindowsCookbookPackage], platform: 'windows')
end
end

View File

@@ -1,103 +1,103 @@
#
# Author:: Doug MacEachern <dougm@vmware.com>
# Author:: Paul Morton (<pmorton@biaprotect.com>)
# Cookbook Name:: windows
# Library:: windows_privileged
#
# Copyright:: 2010, VMware, Inc.
# Copyright:: 2011, Business Intelligence Associates, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# helpers for Windows API calls that require privilege adjustments
class Chef
class WindowsPrivileged
# File -> Load Hive... in regedit.exe
def reg_load_key(name, file)
load_deps
run(SE_BACKUP_NAME, SE_RESTORE_NAME) do
rc = RegLoadKey(HKEY_USERS, name.to_s, file)
if rc == ERROR_SUCCESS
return true
elsif rc == ERROR_SHARING_VIOLATION
return false
else
fail get_last_error(rc)
end
end
end
# File -> Unload Hive... in regedit.exe
def reg_unload_key(name)
load_deps
run(SE_BACKUP_NAME, SE_RESTORE_NAME) do
rc = RegUnLoadKey(HKEY_USERS, name.to_s)
fail get_last_error(rc) if rc != ERROR_SUCCESS
end
end
def run(*privileges)
load_deps
token = [0].pack('L')
unless OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, token)
fail get_last_error
end
token = token.unpack('L')[0]
privileges.each do |name|
unless adjust_privilege(token, name, SE_PRIVILEGE_ENABLED)
fail get_last_error
end
end
begin
yield
ensure # disable privs
privileges.each do |name|
adjust_privilege(token, name, 0)
end
end
end
def adjust_privilege(token, priv, attr = 0)
load_deps
luid = [0, 0].pack('Ll')
if LookupPrivilegeValue(nil, priv, luid)
new_state = [1, luid.unpack('Ll'), attr].flatten.pack('LLlL')
AdjustTokenPrivileges(token, 0, new_state, new_state.size, 0, 0)
end
end
private
def load_deps
if RUBY_PLATFORM =~ /mswin|mingw32|windows/
require 'windows/error'
require 'windows/registry'
require 'windows/process'
require 'windows/security'
include Windows::Error
include Windows::Registry
include Windows::Process
include Windows::Security
end
end
end
end
#
# Author:: Doug MacEachern <dougm@vmware.com>
# Author:: Paul Morton (<pmorton@biaprotect.com>)
# Cookbook:: windows
# Library:: windows_privileged
#
# Copyright:: 2010-2017, VMware, Inc.
# Copyright:: 2011-2017, Business Intelligence Associates, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# helpers for Windows API calls that require privilege adjustments
class Chef
class WindowsPrivileged
# File -> Load Hive... in regedit.exe
def reg_load_key(name, file)
load_deps
run(SE_BACKUP_NAME, SE_RESTORE_NAME) do
rc = RegLoadKey(HKEY_USERS, name.to_s, file)
if rc == ERROR_SUCCESS
return true
elsif rc == ERROR_SHARING_VIOLATION
return false
else
raise get_last_error(rc)
end
end
end
# File -> Unload Hive... in regedit.exe
def reg_unload_key(name)
load_deps
run(SE_BACKUP_NAME, SE_RESTORE_NAME) do
rc = RegUnLoadKey(HKEY_USERS, name.to_s)
raise get_last_error(rc) if rc != ERROR_SUCCESS
end
end
def run(*privileges)
load_deps
token = [0].pack('L')
unless OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, token)
raise get_last_error
end
token = token.unpack('L')[0]
privileges.each do |name|
unless adjust_privilege(token, name, SE_PRIVILEGE_ENABLED)
raise get_last_error
end
end
begin
yield
ensure # disable privs
privileges.each do |name|
adjust_privilege(token, name, 0)
end
end
end
def adjust_privilege(token, priv, attr = 0)
load_deps
luid = [0, 0].pack('Ll')
if LookupPrivilegeValue(nil, priv, luid)
new_state = [1, luid.unpack('Ll'), attr].flatten.pack('LLlL')
AdjustTokenPrivileges(token, 0, new_state, new_state.size, 0, 0)
end
end
private
def load_deps
if RUBY_PLATFORM =~ /mswin|mingw32|windows/
require 'windows/error'
require 'windows/registry'
require 'windows/process'
require 'windows/security'
include Windows::Error
include Windows::Registry
include Windows::Process
include Windows::Security
end
end
end
end

View File

@@ -1,32 +1,32 @@
#
# Author:: Adam Edwards (<adamed@chef.io>)
#
# Copyright:: 2014-2015, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
if RUBY_PLATFORM =~ /mswin|mingw32|windows/
require 'win32ole'
def execute_wmi_query(wmi_query)
wmi = ::WIN32OLE.connect('winmgmts://')
result = wmi.ExecQuery(wmi_query)
return nil unless result.each.count > 0
result
end
def wmi_object_property(wmi_object, wmi_property)
wmi_object.send(wmi_property)
end
end
#
# Author:: Adam Edwards (<adamed@chef.io>)
#
# Copyright:: 2014-2017, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
if RUBY_PLATFORM =~ /mswin|mingw32|windows/
require 'win32ole'
def execute_wmi_query(wmi_query)
wmi = ::WIN32OLE.connect('winmgmts://')
result = wmi.ExecQuery(wmi_query)
return nil unless result.each.count > 0
result
end
def wmi_object_property(wmi_object, wmi_property)
wmi_object.send(wmi_property)
end
end