class Chef::Resource::WindowsFeaturePowershell

Public Instance Methods

add_to_feature_mash(feature_type, feature_details) click to toggle source

add the features values to the appropriate array @return [void]

# File lib/chef/resource/windows_feature_powershell.rb, line 239
def add_to_feature_mash(feature_type, feature_details)
  # add the lowercase feature name to the mash unless we're on < 2012 where they're case sensitive
  node.override["powershell_features_cache"][feature_type] << (older_than_win_2012_or_8? ? feature_details : feature_details.downcase)
end
fail_if_removed() click to toggle source

Fail if any of the packages are in a removed state @return [void]

# File lib/chef/resource/windows_feature_powershell.rb, line 246
def fail_if_removed
  return if new_resource.source # if someone provides a source then all is well
  if node["platform_version"].to_f > 6.2 # 2012R2 or later
    return if registry_key_exists?('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing') && registry_value_exists?('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing', name: "LocalSourcePath") # if source is defined in the registry, still fine
  end
  removed = new_resource.feature_name & node["powershell_features_cache"]["removed"]
  raise "The Windows feature#{'s' if removed.count > 1} #{removed.join(',')} #{removed.count > 1 ? 'are' : 'is'} removed from the host and cannot be installed." unless removed.empty?
end
fail_if_unavailable() click to toggle source

if any features are not supported on this release of Windows or have been deleted raise with a friendly message. At one point in time we just warned, but this goes against the behavior of ever other package provider in Chef and it isn't clear what you'd want if you passed an array and some features were available and others were not. @return [void]

# File lib/chef/resource/windows_feature_powershell.rb, line 191
def fail_if_unavailable
  all_available = node["powershell_features_cache"]["enabled"] +
    node["powershell_features_cache"]["disabled"] +
    node["powershell_features_cache"]["removed"]

  # the difference of desired features to install to all features is what's not available
  unavailable = (new_resource.feature_name - all_available)
  raise "The Windows feature#{'s' if unavailable.count > 1} #{unavailable.join(',')} #{unavailable.count > 1 ? 'are' : 'is'} not available on this version of Windows. Run 'Get-WindowsFeature' to see the list of available feature names." unless unavailable.empty?
end
features_to_delete() click to toggle source

@return [Array] features the user has requested to delete which need deleting

# File lib/chef/resource/windows_feature_powershell.rb, line 176
def features_to_delete
  # the intersection of the features to remove & enabled/disabled features are what needs removing
  @remove ||= begin
    all_available = node["powershell_features_cache"]["enabled"] +
      node["powershell_features_cache"]["disabled"]
    new_resource.feature_name & all_available
  end
end
features_to_install() click to toggle source

@return [Array] features the user has requested to install which need installation

# File lib/chef/resource/windows_feature_powershell.rb, line 164
def features_to_install
  # the intersection of the features to install & disabled features are what needs installing
  @install ||= new_resource.feature_name & node["powershell_features_cache"]["disabled"]
end
features_to_remove() click to toggle source

@return [Array] features the user has requested to remove which need removing

# File lib/chef/resource/windows_feature_powershell.rb, line 170
def features_to_remove
  # the intersection of the features to remove & enabled features are what needs removing
  @remove ||= new_resource.feature_name & node["powershell_features_cache"]["enabled"]
end
install_feature_cmdlet() click to toggle source

The appropriate cmdlet to install a windows feature based on windows release @return [String]

# File lib/chef/resource/windows_feature_powershell.rb, line 153
def install_feature_cmdlet
  older_than_win_2012_or_8? ? "Add-WindowsFeature" : "Install-WindowsFeature"
end
parsed_feature_list() click to toggle source

fetch the list of available feature names and state in JSON and parse the JSON

# File lib/chef/resource/windows_feature_powershell.rb, line 225
def parsed_feature_list
  # Grab raw feature information from dism command line
  # Windows < 2012 doesn't present a state value so we have to check if the feature is installed or not
  raw_list_of_features = if older_than_win_2012_or_8? # make the older format look like the new format, warts and all
                           powershell_out!('Get-WindowsFeature | Select-Object -Property Name, @{Name="InstallState"; Expression = {If ($_.Installed) { 1 } Else { 0 }}} | ConvertTo-Json -Compress', timeout: new_resource.timeout).stdout
                         else
                           powershell_out!("Get-WindowsFeature | Select-Object -Property Name,InstallState | ConvertTo-Json -Compress", timeout: new_resource.timeout).stdout
                         end

  Chef::JSONCompat.from_json(raw_list_of_features)
