winrm 1.7.3 → 1.8.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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +10 -10
  3. data/.rspec +3 -3
  4. data/.travis.yml +12 -12
  5. data/Gemfile +9 -9
  6. data/LICENSE +202 -202
  7. data/README.md +213 -194
  8. data/Rakefile +36 -36
  9. data/Vagrantfile +9 -9
  10. data/WinrmAppveyor.psm1 +32 -0
  11. data/appveyor.yml +51 -42
  12. data/bin/rwinrm +97 -97
  13. data/changelog.md +3 -0
  14. data/lib/winrm.rb +42 -42
  15. data/lib/winrm/command_executor.rb +6 -2
  16. data/lib/winrm/command_output_decoder.rb +53 -53
  17. data/lib/winrm/exceptions/exceptions.rb +57 -57
  18. data/lib/winrm/helpers/iso8601_duration.rb +58 -58
  19. data/lib/winrm/helpers/powershell_script.rb +42 -42
  20. data/lib/winrm/http/response_handler.rb +82 -82
  21. data/lib/winrm/http/transport.rb +17 -0
  22. data/lib/winrm/output.rb +43 -43
  23. data/lib/winrm/soap_provider.rb +39 -39
  24. data/lib/winrm/version.rb +1 -1
  25. data/lib/winrm/winrm_service.rb +550 -547
  26. data/preamble +17 -17
  27. data/spec/auth_timeout_spec.rb +16 -16
  28. data/spec/cmd_spec.rb +102 -102
  29. data/spec/command_executor_spec.rb +27 -10
  30. data/spec/command_output_decoder_spec.rb +37 -37
  31. data/spec/config-example.yml +19 -19
  32. data/spec/exception_spec.rb +50 -50
  33. data/spec/issue_184_spec.rb +67 -67
  34. data/spec/issue_59_spec.rb +23 -23
  35. data/spec/matchers.rb +74 -74
  36. data/spec/output_spec.rb +110 -110
  37. data/spec/powershell_spec.rb +97 -97
  38. data/spec/response_handler_spec.rb +59 -59
  39. data/spec/spec_helper.rb +73 -73
  40. data/spec/stubs/responses/get_command_output_response.xml.erb +13 -13
  41. data/spec/stubs/responses/open_shell_v1.xml +19 -19
  42. data/spec/stubs/responses/open_shell_v2.xml +20 -20
  43. data/spec/stubs/responses/soap_fault_v1.xml +36 -36
  44. data/spec/stubs/responses/soap_fault_v2.xml +42 -42
  45. data/spec/stubs/responses/wmi_error_v2.xml +41 -41
  46. data/spec/transport_spec.rb +139 -124
  47. data/spec/winrm_options_spec.rb +76 -76
  48. data/spec/winrm_primitives_spec.rb +51 -51
  49. data/spec/wql_spec.rb +14 -14
  50. data/winrm.gemspec +40 -40
  51. metadata +4 -3
