ruby-pwsh 0.10.3 → 0.11.0.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +16 -38
- data/lib/puppet/provider/dsc_base_provider/dsc_base_provider.rb +20 -20
- data/lib/pwsh/version.rb +1 -1
- data/lib/pwsh/windows_powershell.rb +2 -2
- data/lib/pwsh.rb +31 -34
- data/spec/acceptance/dsc/basic.rb +4 -0
- data/spec/acceptance/dsc/cim_instances.rb +3 -4
- data/spec/acceptance/dsc/class.rb +3 -3
- data/spec/acceptance/dsc/complex.rb +2 -2
- data/spec/acceptance/support/setup_winrm.ps1 +6 -0
- data/spec/unit/puppet/provider/dsc_base_provider/dsc_base_provider_spec.rb +171 -113
- data/spec/unit/pwsh/util_spec.rb +100 -93
- data/spec/unit/pwsh/version_spec.rb +2 -2
- data/spec/unit/pwsh/windows_powershell_spec.rb +18 -13
- data/spec/unit/pwsh_spec.rb +61 -63
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3357d3c933ddf7b2ecce5d3be1958e9d6aaf6b9966f0b4e4d1f45c40f13963c
|
4
|
+
data.tar.gz: 59e415fc5c1804e09c481bfb6a3c8aa58a7b9767dd04f0a31b3f65c6986ab9c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd03304fb4b624296d2770b33296464ca7968e0d1f3b5ee31ddad4490892fcefeca55359447dad2389fb7123bb6b95f42d287f1dd29c50a4ccdd0244338d862e
|
7
|
+
data.tar.gz: 0a4c863c752858ee96975d0278220ca914ba1ea5e02bddd57ab8c798b23c775c2914e81a67482c3bfa5b54af64e0f55946e99af0c2d0fef2b7470c3aec379c86
|
data/.rubocop.yml
CHANGED
@@ -1,41 +1,19 @@
|
|
1
|
-
|
2
|
-
Enabled: false
|
3
|
-
Layout/EndOfLine:
|
4
|
-
Description: Don't enforce CRLF on Windows.
|
5
|
-
Enabled: false
|
6
|
-
Metrics/LineLength:
|
7
|
-
Description: People have wide screens, use them.
|
8
|
-
Max: 200
|
9
|
-
Metrics/BlockLength:
|
10
|
-
Enabled: false
|
11
|
-
Metrics/MethodLength:
|
12
|
-
Enabled: false
|
13
|
-
Metrics/ClassLength:
|
14
|
-
Enabled: false
|
15
|
-
Metrics/PerceivedComplexity:
|
16
|
-
Enabled: false
|
17
|
-
Metrics/CyclomaticComplexity:
|
18
|
-
Enabled: false
|
19
|
-
Metrics/AbcSize:
|
20
|
-
Enabled: false
|
1
|
+
inherit_from: .rubocop_todo.yml
|
21
2
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
Naming/FileName:
|
3
|
+
require:
|
4
|
+
- rubocop-performance
|
5
|
+
- rubocop-rspec
|
6
|
+
|
7
|
+
AllCops:
|
28
8
|
Exclude:
|
29
|
-
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
9
|
+
- Gemfile
|
10
|
+
- Rakefile
|
11
|
+
- spec/fixtures/**/*
|
12
|
+
- vendor/bundle/**/*
|
13
|
+
NewCops: enable
|
14
|
+
SuggestExtensions: false
|
15
|
+
TargetRubyVersion: '2.7'
|
16
|
+
|
17
|
+
# Disabled
|
36
18
|
Style/ClassAndModuleChildren:
|
37
|
-
|
38
|
-
- lib/puppet/provider/dsc_base_provider/dsc_base_provider.rb
|
39
|
-
Style/ClassVars:
|
40
|
-
Exclude:
|
41
|
-
- lib/puppet/provider/dsc_base_provider/dsc_base_provider.rb
|
19
|
+
Enabled: false
|
@@ -88,7 +88,7 @@ class Puppet::Provider::DscBaseProvider
|
|
88
88
|
# - When the values match case insensitively but the attribute is an enum, prefer the casing of the manifest enum.
|
89
89
|
# - When the values match case insensitively and the attribute is not an enum, prefer the casing from invoke_get_method
|
90
90
|
canonicalized[key] = r[key] unless same?(value, downcased_resource[key]) && !enum_attributes(context).include?(key)
|
91
|
-
canonicalized.delete(key) unless downcased_resource.
|
91
|
+
canonicalized.delete(key) unless downcased_resource.key?(key)
|
92
92
|
end
|
93
93
|
# Cache the actually canonicalized resource separately
|
94
94
|
@@cached_canonicalized_resource << canonicalized.dup
|
@@ -134,7 +134,7 @@ class Puppet::Provider::DscBaseProvider
|
|
134
134
|
(mandatory_get_attributes(context) - namevar_attributes(context)).include?(attribute)
|
135
135
|
end
|
136
136
|
# If dsc_psdscrunascredential was specified, re-add it here.
|
137
|
-
mandatory_properties[:dsc_psdscrunascredential] = canonicalized_resource[:dsc_psdscrunascredential] if canonicalized_resource.
|
137
|
+
mandatory_properties[:dsc_psdscrunascredential] = canonicalized_resource[:dsc_psdscrunascredential] if canonicalized_resource.key?(:dsc_psdscrunascredential)
|
138
138
|
end
|
139
139
|
names.collect do |name|
|
140
140
|
name = { name: name } if name.is_a? String
|
@@ -253,7 +253,7 @@ class Puppet::Provider::DscBaseProvider
|
|
253
253
|
|
254
254
|
begin
|
255
255
|
data = JSON.parse(output)
|
256
|
-
rescue => e
|
256
|
+
rescue StandardError => e
|
257
257
|
context.err(e)
|
258
258
|
return nil
|
259
259
|
end
|
@@ -263,7 +263,7 @@ class Puppet::Provider::DscBaseProvider
|
|
263
263
|
unless error.nil? || error.empty?
|
264
264
|
# NB: We should have a way to stop processing this resource *now* without blowing up the whole Puppet run
|
265
265
|
# Raising an error stops processing but blows things up while context.err alerts but continues to process
|
266
|
-
if error
|
266
|
+
if error.include?('Logon failure: the user has not been granted the requested logon type at this computer')
|
267
267
|
logon_error = "PSDscRunAsCredential account specified (#{name_hash[:dsc_psdscrunascredential]['user']}) does not have appropriate logon rights; are they an administrator?"
|
268
268
|
name_hash[:name].nil? ? context.err(logon_error) : context.err(name_hash[:name], logon_error)
|
269
269
|
@@logon_failures << name_hash[:dsc_psdscrunascredential].dup
|
@@ -343,19 +343,19 @@ class Puppet::Provider::DscBaseProvider
|
|
343
343
|
end
|
344
344
|
# PowerShell does not distinguish between a return of empty array/string
|
345
345
|
# and null but Puppet does; revert to those values if specified.
|
346
|
-
data[type_key] = [] if data[type_key].nil? && query_props.
|
346
|
+
data[type_key] = [] if data[type_key].nil? && query_props.key?(type_key) && query_props[type_key].is_a?(Array)
|
347
347
|
end
|
348
348
|
# If a resource is found, it's present, so refill this Puppet-only key
|
349
|
-
data
|
349
|
+
data[:name] = name_hash[:name]
|
350
350
|
|
351
351
|
# Have to check for this to avoid a weird canonicalization warning
|
352
352
|
# The Resource API calls canonicalize against the current state which
|
353
353
|
# will lead to dsc_ensure being set to absent in the name_hash even if
|
354
354
|
# it was set to present in the manifest
|
355
|
-
name_hash_has_nil_keys = name_hash.
|
355
|
+
name_hash_has_nil_keys = name_hash.count { |_k, v| v.nil? }.positive?
|
356
356
|
# We want to throw away all of the empty keys if and only if the manifest
|
357
357
|
# declaration is for an absent resource and the resource is actually absent
|
358
|
-
data.
|
358
|
+
data.compact! if data[:dsc_ensure] == 'Absent' && name_hash[:dsc_ensure] == 'Absent' && !name_hash_has_nil_keys
|
359
359
|
|
360
360
|
# Sort the return for order-insensitive nested enumerable comparison:
|
361
361
|
data = recursively_sort(data)
|
@@ -451,7 +451,7 @@ class Puppet::Provider::DscBaseProvider
|
|
451
451
|
# path to allow multiple modules to with shared dsc_resources to be installed side by side
|
452
452
|
# The old vendored_modules_path: puppet_x/dsc_resources
|
453
453
|
# The new vendored_modules_path: puppet_x/<module_name>/dsc_resources
|
454
|
-
root_module_path = load_path.
|
454
|
+
root_module_path = load_path.find { |path| path.match?(%r{#{puppetize_name(module_name)}/lib}) }
|
455
455
|
vendored_path = if root_module_path.nil?
|
456
456
|
File.expand_path(Pathname.new(__FILE__).dirname + '../../../' + "puppet_x/#{puppetize_name(module_name)}/dsc_resources") # rubocop:disable Style/StringConcatenation
|
457
457
|
else
|
@@ -501,7 +501,7 @@ class Puppet::Provider::DscBaseProvider
|
|
501
501
|
# @return [String] a uuid with underscores instead of dashes.
|
502
502
|
def random_variable_name
|
503
503
|
# PowerShell variables can't include dashes
|
504
|
-
SecureRandom.uuid.
|
504
|
+
SecureRandom.uuid.tr('-', '_')
|
505
505
|
end
|
506
506
|
|
507
507
|
# Return a Hash containing all of the variables defined for instantiation as well as the Ruby hash for their
|
@@ -640,7 +640,7 @@ class Puppet::Provider::DscBaseProvider
|
|
640
640
|
# @param context [Object] the Puppet runtime context to operate in and send feedback to
|
641
641
|
# @return [Array] returns an array of attribute names as symbols which are enums
|
642
642
|
def enum_attributes(context)
|
643
|
-
context.type.attributes.select { |_name, properties| properties[:type].
|
643
|
+
context.type.attributes.select { |_name, properties| properties[:type].include?('Enum[') }.keys
|
644
644
|
end
|
645
645
|
|
646
646
|
# Look through a fully formatted string, replacing all instances where a value matches the formatted properties
|
@@ -670,7 +670,7 @@ class Puppet::Provider::DscBaseProvider
|
|
670
670
|
def munge_psmodulepath(resource)
|
671
671
|
return unless resource[:dscmeta_resource_implementation] == 'Class'
|
672
672
|
|
673
|
-
vendor_path = resource[:vendored_modules_path].
|
673
|
+
vendor_path = resource[:vendored_modules_path].tr('/', '\\')
|
674
674
|
<<~MUNGE_PSMODULEPATH.strip
|
675
675
|
$UnmungedPSModulePath = [System.Environment]::GetEnvironmentVariable('PSModulePath','machine')
|
676
676
|
$MungedPSModulePath = $env:PSModulePath + ';#{vendor_path}'
|
@@ -731,7 +731,7 @@ class Puppet::Provider::DscBaseProvider
|
|
731
731
|
# name = property_name.to_s.gsub(/^dsc_/, '').to_sym
|
732
732
|
# Process nested CIM instances first as those neeed to be passed to higher-order
|
733
733
|
# instances and must therefore be declared before they must be referenced
|
734
|
-
cim_instance_hashes = nested_cim_instances(property_hash[:value]).flatten.
|
734
|
+
cim_instance_hashes = nested_cim_instances(property_hash[:value]).flatten.compact
|
735
735
|
# Sometimes the instances are an empty array
|
736
736
|
unless cim_instance_hashes.count.zero?
|
737
737
|
cim_instance_hashes.each do |instance|
|
@@ -743,7 +743,7 @@ class Puppet::Provider::DscBaseProvider
|
|
743
743
|
end
|
744
744
|
end
|
745
745
|
# We have to handle arrays of CIM instances slightly differently
|
746
|
-
if property_hash[:mof_type]
|
746
|
+
if /\[\]$/.match?(property_hash[:mof_type])
|
747
747
|
class_name = property_hash[:mof_type].gsub('[]', '')
|
748
748
|
property_hash[:value].each do |hash|
|
749
749
|
variable_name = random_variable_name
|
@@ -847,7 +847,7 @@ class Puppet::Provider::DscBaseProvider
|
|
847
847
|
params_block = params_block.gsub("#{param_block_name} = @()", "#{param_block_name} = [#{properties[:mof_type]}]@()")
|
848
848
|
end
|
849
849
|
# HACK: make CIM instances work:
|
850
|
-
resource[:parameters].select { |_key, hash| hash[:mof_is_embedded] && hash[:mof_type]
|
850
|
+
resource[:parameters].select { |_key, hash| hash[:mof_is_embedded] && hash[:mof_type].include?('[]') }.each do |_property_name, property_hash|
|
851
851
|
formatted_property_hash = interpolate_variables(format(property_hash[:value]))
|
852
852
|
params_block = params_block.gsub(formatted_property_hash, "[CimInstance[]]#{formatted_property_hash}")
|
853
853
|
end
|
@@ -861,7 +861,7 @@ class Puppet::Provider::DscBaseProvider
|
|
861
861
|
# @param resource [Hash] a hash with the information needed to run `Invoke-DscResource`
|
862
862
|
# @return [String] A string representing the PowerShell script which will invoke the DSC Resource.
|
863
863
|
def ps_script_content(resource)
|
864
|
-
template_path = File.expand_path(
|
864
|
+
template_path = File.expand_path(__dir__)
|
865
865
|
# Defines the helper functions
|
866
866
|
functions = File.new("#{template_path}/invoke_dsc_resource_functions.ps1").read
|
867
867
|
# Defines the response hash and the runtime settings
|
@@ -888,7 +888,7 @@ class Puppet::Provider::DscBaseProvider
|
|
888
888
|
def format(value)
|
889
889
|
Pwsh::Util.format_powershell_value(value)
|
890
890
|
rescue RuntimeError => e
|
891
|
-
raise unless e.message
|
891
|
+
raise unless e.message.include?('Sensitive [value redacted]')
|
892
892
|
|
893
893
|
Pwsh::Util.format_powershell_value(unwrap(value))
|
894
894
|
end
|
@@ -948,12 +948,12 @@ class Puppet::Provider::DscBaseProvider
|
|
948
948
|
def handle_secrets(text, replacement, error_message)
|
949
949
|
# Every secret unwrapped in this module will unwrap as "'secret#{SECRET_POSTFIX}'"
|
950
950
|
# Currently, no known resources specify a SecureString instead of a PSCredential object.
|
951
|
-
return text unless
|
951
|
+
return text unless /#{Regexp.quote(SECRET_POSTFIX)}/.match?(text)
|
952
952
|
|
953
953
|
# In order to reduce time-to-parse, look at each line individually and *only* attempt
|
954
954
|
# to substitute if a naive match for the secret postfix is found on the line.
|
955
955
|
modified_text = text.split("\n").map do |line|
|
956
|
-
if
|
956
|
+
if /#{Regexp.quote(SECRET_POSTFIX)}/.match?(line)
|
957
957
|
line.gsub(SECRET_DATA_REGEX, replacement)
|
958
958
|
else
|
959
959
|
line
|
@@ -963,7 +963,7 @@ class Puppet::Provider::DscBaseProvider
|
|
963
963
|
modified_text = modified_text.join("\n")
|
964
964
|
|
965
965
|
# Something has gone wrong, error loudly
|
966
|
-
raise error_message if
|
966
|
+
raise error_message if /#{Regexp.quote(SECRET_POSTFIX)}/.match?(modified_text)
|
967
967
|
|
968
968
|
modified_text
|
969
969
|
end
|
data/lib/pwsh/version.rb
CHANGED
@@ -82,7 +82,7 @@ if Pwsh::Util.on_windows?
|
|
82
82
|
HKLM.open(PS_ONE_REG_PATH, ACCESS_TYPE) do |reg|
|
83
83
|
version = reg[REG_KEY]
|
84
84
|
end
|
85
|
-
rescue
|
85
|
+
rescue StandardError
|
86
86
|
version = nil
|
87
87
|
end
|
88
88
|
version
|
@@ -98,7 +98,7 @@ if Pwsh::Util.on_windows?
|
|
98
98
|
HKLM.open(PS_THREE_REG_PATH, ACCESS_TYPE) do |reg|
|
99
99
|
version = reg[REG_KEY]
|
100
100
|
end
|
101
|
-
rescue
|
101
|
+
rescue StandardError
|
102
102
|
version = nil
|
103
103
|
end
|
104
104
|
version
|
data/lib/pwsh.rb
CHANGED
@@ -55,7 +55,7 @@ module Pwsh
|
|
55
55
|
# ignore any errors trying to tear down this unusable instance
|
56
56
|
begin
|
57
57
|
manager.exit unless manager.nil? # rubocop:disable Style/SafeNavigation
|
58
|
-
rescue
|
58
|
+
rescue StandardError
|
59
59
|
nil
|
60
60
|
end
|
61
61
|
@@instances[key] = Manager.new(cmd, args, options)
|
@@ -151,7 +151,7 @@ module Pwsh
|
|
151
151
|
UNIXSocket.new(pipe_path)
|
152
152
|
end
|
153
153
|
break
|
154
|
-
rescue
|
154
|
+
rescue StandardError
|
155
155
|
sleep sleep_interval
|
156
156
|
end
|
157
157
|
end
|
@@ -208,7 +208,6 @@ module Pwsh
|
|
208
208
|
out[:stderr] = out[:stderr].nil? ? [] : [out[:stderr]]
|
209
209
|
out[:stderr] += err unless err.nil?
|
210
210
|
out[:native_stdout] = native_stdout
|
211
|
-
|
212
211
|
out
|
213
212
|
end
|
214
213
|
|
@@ -224,7 +223,7 @@ module Pwsh
|
|
224
223
|
# rather than expecting the pipe.close to terminate it
|
225
224
|
begin
|
226
225
|
write_pipe(pipe_command(:exit)) unless @pipe.closed?
|
227
|
-
rescue
|
226
|
+
rescue StandardError
|
228
227
|
nil
|
229
228
|
end
|
230
229
|
|
@@ -245,8 +244,8 @@ module Pwsh
|
|
245
244
|
# @return [String] full path to the bootstrap template
|
246
245
|
def self.template_path
|
247
246
|
# A PowerShell -File compatible path to bootstrap the instance
|
248
|
-
path = File.expand_path('
|
249
|
-
path = File.join(path, 'init.ps1').
|
247
|
+
path = File.expand_path('templates', __dir__)
|
248
|
+
path = File.join(path, 'init.ps1').tr('/', '\\')
|
250
249
|
"\"#{path}\""
|
251
250
|
end
|
252
251
|
|
@@ -268,7 +267,7 @@ module Pwsh
|
|
268
267
|
|
269
268
|
# Lower bound protection. The polling resolution is only 50ms.
|
270
269
|
timeout_ms = 50 if timeout_ms < 50
|
271
|
-
rescue
|
270
|
+
rescue StandardError
|
272
271
|
timeout_ms = 300 * 1000
|
273
272
|
end
|
274
273
|
|
@@ -308,17 +307,17 @@ module Pwsh
|
|
308
307
|
|
309
308
|
# PS Side expects Invoke-PowerShellUserCode is always the return value here
|
310
309
|
# TODO: Refactor to use <<~ as soon as we can :sob:
|
311
|
-
|
312
|
-
$params = @{
|
313
|
-
|
314
|
-
#{powershell_code}
|
315
|
-
'@
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
}
|
320
|
-
|
321
|
-
Invoke-PowerShellUserCode @params
|
310
|
+
<<~CODE
|
311
|
+
$params = @{
|
312
|
+
Code = @'
|
313
|
+
#{powershell_code}
|
314
|
+
'@
|
315
|
+
TimeoutMilliseconds = #{timeout_ms}
|
316
|
+
WorkingDirectory = "#{working_dir}"
|
317
|
+
AdditionalEnvironmentVariables = #{additional_environment_variables}
|
318
|
+
}
|
319
|
+
|
320
|
+
Invoke-PowerShellUserCode @params
|
322
321
|
CODE
|
323
322
|
end
|
324
323
|
|
@@ -336,10 +335,10 @@ Invoke-PowerShellUserCode @params
|
|
336
335
|
#
|
337
336
|
# @return [String] the absolute path to the PowerShell executable. Returns 'powershell.exe' if no more specific path found.
|
338
337
|
def self.powershell_path
|
339
|
-
if File.exist?("#{ENV
|
340
|
-
"#{ENV
|
341
|
-
elsif File.exist?("#{ENV
|
342
|
-
"#{ENV
|
338
|
+
if File.exist?("#{ENV.fetch('SYSTEMROOT', nil)}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe")
|
339
|
+
"#{ENV.fetch('SYSTEMROOT', nil)}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe"
|
340
|
+
elsif File.exist?("#{ENV.fetch('SYSTEMROOT', nil)}\\system32\\WindowsPowershell\\v1.0\\powershell.exe")
|
341
|
+
"#{ENV.fetch('SYSTEMROOT', nil)}\\system32\\WindowsPowershell\\v1.0\\powershell.exe"
|
343
342
|
else
|
344
343
|
'powershell.exe'
|
345
344
|
end
|
@@ -353,7 +352,7 @@ Invoke-PowerShellUserCode @params
|
|
353
352
|
# Convert all the key names to upcase so we can be sure to find PATH etc.
|
354
353
|
# Also while ruby can have difficulty changing the case of some UTF8 characters, we're
|
355
354
|
# only going to use plain ASCII names so this is safe.
|
356
|
-
current_path = Pwsh::Util.on_windows? ? ENV.select { |k, _| k.
|
355
|
+
current_path = Pwsh::Util.on_windows? ? ENV.select { |k, _| k.casecmp('PATH').zero? }.values[0] : ENV.fetch('PATH', nil)
|
357
356
|
current_path = '' if current_path.nil?
|
358
357
|
|
359
358
|
# Prefer any additional paths
|
@@ -367,10 +366,10 @@ Invoke-PowerShellUserCode @params
|
|
367
366
|
# TODO: What about PS 8?
|
368
367
|
# TODO: Need to check on French/Turkish windows if ENV['PROGRAMFILES'] parses UTF8 names correctly
|
369
368
|
# TODO: Need to ensure ENV['PROGRAMFILES'] is case insensitive, i.e. ENV['PROGRAMFiles'] should also resolve on Windows
|
370
|
-
search_paths += ";#{ENV
|
371
|
-
";#{ENV
|
372
|
-
";#{ENV
|
373
|
-
";#{ENV
|
369
|
+
search_paths += ";#{ENV.fetch('PROGRAMFILES', nil)}\\PowerShell\\6" \
|
370
|
+
";#{ENV.fetch('PROGRAMFILES(X86)', nil)}\\PowerShell\\6" \
|
371
|
+
";#{ENV.fetch('PROGRAMFILES', nil)}\\PowerShell\\7" \
|
372
|
+
";#{ENV.fetch('PROGRAMFILES(X86)', nil)}\\PowerShell\\7"
|
374
373
|
end
|
375
374
|
raise 'No paths discovered to search for Powershell!' if search_paths.split(File::PATH_SEPARATOR).empty?
|
376
375
|
|
@@ -433,7 +432,7 @@ Invoke-PowerShellUserCode @params
|
|
433
432
|
# as this resolves to a HANDLE and then calls the Windows API
|
434
433
|
!stream.stat.nil?
|
435
434
|
# Any exceptions mean the stream is dead
|
436
|
-
rescue
|
435
|
+
rescue StandardError
|
437
436
|
false
|
438
437
|
end
|
439
438
|
|
@@ -497,9 +496,7 @@ Invoke-PowerShellUserCode @params
|
|
497
496
|
#
|
498
497
|
# @return nil
|
499
498
|
def write_pipe(input)
|
500
|
-
|
501
|
-
# not write - otherwise, the pipe breaks after writing 1024 bytes.
|
502
|
-
written = @pipe.syswrite(input)
|
499
|
+
written = @pipe.write(input)
|
503
500
|
@pipe.flush
|
504
501
|
|
505
502
|
if written != input.length # rubocop:disable Style/GuardClause
|
@@ -541,7 +538,7 @@ Invoke-PowerShellUserCode @params
|
|
541
538
|
read_from_pipe(pipe, 0) { |s| output << s } while self.class.readable?(pipe)
|
542
539
|
|
543
540
|
# String has been binary up to this point, so force UTF-8 now
|
544
|
-
output == [] ? [] : [output.join
|
541
|
+
output == [] ? [] : [output.join.force_encoding(Encoding::UTF_8)]
|
545
542
|
end
|
546
543
|
|
547
544
|
# Open threads and pipes to read stdout and stderr from the PowerShell manager,
|
@@ -592,8 +589,8 @@ Invoke-PowerShellUserCode @params
|
|
592
589
|
|
593
590
|
[
|
594
591
|
output,
|
595
|
-
stdout == [] ? nil : stdout.join
|
596
|
-
stderr_reader.value
|
592
|
+
stdout == [] ? nil : stdout.join, # native stdout
|
593
|
+
stderr_reader.value # native stderr
|
597
594
|
]
|
598
595
|
ensure
|
599
596
|
# Failsafe if the prior unlock was never reached / Mutex wasn't unlocked
|
@@ -64,6 +64,7 @@ RSpec.describe 'DSC Acceptance: Basic' do
|
|
64
64
|
expect(second_run_result[:exitcode]).to be(0)
|
65
65
|
end
|
66
66
|
end
|
67
|
+
|
67
68
|
context 'Creating' do
|
68
69
|
let(:manifest) do
|
69
70
|
[
|
@@ -127,6 +128,7 @@ RSpec.describe 'DSC Acceptance: Basic' do
|
|
127
128
|
expect(second_run_result[:exitcode]).to be(0)
|
128
129
|
end
|
129
130
|
end
|
131
|
+
|
130
132
|
context 'PSDscRunAsCredential' do
|
131
133
|
before(:all) do
|
132
134
|
prep_command = <<~PREP_USER.strip
|
@@ -144,6 +146,7 @@ RSpec.describe 'DSC Acceptance: Basic' do
|
|
144
146
|
PREP_USER
|
145
147
|
execute_reset_command(prep_command)
|
146
148
|
end
|
149
|
+
|
147
150
|
after(:all) do
|
148
151
|
cleanup_command = <<~CLEANUP_USER.strip
|
149
152
|
Remove-LocalUser -Name #{local_user} -ErrorAction Stop
|
@@ -178,6 +181,7 @@ RSpec.describe 'DSC Acceptance: Basic' do
|
|
178
181
|
expect(second_run_result[:exitcode]).to be(0)
|
179
182
|
end
|
180
183
|
end
|
184
|
+
|
181
185
|
context 'with an invalid credential' do
|
182
186
|
let(:manifest) do
|
183
187
|
[
|
@@ -1,10 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
# TODO: Test against mcollera/AccessControlDsc for CIM instance behavior
|
3
4
|
# 1. Make sure valid nested CIM instances can be passed to Invoke-DscResource
|
4
5
|
# 2. Make sure nested CIM instances can be read back from Invoke-DscResource
|
5
6
|
|
6
|
-
# frozen_string_literal: true
|
7
|
-
|
8
7
|
require 'spec_helper'
|
9
8
|
require 'ruby-pwsh'
|
10
9
|
|
@@ -26,7 +25,7 @@ RSpec.describe 'DSC Acceptance: Complex' do
|
|
26
25
|
end
|
27
26
|
|
28
27
|
context 'Managing the access control list of a folder' do
|
29
|
-
before
|
28
|
+
before do
|
30
29
|
reset_command = <<~RESET_COMMAND
|
31
30
|
$TestFolderPath = Join-Path -Path "#{fixtures_path}" -Childpath access_control
|
32
31
|
# Delete the test folder if it exists (to clear access control modifications)
|
@@ -62,7 +61,7 @@ RSpec.describe 'DSC Acceptance: Complex' do
|
|
62
61
|
]
|
63
62
|
}
|
64
63
|
MANIFEST
|
65
|
-
File.
|
64
|
+
File.write(test_manifest, content)
|
66
65
|
# Apply the test manifest
|
67
66
|
first_run_result = powershell.execute(puppet_apply)
|
68
67
|
expect(first_run_result[:exitcode]).to be(2)
|
@@ -32,7 +32,7 @@ RSpec.describe 'DSC Acceptance: Class-Based Resource' do
|
|
32
32
|
].join(' ')
|
33
33
|
end
|
34
34
|
|
35
|
-
before
|
35
|
+
before do
|
36
36
|
reset_command = <<~RESET_COMMAND
|
37
37
|
$PsrcPath = '#{psrc_path}'
|
38
38
|
# Delete the test PSRC fixture if it exists
|
@@ -68,7 +68,7 @@ RSpec.describe 'DSC Acceptance: Class-Based Resource' do
|
|
68
68
|
].join(' ')
|
69
69
|
end
|
70
70
|
|
71
|
-
before
|
71
|
+
before do
|
72
72
|
reset_command = <<~RESET_COMMAND
|
73
73
|
$PsrcPath = '#{psrc_path}'
|
74
74
|
# Delete the test PSRC fixture if it exists
|
@@ -104,7 +104,7 @@ RSpec.describe 'DSC Acceptance: Class-Based Resource' do
|
|
104
104
|
].join(' ')
|
105
105
|
end
|
106
106
|
|
107
|
-
before
|
107
|
+
before do
|
108
108
|
reset_command = <<~RESET_COMMAND
|
109
109
|
$PsrcPath = '#{psrc_path}'
|
110
110
|
# Delete the test PSRC fixture if it exists
|
@@ -21,7 +21,7 @@ RSpec.describe 'DSC Acceptance: Complex' do
|
|
21
21
|
end
|
22
22
|
|
23
23
|
context 'Adding a new website' do
|
24
|
-
before
|
24
|
+
before do
|
25
25
|
reset_command = <<~RESET_COMMAND
|
26
26
|
# Ensure IIS is not installed
|
27
27
|
$Feature = Get-WindowsFeature -Name 'Web-Asp-Net45'
|
@@ -108,7 +108,7 @@ RSpec.describe 'DSC Acceptance: Complex' do
|
|
108
108
|
require => File['WebContentIndex'],
|
109
109
|
}
|
110
110
|
MANIFEST
|
111
|
-
File.
|
111
|
+
File.write(test_manifest, content)
|
112
112
|
# Puppet apply the test manifest
|
113
113
|
first_run_result = powershell.execute(puppet_apply)
|
114
114
|
expect(first_run_result[:exitcode]).to be(2)
|
@@ -0,0 +1,6 @@
|
|
1
|
+
Get-ChildItem WSMan:\localhost\Listener\ -OutVariable Listeners | Format-List * -Force
|
2
|
+
$HTTPListener = $Listeners | Where-Object -FilterScript { $_.Keys.Contains('Transport=HTTP') }
|
3
|
+
If ($HTTPListener.Count -eq 0) {
|
4
|
+
winrm create winrm/config/Listener?Address=*+Transport=HTTP
|
5
|
+
winrm e winrm/config/listener
|
6
|
+
}
|