end
powershell_version() click to toggle source

shellout to determine the actively installed version of powershell we have this same data in ohai, but it doesn't get updated if powershell is installed mid run @return [Integer] the powershell version or 0 for nothing

# File lib/chef/resource/windows_feature_powershell.rb, line 132
def powershell_version
  cmd = powershell_out("$PSVersionTable.psversion.major")
  return 1 if cmd.stdout.empty? # PowerShell 1.0 doesn't have a $PSVersionTable
  Regexp.last_match(1).to_i if cmd.stdout =~ /^(\d+)/
rescue Errno::ENOENT
  0 # zero as in nothing is installed
end
raise_if_delete_unsupported() click to toggle source

Fail unless we're on windows 8+ / 2012+ where deleting a feature is supported

# File lib/chef/resource/windows_feature_powershell.rb, line 256
def raise_if_delete_unsupported
  raise Chef::Exceptions::UnsupportedAction, "#{self} :delete action not supported on Windows releases before Windows 8/2012. Cannot continue!" if older_than_win_2012_or_8?
end
raise_on_old_powershell() click to toggle source

raise if we're running powershell less than 3.0 since we need convertto-json check the powershell version via ohai data and if we're < 3.0 also shellout to make sure as a newer version could be installed post ohai run. Yes we're double checking. It's fine. @todo this can go away when we fully remove support for Windows 2008 R2 @raise [RuntimeError] Raise if powershell is < 3.0

# File lib/chef/resource/windows_feature_powershell.rb, line 145
def raise_on_old_powershell
  # be super defensive about the powershell lang plugin not being there
  return if node["languages"] && node["languages"]["powershell"] && node["languages"]["powershell"]["version"].to_i >= 3
  raise "The windows_feature_powershell resource requires PowerShell 3.0 or later. Please install PowerShell 3.0+ before running this resource." if powershell_version < 3
end
reload_cached_powershell_data() click to toggle source

run Get-WindowsFeature to get a list of all available features and their state and save that to the node at node.override level. @return [void]

# File lib/chef/resource/windows_feature_powershell.rb, line 204
def reload_cached_powershell_data
  Chef::Log.debug("Caching Windows features available via Get-WindowsFeature.")
  node.override["powershell_features_cache"] = Mash.new
  node.override["powershell_features_cache"]["enabled"] = []
  node.override["powershell_features_cache"]["disabled"] = []
  node.override["powershell_features_cache"]["removed"] = []

  parsed_feature_list.each do |feature_details_raw|
    case feature_details_raw["InstallState"]
    when 5 # matches 'Removed' InstallState
      add_to_feature_mash("removed", feature_details_raw["Name"])
    when 1, 3 # matches 'Installed' or 'InstallPending' states
      add_to_feature_mash("enabled", feature_details_raw["Name"])
    when 0, 2 # matches 'Available' or 'UninstallPending' states
      add_to_feature_mash("disabled", feature_details_raw["Name"])
    end
  end
  Chef::Log.debug("The powershell cache contains\n#{node['powershell_features_cache']}")
end
remove_feature_cmdlet() click to toggle source

The appropriate cmdlet to remove a windows feature based on windows release @return [String]

# File lib/chef/resource/windows_feature_powershell.rb, line 159
def remove_feature_cmdlet
  older_than_win_2012_or_8? ? "Remove-WindowsFeature" : "Uninstall-WindowsFeature"
end
to_formatted_array(x) click to toggle source

Converts strings of features into an Array. Array objects are lowercased unless we're on < 8/2k12+. @return [Array] array of features

# File lib/chef/resource/windows_feature_powershell.rb, line 55
def to_formatted_array(x)
  x = x.split(/\s*,\s*/) if x.is_a?(String) # split multiple forms of a comma separated list

  # feature installs on windows < 8/2012 are case sensitive so only downcase when on 2012+
  older_than_win_2012_or_8? ? x : x.map(&:downcase)
end