ruby-pwsh 0.10.3 → 0.11.0.rc.1
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/.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
|
+
}
|