@@ -1,97 +1,97 @@
1
- # encoding: UTF-8
2
- describe 'winrm client powershell', integration: true do
3
- before(:all) do
4
- @winrm = winrm_connection
5
- end
6
-
7
- describe 'ipconfig' do
8
- subject(:output) { @winrm.powershell('ipconfig') }
9
- it { should have_exit_code 0 }
10
- it { should have_stdout_match(/Windows IP Configuration/) }
11
- it { should have_no_stderr }
12
- end
13
-
14
- describe 'echo \'hello world\' using apostrophes' do
15
- subject(:output) { @winrm.powershell("echo 'hello world'") }
16
- it { should have_exit_code 0 }
17
- it { should have_stdout_match(/hello world/) }
18
- it { should have_no_stderr }
19
- end
20
-
21
- describe 'dir with incorrect argument /z' do
22
- subject(:output) { @winrm.powershell('dir /z') }
23
- it { should have_exit_code 1 }
24
- it { should have_no_stdout }
25
- end
26
-
27
- describe 'Math area calculation' do
28
- subject(:output) do
29
- @winrm.powershell(<<-EOH
30
- $diameter = 4.5
31
- $area = [Math]::pow([Math]::PI * ($diameter/2), 2)
32
- Write-Host $area
33
- EOH
34
- )
35
- end
36
- it { should have_exit_code 0 }
37
- it { should have_stdout_match(/49.9648722805149/) }
38
- it { should have_no_stderr }
39
- end
40
-
41
- describe 'ipconfig with a block' do
42
- subject(:stdout) do
43
- outvar = ''
44
- @winrm.powershell('ipconfig') do |stdout, _stderr|
45
- outvar << stdout
46
- end
47
- outvar
48
- end
49
- it { should match(/Windows IP Configuration/) }
50
- end
51
-
52
- describe 'capturing output from Write-Host and Write-Error' do
53
- subject(:output) do
54
- script = <<-eos
55
- Write-Host 'Hello'
56
- $host.ui.WriteErrorLine(', world!')
57
- eos
58
-
59
- @captured_stdout = ''
60
- @captured_stderr = ''
61
- @winrm.powershell(script) do |stdout, stderr|
62
- @captured_stdout << stdout if stdout
63
- @captured_stderr << stderr if stderr
64
- end
65
- end
66
-
67
- it 'should have stdout' do
68
- expect(output.stdout).to eq("Hello\n")
69
- expect(output.stdout).to eq(@captured_stdout)
70
- end
71
-
72
- it 'should have stderr' do
73
- # TODO: Option to parse CLIXML
74
- # expect(output.output).to eq("Hello\n, world!")
75
- # expect(output.stderr).to eq(", world!")
76
- expect(output.stderr).to eq(
77
- "#< CLIXML\r\n<Objs Version=\"1.1.0.1\" " \
78
- "xmlns=\"http://schemas.microsoft.com/powershell/2004/04\">" \
79
- "<S S=\"Error\">, world!_x000D__x000A_</S></Objs>")
80
- expect(output.stderr).to eq(@captured_stderr)
81
- end
82
-
83
- it 'should have output' do
84
- # TODO: Option to parse CLIXML
85
- # expect(output.output).to eq("Hello\n, world!")
86
- expect(output.output).to eq("Hello\n#< CLIXML\r\n<Objs Version=\"1.1.0.1\" " \
87
- "xmlns=\"http://schemas.microsoft.com/powershell/2004/04\">" \
88
- "<S S=\"Error\">, world!_x000D__x000A_</S></Objs>")
89
- end
90
- end
91
-
92
- describe 'it should handle utf-8 characters' do
93
- subject(:output) { @winrm.powershell('echo "✓1234-äöü"') }
94
- it { should have_exit_code 0 }
95
- it { should have_stdout_match(/✓1234-äöü/) }
96
- end
97
- end
1
+ # encoding: UTF-8
2
+ describe 'winrm client powershell', integration: true do
3
+ before(:all) do
4
+ @winrm = winrm_connection
5
+ end
6
+
7
+ describe 'ipconfig' do
8
+ subject(:output) { @winrm.powershell('ipconfig') }
9
+ it { should have_exit_code 0 }
10
+ it { should have_stdout_match(/Windows IP Configuration/) }
11
+ it { should have_no_stderr }
12
+ end
13
+
14
+ describe 'echo \'hello world\' using apostrophes' do
15
+ subject(:output) { @winrm.powershell("echo 'hello world'") }
16
+ it { should have_exit_code 0 }
17
+ it { should have_stdout_match(/hello world/) }
18
+ it { should have_no_stderr }
19
+ end
20
+
21
+ describe 'dir with incorrect argument /z' do
22
+ subject(:output) { @winrm.powershell('dir /z') }
23
+ it { should have_exit_code 1 }
24
+ it { should have_no_stdout }
25
+ end
26
+
27
+ describe 'Math area calculation' do
28
+ subject(:output) do
29
+ @winrm.powershell(<<-EOH
30
+ $diameter = 4.5
31
+ $area = [Math]::pow([Math]::PI * ($diameter/2), 2)
32
+ Write-Host $area
33
+ EOH
34
+ )
35
+ end
36
+ it { should have_exit_code 0 }
37
+ it { should have_stdout_match(/49.9648722805149/) }
38
+ it { should have_no_stderr }
39
+ end
40
+
41
+ describe 'ipconfig with a block' do
42
+ subject(:stdout) do
43
+ outvar = ''
44
+ @winrm.powershell('ipconfig') do |stdout, _stderr|
45
+ outvar << stdout
46
+ end
47
+ outvar
48
+ end
49
+ it { should match(/Windows IP Configuration/) }
50
+ end
51
+
52
+ describe 'capturing output from Write-Host and Write-Error' do
53
+ subject(:output) do
54
+ script = <<-eos
55
+ Write-Host 'Hello'
56
+ $host.ui.WriteErrorLine(', world!')
57
+ eos
58
+
59
+ @captured_stdout = ''
60
+ @captured_stderr = ''
61
+ @winrm.powershell(script) do |stdout, stderr|
62
+ @captured_stdout << stdout if stdout
63
+ @captured_stderr << stderr if stderr
64
+ end
65
+ end
66
+
67
+ it 'should have stdout' do
68
+ expect(output.stdout).to eq("Hello\n")
69
+ expect(output.stdout).to eq(@captured_stdout)
70
+ end
71
+
72
+ it 'should have stderr' do
73
+ # TODO: Option to parse CLIXML
74
+ # expect(output.output).to eq("Hello\n, world!")
75
+ # expect(output.stderr).to eq(", world!")
76
+ expect(output.stderr).to eq(
77
+ "#< CLIXML\r\n<Objs Version=\"1.1.0.1\" " \
78
+ "xmlns=\"http://schemas.microsoft.com/powershell/2004/04\">" \
79
+ "<S S=\"Error\">, world!_x000D__x000A_</S></Objs>")
80
+ expect(output.stderr).to eq(@captured_stderr)
81
+ end
82
+
83
+ it 'should have output' do
84
+ # TODO: Option to parse CLIXML
85
+ # expect(output.output).to eq("Hello\n, world!")
86
+ expect(output.output).to eq("Hello\n#< CLIXML\r\n<Objs Version=\"1.1.0.1\" " \
87
+ "xmlns=\"http://schemas.microsoft.com/powershell/2004/04\">" \
88
+ "<S S=\"Error\">, world!_x000D__x000A_</S></Objs>")
89
+ end
90
+ end
91
+
92
+ describe 'it should handle utf-8 characters' do
93
+ subject(:output) { @winrm.powershell('echo "✓1234-äöü"') }
94
+ it { should have_exit_code 0 }
95
+ it { should have_stdout_match(/✓1234-äöü/) }
96
+ end
97
+ end
@@ -1,59 +1,59 @@
1
- # encoding: UTF-8
2
- require 'winrm/http/response_handler'
3
-
4
- describe 'response handler', unit: true do
5
- %w(v1, v2).each do |winrm_version|
6
- let(:soap_fault) { File.read("spec/stubs/responses/soap_fault_#{winrm_version}.xml") }
7
- let(:open_shell) { File.read("spec/stubs/responses/open_shell_#{winrm_version}.xml") }
8
-
9
- describe "successful 200 #{winrm_version} response" do
10
- it 'returns an xml doc' do
11
- handler = WinRM::ResponseHandler.new(open_shell, 200)
12
- xml_doc = handler.parse_to_xml
13
- expect(xml_doc).to be_instance_of(REXML::Document)
14
- expect(xml_doc.to_s).to eq(REXML::Document.new(open_shell).to_s)
15
- end
16
- end
17
-
18
- describe "failed 500 #{winrm_version} response" do
19
- it 'raises a WinRMHTTPTransportError' do
20
- handler = WinRM::ResponseHandler.new('', 500)
21
- expect { handler.parse_to_xml }.to raise_error(WinRM::WinRMHTTPTransportError)
22
- end
23
- end
24
-
25
- describe "failed 401 #{winrm_version} response" do
26
- it 'raises a WinRMAuthorizationError' do
27
- handler = WinRM::ResponseHandler.new('', 401)
28
- expect { handler.parse_to_xml }.to raise_error(WinRM::WinRMAuthorizationError)
29
- end
30
- end
31
-
32
- describe "failed 400 #{winrm_version} response" do
33
- it 'raises a WinRMWSManFault' do
34
- handler = WinRM::ResponseHandler.new(soap_fault, 400)
35
- begin
36
- handler.parse_to_xml
37
- rescue WinRM::WinRMWSManFault => e
38
- expect(e.fault_code).to eq('2150858778')
39
- expect(e.fault_description).to include(
40
- 'The specified class does not exist in the given namespace')
41
- end
42
- end
43
- end
44
- end
45
-
46
- describe 'failed 500 WMI error response' do
47
- let(:wmi_error) { File.read('spec/stubs/responses/wmi_error_v2.xml') }
48
-
49
- it 'raises a WinRMWMIError' do
50
- handler = WinRM::ResponseHandler.new(wmi_error, 500)
51
- begin
52
- handler.parse_to_xml
53
- rescue WinRM::WinRMWMIError => e
54
- expect(e.error_code).to eq('2150859173')
55
- expect(e.error).to include('The WS-Management service cannot process the request.')
56
- end
57
- end
58
- end
59
- end
1
+ # encoding: UTF-8
2
+ require 'winrm/http/response_handler'
3
+
4
+ describe 'response handler', unit: true do
5
+ %w(v1, v2).each do |winrm_version|
6
+ let(:soap_fault) { File.read("spec/stubs/responses/soap_fault_#{winrm_version}.xml") }
7
+ let(:open_shell) { File.read("spec/stubs/responses/open_shell_#{winrm_version}.xml") }
8
+
9
+ describe "successful 200 #{winrm_version} response" do
10
+ it 'returns an xml doc' do
11
+ handler = WinRM::ResponseHandler.new(open_shell, 200)
12
+ xml_doc = handler.parse_to_xml
13
+ expect(xml_doc).to be_instance_of(REXML::Document)
14
+ expect(xml_doc.to_s).to eq(REXML::Document.new(open_shell).to_s)
15
+ end
16
+ end
17
+
18
+ describe "failed 500 #{winrm_version} response" do
19
+ it 'raises a WinRMHTTPTransportError' do
20
+ handler = WinRM::ResponseHandler.new('', 500)
21
+ expect { handler.parse_to_xml }.to raise_error(WinRM::WinRMHTTPTransportError)
22
+ end
23
+ end
24
+
25
+ describe "failed 401 #{winrm_version} response" do
26
+ it 'raises a WinRMAuthorizationError' do
27
+ handler = WinRM::ResponseHandler.new('', 401)
28
+ expect { handler.parse_to_xml }.to raise_error(WinRM::WinRMAuthorizationError)
29
+ end
30
+ end
31
+
32
+ describe "failed 400 #{winrm_version} response" do
33
+ it 'raises a WinRMWSManFault' do
34
+ handler = WinRM::ResponseHandler.new(soap_fault, 400)
35
+ begin
36
+ handler.parse_to_xml
37
+ rescue WinRM::WinRMWSManFault => e
38
+ expect(e.fault_code).to eq('2150858778')
39
+ expect(e.fault_description).to include(
40
+ 'The specified class does not exist in the given namespace')
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ describe 'failed 500 WMI error response' do
47
+ let(:wmi_error) { File.read('spec/stubs/responses/wmi_error_v2.xml') }
48
+
49
+ it 'raises a WinRMWMIError' do
50
+ handler = WinRM::ResponseHandler.new(wmi_error, 500)
51
+ begin
52
+ handler.parse_to_xml
53
+ rescue WinRM::WinRMWMIError => e
54
+ expect(e.error_code).to eq('2150859173')
55
+ expect(e.error).to include('The WS-Management service cannot process the request.')
56
+ end
57
+ end
58
+ end
59
+ end
@@ -1,73 +1,73 @@
1
- # encoding: UTF-8
2
- require 'rubygems'
3
- require 'bundler/setup'
4
- require 'winrm'
5
- require 'json'
6
- require_relative 'matchers'
7
-
8
- # Creates a WinRM connection for integration tests
9
- module ConnectionHelper
10
- # rubocop:disable AbcSize
11
- def winrm_connection
12
- winrm = WinRM::WinRMWebService.new(
13
- config[:endpoint], config[:auth_type].to_sym, config[:options])
14
- winrm.logger.level = :error
15
- winrm
16
- end
17
- # rubocop:enable AbcSize
18
-
19
- def config
20
- @config ||= begin
21
- cfg = symbolize_keys(YAML.load(File.read(winrm_config_path)))
22
- cfg[:options].merge!(basic_auth_only: true) unless cfg[:auth_type].eql? :kerberos
23
- merge_environment!(cfg)
24
- cfg
25
- end
26
- end
27
-
28
- def merge_environment!(config)
29
- merge_config_option_from_environment(config, 'user')
30
- merge_config_option_from_environment(config, 'pass')
31
- merge_config_option_from_environment(config, 'no_ssl_peer_verification')
32
- if ENV['use_ssl_peer_fingerprint']
33
- config[:options][:ssl_peer_fingerprint] = ENV['winrm_cert']
34
- end
35
- config[:endpoint] = ENV['winrm_endpoint'] if ENV['winrm_endpoint']
36
- end
37
-
38
- def merge_config_option_from_environment(config, key)
39
- env_key = 'winrm_' + key
40
- config[:options][key.to_sym] = ENV[env_key] if ENV[env_key]
41
- end
42
-
43
- def winrm_config_path
44
- # Copy config-example.yml to config.yml and edit for your local configuration
45
- path = File.expand_path("#{File.dirname(__FILE__)}/config.yml")
46
- unless File.exist?(path)
47
- # user hasn't done this, so use sane defaults for unit tests
48
- path = File.expand_path("#{File.dirname(__FILE__)}/config-example.yml")
49
- end
50
- path
51
- end
52
-
53
- # rubocop:disable Metrics/MethodLength
54
- def symbolize_keys(hash)
55
- hash.each_with_object({}) do |(key, value), result|
56
- new_key = case key
57
- when String then key.to_sym
58
- else key
59
- end
60
- new_value = case value
61
- when Hash then symbolize_keys(value)
62
- else value
63
- end
64
- result[new_key] = new_value
65
- result
66
- end
67
- end
68
- # rubocop:enable Metrics/MethodLength
69
- end
70
-
71
- RSpec.configure do |config|
72
- config.include(ConnectionHelper)
73
- end
1
+ # encoding: UTF-8
2
+ require 'rubygems'
3
+ require 'bundler/setup'
4
+ require 'winrm'
5
+ require 'json'
6
+ require_relative 'matchers'
7
+
8
+ # Creates a WinRM connection for integration tests
9
+ module ConnectionHelper
10
+ # rubocop:disable AbcSize
11
+ def winrm_connection
12
+ winrm = WinRM::WinRMWebService.new(
13
+ config[:endpoint], config[:auth_type].to_sym, config[:options])
14
+ winrm.logger.level = :error
15
+ winrm
16
+ end
17
+ # rubocop:enable AbcSize
18
+
19
+ def config
20
+ @config ||= begin
21
+ cfg = symbolize_keys(YAML.load(File.read(winrm_config_path)))
22
+ cfg[:options].merge!(basic_auth_only: true) unless cfg[:auth_type].eql? :kerberos
23
+ merge_environment!(cfg)
24
+ cfg
25
+ end
26
+ end
27
+
28
+ def merge_environment!(config)
29
+ merge_config_option_from_environment(config, 'user')
30
+ merge_config_option_from_environment(config, 'pass')
31
+ merge_config_option_from_environment(config, 'no_ssl_peer_verification')
32
+ if ENV['use_ssl_peer_fingerprint']
33
+ config[:options][:ssl_peer_fingerprint] = ENV['winrm_cert']
34
+ end
35
+ config[:endpoint] = ENV['winrm_endpoint'] if ENV['winrm_endpoint']
36
+ end
37
+
38
+ def merge_config_option_from_environment(config, key)
39
+ env_key = 'winrm_' + key
40
+ config[:options][key.to_sym] = ENV[env_key] if ENV[env_key]
41
+ end
42
+
43
+ def winrm_config_path
44
+ # Copy config-example.yml to config.yml and edit for your local configuration
45
+ path = File.expand_path("#{File.dirname(__FILE__)}/config.yml")
46
+ unless File.exist?(path)
47
+ # user hasn't done this, so use sane defaults for unit tests
48
+ path = File.expand_path("#{File.dirname(__FILE__)}/config-example.yml")
49
+ end
50
+ path
51
+ end
52
+
53
+ # rubocop:disable Metrics/MethodLength
54
+ def symbolize_keys(hash)
55
+ hash.each_with_object({}) do |(key, value), result|
56
+ new_key = case key
57
+ when String then key.to_sym
58
+ else key
59
+ end
60
+ new_value = case value
61
+ when Hash then symbolize_keys(value)
62
+ else value
63
+ end
64
+ result[new_key] = new_value
65
+ result
66
+ end
67
+ end
68
+ # rubocop:enable Metrics/MethodLength
69
+ end
70
+
71
+ RSpec.configure do |config|
72
+ config.include(ConnectionHelper)
73
+ end