chef 11.14.6 → 11.16.0.rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/chef/exceptions.rb +2 -0
- data/lib/chef/mixin/windows_architecture_helper.rb +16 -0
- data/lib/chef/provider/dsc_script.rb +148 -0
- data/lib/chef/providers.rb +1 -0
- data/lib/chef/resource/dsc_script.rb +123 -0
- data/lib/chef/resources.rb +1 -0
- data/lib/chef/util/dsc/configuration_generator.rb +115 -0
- data/lib/chef/util/dsc/lcm_output_parser.rb +178 -0
- data/lib/chef/util/dsc/local_configuration_manager.rb +137 -0
- data/lib/chef/util/dsc/resource_info.rb +26 -0
- data/lib/chef/util/path_helper.rb +2 -2
- data/lib/chef/util/powershell/cmdlet.rb +136 -0
- data/lib/chef/util/powershell/cmdlet_result.rb +46 -0
- data/lib/chef/version.rb +1 -1
- data/spec/functional/resource/dsc_script_spec.rb +336 -0
- data/spec/functional/resource/group_spec.rb +5 -1
- data/spec/functional/util/powershell/cmdlet_spec.rb +114 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/platform_helpers.rb +24 -0
- data/spec/unit/provider/dsc_script_spec.rb +141 -0
- data/spec/unit/resource/dsc_script_spec.rb +94 -0
- data/spec/unit/util/dsc/configuration_generator_spec.rb +173 -0
- data/spec/unit/util/dsc/lcm_output_parser_spec.rb +178 -0
- data/spec/unit/util/dsc/local_configuration_manager_spec.rb +134 -0
- data/spec/unit/util/powershell/cmdlet_spec.rb +106 -0
- metadata +77 -61
@@ -0,0 +1,178 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Jay Mundrawala (<jdm@getchef.com>)
|
3
|
+
#
|
4
|
+
# Copyright:: 2014, Chef Software, Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'chef/log'
|
20
|
+
require 'chef/util/dsc/resource_info'
|
21
|
+
|
22
|
+
class Chef
|
23
|
+
class Util
|
24
|
+
class DSC
|
25
|
+
class LocalConfigurationManager
|
26
|
+
module Parser
|
27
|
+
class ParseException < RuntimeError; end
|
28
|
+
|
29
|
+
class Operation
|
30
|
+
attr_reader :op_type
|
31
|
+
attr_reader :resources
|
32
|
+
attr_reader :info
|
33
|
+
attr_reader :sets
|
34
|
+
attr_reader :tests
|
35
|
+
|
36
|
+
def initialize(op_type, info)
|
37
|
+
@op_type = op_type
|
38
|
+
@info = []
|
39
|
+
@sets = []
|
40
|
+
@tests = []
|
41
|
+
@resources = []
|
42
|
+
add_info(info)
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_info(info)
|
46
|
+
@info << info
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_set(set)
|
50
|
+
raise ParseException, "add_set is not allowed in this context. Found #{@op_type}" unless [:resource, :set].include?(@op_type)
|
51
|
+
@sets << set
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_test(test)
|
55
|
+
raise ParseException, "add_test is not allowed in this context. Found #{@op_type}" unless [:resource, :set].include?(@op_type)
|
56
|
+
@tests << test
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_resource(resource)
|
60
|
+
raise ParseException, 'add_resource is only allowed to be added to the set op_type' unless @op_type == :set
|
61
|
+
@resources << resource
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Parses the output from LCM and returns a list of Chef::Util::DSC::ResourceInfo objects
|
66
|
+
# that describe how the resources affected the system
|
67
|
+
#
|
68
|
+
# Example:
|
69
|
+
# parse <<-EOF
|
70
|
+
# What if: [Machine]: LCM: [Start Set ]
|
71
|
+
# What if: [Machine]: LCM: [Start Resource ] [[File]FileToNotBeThere]
|
72
|
+
# What if: [Machine]: LCM: [Start Set ] [[File]FileToNotBeThere]
|
73
|
+
# What if: [C:\ShouldNotExist.txt] removed
|
74
|
+
# What if: [Machine]: LCM: [End Set ] [[File]FileToNotBeThere] in 0.1 seconds
|
75
|
+
# What if: [Machine]: LCM: [End Resource ] [[File]FileToNotBeThere]
|
76
|
+
# What if: [Machine]: LCM: [End Set ]
|
77
|
+
# EOF
|
78
|
+
#
|
79
|
+
# would return
|
80
|
+
#
|
81
|
+
# [
|
82
|
+
# Chef::Util::DSC::ResourceInfo.new(
|
83
|
+
# '[[File]FileToNotBeThere]',
|
84
|
+
# true,
|
85
|
+
# [
|
86
|
+
# '[[File]FileToNotBeThere]',
|
87
|
+
# '[C:\Shouldnotexist.txt]',
|
88
|
+
# '[[File]FileToNotBeThere] in 0.1 seconds'
|
89
|
+
# ]
|
90
|
+
# )
|
91
|
+
# ]
|
92
|
+
#
|
93
|
+
def self.parse(lcm_output)
|
94
|
+
return [] unless lcm_output
|
95
|
+
|
96
|
+
stack = Array.new
|
97
|
+
popped_op = nil
|
98
|
+
lcm_output.lines.each do |line|
|
99
|
+
op_action, op_type, info = parse_line(line)
|
100
|
+
info.strip! # Because this was formatted for humans
|
101
|
+
|
102
|
+
# The rules:
|
103
|
+
# - For each `start` action, there must be a matching `end` action
|
104
|
+
# - `skip` actions do not not do anything (They don't add to the stack)
|
105
|
+
case op_action
|
106
|
+
when :start
|
107
|
+
new_op = Operation.new(op_type, info)
|
108
|
+
case op_type
|
109
|
+
when :set
|
110
|
+
stack[-1].add_set(new_op) if stack[-1]
|
111
|
+
when :test
|
112
|
+
stack[-1].add_test(new_op)
|
113
|
+
when :resource
|
114
|
+
while stack[-1].op_type != :set
|
115
|
+
Chef::Log.warn("Can't add resource to set...popping until it is allowed.")
|
116
|
+
popped_op = stack.pop
|
117
|
+
end
|
118
|
+
stack[-1].add_resource(new_op)
|
119
|
+
else
|
120
|
+
Chef::Log.warn("Unknown op_action #{op_action}: Read line #{line}")
|
121
|
+
end
|
122
|
+
stack.push(new_op)
|
123
|
+
when :end
|
124
|
+
popped_op = stack.pop
|
125
|
+
popped_op.add_info(info)
|
126
|
+
while popped_op.op_type != op_type
|
127
|
+
Chef::Log::warn("Unmatching end for op_type. Expected op_type=#{op_type}, found op_type=#{popped_op.op_type}. From output:\n#{lcm_output}")
|
128
|
+
popped_op = stack.pop
|
129
|
+
end
|
130
|
+
when :skip
|
131
|
+
# We don't really have anything to do here
|
132
|
+
when :info
|
133
|
+
stack[-1].add_info(info) if stack[-1]
|
134
|
+
else
|
135
|
+
stack[-1].add_info(line) if stack[-1]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
op_to_resource_infos(popped_op)
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.parse_line(line)
|
143
|
+
if match = line.match(/^.*?:.*?:\s*LCM:\s*\[(.*?)\](.*)/)
|
144
|
+
# If the line looks like
|
145
|
+
# x: [y]: LCM: [op_action op_type] message
|
146
|
+
# extract op_action, op_type, and message
|
147
|
+
operation, info = match.captures
|
148
|
+
op_action, op_type = operation.strip.split(' ').map {|m| m.downcase.to_sym}
|
149
|
+
else
|
150
|
+
# If the line looks like
|
151
|
+
# x: [y]: message
|
152
|
+
# extract message
|
153
|
+
match = line.match(/^.*?:.*?: \s+(.*)/)
|
154
|
+
op_action = op_type = :info
|
155
|
+
info = match.captures[0]
|
156
|
+
end
|
157
|
+
info.strip! # Because this was formatted for humans
|
158
|
+
return [op_action, op_type, info]
|
159
|
+
end
|
160
|
+
private_class_method :parse_line
|
161
|
+
|
162
|
+
def self.op_to_resource_infos(op)
|
163
|
+
resources = op ? op.resources : []
|
164
|
+
|
165
|
+
resources.map do |r|
|
166
|
+
name = r.info[0]
|
167
|
+
sets = r.sets.length > 0
|
168
|
+
change_log = r.sets[-1].info if sets
|
169
|
+
Chef::Util::DSC::ResourceInfo.new(name, sets, change_log)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
private_class_method :op_to_resource_infos
|
173
|
+
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Edwards (<adamed@getchef.com>)
|
3
|
+
#
|
4
|
+
# Copyright:: 2014, Chef Software, Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'chef/util/powershell/cmdlet'
|
20
|
+
require 'chef/util/dsc/lcm_output_parser'
|
21
|
+
|
22
|
+
class Chef::Util::DSC
|
23
|
+
class LocalConfigurationManager
|
24
|
+
def initialize(node, configuration_path)
|
25
|
+
@node = node
|
26
|
+
@configuration_path = configuration_path
|
27
|
+
clear_execution_time
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_configuration(configuration_document)
|
31
|
+
status = run_configuration_cmdlet(configuration_document)
|
32
|
+
handle_what_if_exception!(status.stderr) unless status.succeeded?
|
33
|
+
configuration_update_required?(status.return_value)
|
34
|
+
end
|
35
|
+
|
36
|
+
def set_configuration(configuration_document)
|
37
|
+
run_configuration_cmdlet(configuration_document, true)
|
38
|
+
end
|
39
|
+
|
40
|
+
def last_operation_execution_time_seconds
|
41
|
+
if @operation_start_time && @operation_end_time
|
42
|
+
@operation_end_time - @operation_start_time
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def run_configuration_cmdlet(configuration_document, apply_configuration = false)
|
49
|
+
Chef::Log.debug("DSC: Calling DSC Local Config Manager to #{apply_configuration ? "set" : "test"} configuration document.")
|
50
|
+
test_only_parameters = ! apply_configuration ? '-whatif; if (! $?) { exit 1 }' : ''
|
51
|
+
|
52
|
+
start_operation_timing
|
53
|
+
command_code = lcm_command_code(@configuration_path, test_only_parameters)
|
54
|
+
status = nil
|
55
|
+
|
56
|
+
begin
|
57
|
+
save_configuration_document(configuration_document)
|
58
|
+
cmdlet = ::Chef::Util::Powershell::Cmdlet.new(@node, "#{command_code}")
|
59
|
+
if apply_configuration
|
60
|
+
status = cmdlet.run!
|
61
|
+
else
|
62
|
+
status = cmdlet.run
|
63
|
+
end
|
64
|
+
ensure
|
65
|
+
end_operation_timing
|
66
|
+
remove_configuration_document
|
67
|
+
if last_operation_execution_time_seconds
|
68
|
+
Chef::Log.debug("DSC: DSC operation completed in #{last_operation_execution_time_seconds} seconds.")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
Chef::Log.debug("DSC: Completed call to DSC Local Config Manager")
|
72
|
+
status
|
73
|
+
end
|
74
|
+
|
75
|
+
def lcm_command_code(configuration_path, test_only_parameters)
|
76
|
+
<<-EOH
|
77
|
+
$ProgressPreference = 'SilentlyContinue';start-dscconfiguration -path #{@configuration_path} -wait -erroraction 'continue' -force #{test_only_parameters}
|
78
|
+
EOH
|
79
|
+
end
|
80
|
+
|
81
|
+
def handle_what_if_exception!(what_if_exception_output)
|
82
|
+
if what_if_exception_output.gsub(/\s+/, ' ') =~ /A parameter cannot be found that matches parameter name 'Whatif'/i
|
83
|
+
# LCM returns an error if any of the resources do not support the opptional What-If
|
84
|
+
Chef::Log::warn("Received error while testing configuration due to resource not supporting 'WhatIf'")
|
85
|
+
elsif output_has_dsc_module_failure?(what_if_exception_output)
|
86
|
+
Chef::Log::warn("Received error while testing configuration due to a module for an imported resource possibly not being fully installed:\n#{what_if_exception_output.gsub(/\s+/, ' ')}")
|
87
|
+
else
|
88
|
+
raise Chef::Exceptions::PowershellCmdletException, "Powershell Cmdlet failed: #{what_if_exception_output.gsub(/\s+/, ' ')}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def output_has_dsc_module_failure?(what_if_output)
|
93
|
+
!! (what_if_output =~ /\sCimException/ &&
|
94
|
+
what_if_output =~ /ProviderOperationExecutionFailure/ &&
|
95
|
+
what_if_output =~ /\smodule\s+is\s+installed/)
|
96
|
+
end
|
97
|
+
|
98
|
+
def configuration_update_required?(what_if_output)
|
99
|
+
Chef::Log.debug("DSC: DSC returned the following '-whatif' output from test operation:\n#{what_if_output}")
|
100
|
+
begin
|
101
|
+
Parser::parse(what_if_output)
|
102
|
+
rescue Chef::Util::DSC::LocalConfigurationManager::Parser => e
|
103
|
+
Chef::Log::warn("Could not parse LCM output: #{e}")
|
104
|
+
[Chef::Util::DSC::ResourceInfo.new('Unknown DSC Resources', true, ['Unknown changes because LCM output was not parsable.'])]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def save_configuration_document(configuration_document)
|
109
|
+
::FileUtils.mkdir_p(@configuration_path)
|
110
|
+
::File.open(configuration_document_path, 'wb') do | file |
|
111
|
+
file.write(configuration_document)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def remove_configuration_document
|
116
|
+
::FileUtils.rm(configuration_document_path)
|
117
|
+
end
|
118
|
+
|
119
|
+
def configuration_document_path
|
120
|
+
File.join(@configuration_path,'..mof')
|
121
|
+
end
|
122
|
+
|
123
|
+
def clear_execution_time
|
124
|
+
@operation_start_time = nil
|
125
|
+
@operation_end_time = nil
|
126
|
+
end
|
127
|
+
|
128
|
+
def start_operation_timing
|
129
|
+
clear_execution_time
|
130
|
+
@operation_start_time = Time.now
|
131
|
+
end
|
132
|
+
|
133
|
+
def end_operation_timing
|
134
|
+
@operation_end_time = Time.now
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
class Chef
|
3
|
+
class Util
|
4
|
+
class DSC
|
5
|
+
class ResourceInfo
|
6
|
+
# The name is the text following [Start Set]
|
7
|
+
attr_reader :name
|
8
|
+
|
9
|
+
# A list of all log messages between [Start Set] and [End Set].
|
10
|
+
# Each line is an element in the list.
|
11
|
+
attr_reader :change_log
|
12
|
+
|
13
|
+
def initialize(name, sets, change_log)
|
14
|
+
@name = name
|
15
|
+
@sets = sets
|
16
|
+
@change_log = change_log || []
|
17
|
+
end
|
18
|
+
|
19
|
+
# Does this resource change the state of the system?
|
20
|
+
def changes_state?
|
21
|
+
@sets
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -32,7 +32,7 @@ class Chef
|
|
32
32
|
Chef::Log.error(msg)
|
33
33
|
raise Chef::Exceptions::ValidationFailed, msg
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
if windows_max_length_exceeded?(path)
|
37
37
|
Chef::Log.debug("Path '#{path}' is longer than #{WIN_MAX_PATH}, prefixing with'\\\\?\\'")
|
38
38
|
path.insert(0, "\\\\?\\")
|
@@ -50,7 +50,7 @@ class Chef
|
|
50
50
|
return true
|
51
51
|
end
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
false
|
55
55
|
end
|
56
56
|
|
@@ -0,0 +1,136 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Edwards (<adamed@getchef.com>)
|
3
|
+
#
|
4
|
+
# Copyright:: 2014, Chef Software, Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'mixlib/shellout'
|
20
|
+
require 'chef/mixin/windows_architecture_helper'
|
21
|
+
require 'chef/util/powershell/cmdlet_result'
|
22
|
+
|
23
|
+
class Chef::Util::Powershell
|
24
|
+
class Cmdlet
|
25
|
+
def initialize(node, cmdlet, output_format=nil, output_format_options={})
|
26
|
+
@output_format = output_format
|
27
|
+
@node = node
|
28
|
+
|
29
|
+
case output_format
|
30
|
+
when nil
|
31
|
+
@json_format = false
|
32
|
+
when :json
|
33
|
+
@json_format = true
|
34
|
+
when :text
|
35
|
+
@json_format = false
|
36
|
+
when :object
|
37
|
+
@json_format = true
|
38
|
+
else
|
39
|
+
raise ArgumentError, "Invalid output format #{output_format.to_s} specified"
|
40
|
+
end
|
41
|
+
|
42
|
+
@cmdlet = cmdlet
|
43
|
+
@output_format_options = output_format_options
|
44
|
+
end
|
45
|
+
|
46
|
+
attr_reader :output_format
|
47
|
+
|
48
|
+
def run(switches={}, execution_options={}, *arguments)
|
49
|
+
arguments_string = arguments.join(' ')
|
50
|
+
|
51
|
+
switches_string = command_switches_string(switches)
|
52
|
+
|
53
|
+
json_depth = 5
|
54
|
+
|
55
|
+
if @json_format && @output_format_options.has_key?(:depth)
|
56
|
+
json_depth = @output_format_options[:depth]
|
57
|
+
end
|
58
|
+
|
59
|
+
json_command = @json_format ? " | convertto-json -compress -depth #{json_depth}" : ""
|
60
|
+
command_string = "powershell.exe -executionpolicy bypass -noprofile -noninteractive -command \"trap [Exception] {write-error -exception ($_.Exception.Message);exit 1};#{@cmdlet} #{switches_string} #{arguments_string}#{json_command}\";if ( ! $? ) { exit 1 }"
|
61
|
+
|
62
|
+
augmented_options = {:returns => [0], :live_stream => false}.merge(execution_options)
|
63
|
+
command = Mixlib::ShellOut.new(command_string, augmented_options)
|
64
|
+
|
65
|
+
os_architecture = "#{ENV['PROCESSOR_ARCHITEW6432']}" == 'AMD64' ? :x86_64 : :i386
|
66
|
+
|
67
|
+
status = nil
|
68
|
+
|
69
|
+
with_os_architecture(@node) do
|
70
|
+
status = command.run_command
|
71
|
+
end
|
72
|
+
|
73
|
+
CmdletResult.new(status, @output_format)
|
74
|
+
end
|
75
|
+
|
76
|
+
def run!(switches={}, execution_options={}, *arguments)
|
77
|
+
result = run(switches, execution_options, arguments)
|
78
|
+
|
79
|
+
if ! result.succeeded?
|
80
|
+
raise Chef::Exceptions::PowershellCmdletException, "Powershell Cmdlet failed: #{result.stderr}"
|
81
|
+
end
|
82
|
+
|
83
|
+
result
|
84
|
+
end
|
85
|
+
|
86
|
+
protected
|
87
|
+
|
88
|
+
include Chef::Mixin::WindowsArchitectureHelper
|
89
|
+
|
90
|
+
def validate_switch_name!(switch_parameter_name)
|
91
|
+
if !!(switch_parameter_name.to_s =~ /\A[A-Za-z]+[_a-zA-Z0-9]*\Z/) == false
|
92
|
+
raise ArgumentError, "`#{switch_parameter_name}` is not a valid PowerShell cmdlet switch parameter name"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def escape_parameter_value(parameter_value)
|
97
|
+
parameter_value.gsub(/(`|'|"|#)/,'`\1')
|
98
|
+
end
|
99
|
+
|
100
|
+
def escape_string_parameter_value(parameter_value)
|
101
|
+
"'#{escape_parameter_value(parameter_value)}'"
|
102
|
+
end
|
103
|
+
|
104
|
+
def command_switches_string(switches)
|
105
|
+
command_switches = switches.map do | switch_name, switch_value |
|
106
|
+
if switch_name.class != Symbol
|
107
|
+
raise ArgumentError, "Invalid type `#{switch_name} `for PowerShell switch '#{switch_name.to_s}'. The switch must be specified as a Symbol'"
|
108
|
+
end
|
109
|
+
|
110
|
+
validate_switch_name!(switch_name)
|
111
|
+
|
112
|
+
switch_argument = ''
|
113
|
+
switch_present = true
|
114
|
+
|
115
|
+
case switch_value
|
116
|
+
when Numeric
|
117
|
+
switch_argument = switch_value.to_s
|
118
|
+
when Float
|
119
|
+
switch_argument = switch_value.to_s
|
120
|
+
when FalseClass
|
121
|
+
switch_present = false
|
122
|
+
when TrueClass
|
123
|
+
when String
|
124
|
+
switch_argument = escape_string_parameter_value(switch_value)
|
125
|
+
else
|
126
|
+
raise ArgumentError, "Invalid argument type `#{switch_value.class}` specified for PowerShell switch `:#{switch_name.to_s}`. Arguments to PowerShell must be of type `String`, `Numeric`, `Float`, `FalseClass`, or `TrueClass`"
|
127
|
+
end
|
128
|
+
|
129
|
+
switch_present ? ["-#{switch_name.to_s.downcase}", switch_argument].join(' ').strip : ''
|
130
|
+
end
|
131
|
+
|
132
|
+
command_switches.join(' ')
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|