winrm 1.8.1 → 2.0.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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +10 -11
  3. data/.rubocop.yml +26 -22
  4. data/.travis.yml +11 -12
  5. data/Gemfile +3 -9
  6. data/LICENSE +202 -202
  7. data/README.md +232 -215
  8. data/Rakefile +34 -36
  9. data/Vagrantfile +6 -9
  10. data/WinrmAppveyor.psm1 +31 -31
  11. data/appveyor.yml +51 -51
  12. data/bin/rwinrm +97 -97
  13. data/changelog.md +86 -86
  14. data/lib/winrm.rb +39 -42
  15. data/lib/winrm/connection.rb +82 -0
  16. data/lib/winrm/connection_opts.rb +87 -0
  17. data/lib/winrm/{exceptions/exceptions.rb → exceptions.rb} +76 -57
  18. data/lib/winrm/http/response_handler.rb +96 -82
  19. data/lib/winrm/http/transport.rb +424 -435
  20. data/lib/winrm/http/transport_factory.rb +68 -0
  21. data/lib/winrm/output.rb +59 -43
  22. data/lib/winrm/psrp/create_pipeline.xml.erb +167 -0
  23. data/lib/winrm/psrp/fragment.rb +70 -0
  24. data/lib/winrm/psrp/init_runspace_pool.xml.erb +224 -0
  25. data/lib/winrm/psrp/message.rb +130 -0
  26. data/lib/winrm/psrp/message_data.rb +41 -0
  27. data/lib/winrm/psrp/message_data/base.rb +49 -0
  28. data/lib/winrm/psrp/message_data/error_record.rb +68 -0
  29. data/lib/winrm/psrp/message_data/pipeline_host_call.rb +32 -0
  30. data/lib/winrm/psrp/message_data/pipeline_output.rb +49 -0
  31. data/lib/winrm/psrp/message_data/runspacepool_host_call.rb +32 -0
  32. data/lib/winrm/psrp/message_data/runspacepool_state.rb +39 -0
  33. data/lib/winrm/psrp/message_data/session_capability.rb +36 -0
  34. data/lib/winrm/psrp/message_defragmenter.rb +62 -0
  35. data/lib/winrm/psrp/message_factory.rb +75 -0
  36. data/lib/winrm/psrp/message_fragmenter.rb +60 -0
  37. data/lib/winrm/psrp/powershell_output_decoder.rb +120 -0
  38. data/lib/winrm/psrp/receive_response_reader.rb +93 -0
  39. data/lib/winrm/psrp/session_capability.xml.erb +7 -0
  40. data/lib/winrm/psrp/uuid.rb +40 -0
  41. data/lib/winrm/shells/base.rb +175 -0
  42. data/lib/winrm/shells/cmd.rb +65 -0
  43. data/lib/winrm/shells/power_shell.rb +201 -0
  44. data/lib/winrm/shells/retryable.rb +45 -0
  45. data/lib/winrm/shells/shell_factory.rb +50 -0
  46. data/lib/winrm/version.rb +7 -7
  47. data/lib/winrm/wsmv/base.rb +59 -0
  48. data/lib/winrm/wsmv/cleanup_command.rb +61 -0
  49. data/lib/winrm/wsmv/close_shell.rb +50 -0
  50. data/lib/winrm/wsmv/command.rb +101 -0
  51. data/lib/winrm/wsmv/command_output.rb +76 -0
  52. data/lib/winrm/wsmv/command_output_decoder.rb +55 -0
  53. data/lib/winrm/wsmv/configuration.rb +46 -0
  54. data/lib/winrm/wsmv/create_pipeline.rb +66 -0
  55. data/lib/winrm/wsmv/create_shell.rb +119 -0
  56. data/lib/winrm/wsmv/header.rb +203 -0
  57. data/lib/winrm/wsmv/init_runspace_pool.rb +95 -0
  58. data/lib/winrm/wsmv/iso8601_duration.rb +60 -0
  59. data/lib/winrm/wsmv/keep_alive.rb +68 -0
  60. data/lib/winrm/wsmv/receive_response_reader.rb +128 -0
  61. data/lib/winrm/wsmv/send_data.rb +68 -0
  62. data/lib/winrm/wsmv/soap.rb +51 -0
  63. data/lib/winrm/wsmv/wql_query.rb +79 -0
  64. data/lib/winrm/wsmv/write_stdin.rb +88 -0
  65. data/preamble +17 -17
  66. data/{spec → tests/integration}/auth_timeout_spec.rb +18 -16
  67. data/{spec → tests/integration}/cmd_spec.rb +104 -102
  68. data/{spec → tests/integration}/config-example.yml +16 -19
  69. data/{spec → tests/integration}/issue_59_spec.rb +26 -23
  70. data/tests/integration/powershell_spec.rb +154 -0
  71. data/{spec → tests/integration}/spec_helper.rb +65 -73
  72. data/{spec → tests/integration}/transport_spec.rb +99 -139
  73. data/{spec → tests/integration}/wql_spec.rb +16 -14
  74. data/{spec → tests}/matchers.rb +60 -74
  75. data/tests/spec/configuration_spec.rb +93 -0
  76. data/tests/spec/connection_spec.rb +39 -0
  77. data/{spec → tests/spec}/exception_spec.rb +50 -50
  78. data/tests/spec/http/transport_factory_spec.rb +68 -0
  79. data/tests/spec/http/transport_spec.rb +44 -0
  80. data/{spec → tests/spec}/output_spec.rb +127 -110
  81. data/tests/spec/psrp/fragment_spec.rb +62 -0
  82. data/tests/spec/psrp/message_data/base_spec.rb +13 -0
  83. data/tests/spec/psrp/message_data/error_record_spec.rb +41 -0
  84. data/tests/spec/psrp/message_data/pipeline_host_call_spec.rb +25 -0
  85. data/tests/spec/psrp/message_data/pipeline_output_spec.rb +32 -0
  86. data/tests/spec/psrp/message_data/runspace_pool_host_call_spec.rb +25 -0
  87. data/tests/spec/psrp/message_data/runspacepool_state_spec.rb +16 -0
  88. data/tests/spec/psrp/message_data/session_capability_spec.rb +30 -0
  89. data/tests/spec/psrp/message_data_spec.rb +35 -0
  90. data/tests/spec/psrp/message_defragmenter_spec.rb +47 -0
  91. data/tests/spec/psrp/message_fragmenter_spec.rb +105 -0
  92. data/tests/spec/psrp/powershell_output_decoder_spec.rb +84 -0
  93. data/tests/spec/psrp/psrp_message_spec.rb +70 -0
  94. data/tests/spec/psrp/recieve_response_reader_spec.rb +154 -0
  95. data/tests/spec/psrp/uuid_spec.rb +28 -0
  96. data/{spec → tests/spec}/response_handler_spec.rb +61 -61
  97. data/tests/spec/shells/base_spec.rb +202 -0
  98. data/tests/spec/shells/cmd_spec.rb +75 -0
  99. data/tests/spec/shells/powershell_spec.rb +175 -0
  100. data/tests/spec/spec_helper.rb +47 -0
  101. data/tests/spec/stubs/clixml/error_record.xml.erb +84 -0
  102. data/{spec → tests/spec}/stubs/responses/get_command_output_response.xml.erb +13 -13
  103. data/tests/spec/stubs/responses/get_command_output_response_not_done.xml.erb +10 -0
  104. data/tests/spec/stubs/responses/get_powershell_keepalive_response.xml.erb +10 -0
  105. data/tests/spec/stubs/responses/get_powershell_output_response.xml.erb +12 -0
  106. data/tests/spec/stubs/responses/get_powershell_output_response_not_done.xml.erb +9 -0
  107. data/{spec → tests/spec}/stubs/responses/open_shell_v1.xml +19 -19
  108. data/{spec → tests/spec}/stubs/responses/open_shell_v2.xml +20 -20
  109. data/{spec → tests/spec}/stubs/responses/soap_fault_v1.xml +36 -36
  110. data/{spec → tests/spec}/stubs/responses/soap_fault_v2.xml +42 -42
  111. data/{spec → tests/spec}/stubs/responses/wmi_error_v2.xml +41 -41
  112. data/tests/spec/wsmv/cleanup_command_spec.rb +22 -0
  113. data/tests/spec/wsmv/close_shell_spec.rb +17 -0
  114. data/{spec → tests/spec/wsmv}/command_output_decoder_spec.rb +37 -37
  115. data/tests/spec/wsmv/command_output_spec.rb +45 -0
  116. data/tests/spec/wsmv/command_spec.rb +19 -0
  117. data/tests/spec/wsmv/configuration_spec.rb +17 -0
  118. data/tests/spec/wsmv/create_pipeline_spec.rb +31 -0
  119. data/tests/spec/wsmv/create_shell_spec.rb +38 -0
  120. data/tests/spec/wsmv/init_runspace_pool_spec.rb +36 -0
  121. data/tests/spec/wsmv/keep_alive_spec.rb +21 -0
  122. data/tests/spec/wsmv/receive_response_reader_spec.rb +123 -0
  123. data/tests/spec/wsmv/send_data_spec.rb +30 -0
  124. data/tests/spec/wsmv/wql_query_spec.rb +13 -0
  125. data/tests/spec/wsmv/write_stdin_spec.rb +22 -0
  126. data/winrm.gemspec +42 -40
  127. metadata +140 -38
  128. data/.rspec +0 -3
  129. data/lib/winrm/command_executor.rb +0 -243
  130. data/lib/winrm/command_output_decoder.rb +0 -53
  131. data/lib/winrm/helpers/iso8601_duration.rb +0 -58
  132. data/lib/winrm/helpers/powershell_script.rb +0 -42
  133. data/lib/winrm/soap_provider.rb +0 -39
  134. data/lib/winrm/winrm_service.rb +0 -550
  135. data/spec/command_executor_spec.rb +0 -475
  136. data/spec/issue_184_spec.rb +0 -67
  137. data/spec/powershell_spec.rb +0 -97
  138. data/spec/winrm_options_spec.rb +0 -76
  139. data/spec/winrm_primitives_spec.rb +0 -51
@@ -1,41 +1,41 @@
1
- <s:Envelope xmlns:a='http://schemas.xmlsoap.org/ws/2004/08/addressing' xmlns:e='http://schemas.xmlsoap.org/ws/2004/08/eventing' xml:lang='en-US' xmlns:n='http://schemas.xmlsoap.org/ws/2004/09/enumeration' xmlns:p='http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd' xmlns:s='http://www.w3.org/2003/05/soap-envelope' xmlns:w='http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd' xmlns:x='http://schemas.xmlsoap.org/ws/2004/09/transfer'>
2
- <s:Header>
3
- <a:Action>http://schemas.dmtf.org/wbem/wsman/1/wsman/fault</a:Action>
4
- <a:MessageID>uuid:B8829021-48C3-4F27-B94B-491DAC4F29B1</a:MessageID>
5
- <a:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:To>
6
- </s:Header>
7
- <s:Body>
8
- <s:Fault>
9
- <s:Code>
10
- <s:Value>s:Sender</s:Value>
11
- <s:Subcode>
12
- <s:Value>w:QuotaLimit</s:Value>
13
- </s:Subcode>
14
- </s:Code>
15
- <s:Reason>
16
- <s:Text xml:lang='en-US'>The WS-Management service cannot process the request. The maximum number of concurrent shells for this user has been exceeded. Close existing shells or raise the quota for this user. </s:Text>
17
- </s:Reason>
18
- <s:Detail>
19
- <p:MSFT_WmiError b:IsCIM_Error='true' xmlns:b='http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd' xmlns:cim='http://schemas.dmtf.org/wbem/wscim/1/common' xmlns:p='http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/MSFT_WmiError' xsi:type='p:MSFT_WmiError_Type' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
20
- <p:CIMStatusCode xsi:type='cim:cimUnsignedInt'>27</p:CIMStatusCode>
21
- <p:CIMStatusCodeDescription xsi:nil='true' xsi:type='cim:cimString'/>
22
- <p:ErrorSource xsi:nil='true' xsi:type='cim:cimString'/>
23
- <p:ErrorSourceFormat xsi:type='cim:cimUnsignedShort'>0</p:ErrorSourceFormat>
24
- <p:ErrorType xsi:type='cim:cimUnsignedShort'>0</p:ErrorType>
25
- <p:Message xsi:type='cim:cimString'>The WS-Management service cannot process the request. This user is allowed a maximum number of 30 concurrent shells, which has been exceeded. Close existing shells or raise the quota for this user. </p:Message>
26
- <p:MessageID xsi:type='cim:cimString'>HRESULT 0x803381a5</p:MessageID>
27
- <p:OtherErrorSourceFormat xsi:nil='true' xsi:type='cim:cimString'/>
28
- <p:OtherErrorType xsi:nil='true' xsi:type='cim:cimString'/>
29
- <p:OwningEntity xsi:nil='true' xsi:type='cim:cimString'/>
30
- <p:PerceivedSeverity xsi:type='cim:cimUnsignedShort'>0</p:PerceivedSeverity>
31
- <p:ProbableCause xsi:type='cim:cimUnsignedShort'>0</p:ProbableCause>
32
- <p:ProbableCauseDescription xsi:nil='true' xsi:type='cim:cimString'/>
33
- <p:error_Category xsi:type='cim:cimUnsignedInt'>30</p:error_Category>
34
- <p:error_Code xsi:type='cim:cimUnsignedInt'>2150859173</p:error_Code>
35
- <p:error_Type xsi:type='cim:cimString'>HRESULT</p:error_Type>
36
- <p:error_WindowsErrorMessage xsi:type='cim:cimString'>The WS-Management service cannot process the request. This user is allowed a maximum number of 30 concurrent shells, which has been exceeded. Close existing shells or raise the quota for this user. </p:error_WindowsErrorMessage>
37
- </p:MSFT_WmiError>
38
- </s:Detail>
39
- </s:Fault>
40
- </s:Body>
41
- </s:Envelope>
1
+ <s:Envelope xmlns:a='http://schemas.xmlsoap.org/ws/2004/08/addressing' xmlns:e='http://schemas.xmlsoap.org/ws/2004/08/eventing' xml:lang='en-US' xmlns:n='http://schemas.xmlsoap.org/ws/2004/09/enumeration' xmlns:p='http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd' xmlns:s='http://www.w3.org/2003/05/soap-envelope' xmlns:w='http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd' xmlns:x='http://schemas.xmlsoap.org/ws/2004/09/transfer'>
2
+ <s:Header>
3
+ <a:Action>http://schemas.dmtf.org/wbem/wsman/1/wsman/fault</a:Action>
4
+ <a:MessageID>uuid:B8829021-48C3-4F27-B94B-491DAC4F29B1</a:MessageID>
5
+ <a:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:To>
6
+ </s:Header>
7
+ <s:Body>
8
+ <s:Fault>
9
+ <s:Code>
10
+ <s:Value>s:Sender</s:Value>
11
+ <s:Subcode>
12
+ <s:Value>w:QuotaLimit</s:Value>
13
+ </s:Subcode>
14
+ </s:Code>
15
+ <s:Reason>
16
+ <s:Text xml:lang='en-US'>The WS-Management service cannot process the request. The maximum number of concurrent shells for this user has been exceeded. Close existing shells or raise the quota for this user. </s:Text>
17
+ </s:Reason>
18
+ <s:Detail>
19
+ <p:MSFT_WmiError b:IsCIM_Error='true' xmlns:b='http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd' xmlns:cim='http://schemas.dmtf.org/wbem/wscim/1/common' xmlns:p='http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/MSFT_WmiError' xsi:type='p:MSFT_WmiError_Type' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
20
+ <p:CIMStatusCode xsi:type='cim:cimUnsignedInt'>27</p:CIMStatusCode>
21
+ <p:CIMStatusCodeDescription xsi:nil='true' xsi:type='cim:cimString'/>
22
+ <p:ErrorSource xsi:nil='true' xsi:type='cim:cimString'/>
23
+ <p:ErrorSourceFormat xsi:type='cim:cimUnsignedShort'>0</p:ErrorSourceFormat>
24
+ <p:ErrorType xsi:type='cim:cimUnsignedShort'>0</p:ErrorType>
25
+ <p:Message xsi:type='cim:cimString'>The WS-Management service cannot process the request. This user is allowed a maximum number of 30 concurrent shells, which has been exceeded. Close existing shells or raise the quota for this user. </p:Message>
26
+ <p:MessageID xsi:type='cim:cimString'>HRESULT 0x803381a5</p:MessageID>
27
+ <p:OtherErrorSourceFormat xsi:nil='true' xsi:type='cim:cimString'/>
28
+ <p:OtherErrorType xsi:nil='true' xsi:type='cim:cimString'/>
29
+ <p:OwningEntity xsi:nil='true' xsi:type='cim:cimString'/>
30
+ <p:PerceivedSeverity xsi:type='cim:cimUnsignedShort'>0</p:PerceivedSeverity>
31
+ <p:ProbableCause xsi:type='cim:cimUnsignedShort'>0</p:ProbableCause>
32
+ <p:ProbableCauseDescription xsi:nil='true' xsi:type='cim:cimString'/>
33
+ <p:error_Category xsi:type='cim:cimUnsignedInt'>30</p:error_Category>
34
+ <p:error_Code xsi:type='cim:cimUnsignedInt'>2150859173</p:error_Code>
35
+ <p:error_Type xsi:type='cim:cimString'>HRESULT</p:error_Type>
36
+ <p:error_WindowsErrorMessage xsi:type='cim:cimString'>The WS-Management service cannot process the request. This user is allowed a maximum number of 30 concurrent shells, which has been exceeded. Close existing shells or raise the quota for this user. </p:error_WindowsErrorMessage>
37
+ </p:MSFT_WmiError>
38
+ </s:Detail>
39
+ </s:Fault>
40
+ </s:Body>
41
+ </s:Envelope>
@@ -0,0 +1,22 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'winrm/wsmv/cleanup_command'
4
+
5
+ describe WinRM::WSMV::CleanupCommand do
6
+ context 'default session options' do
7
+ let(:cmd_opts) do
8
+ {
9
+ shell_id: 'F4A2622B-B842-4EB8-8A78-0225C8A993DF',
10
+ command_id: 'A2A2622B-B842-4EB8-8A78-0225C8A993DF'
11
+ }
12
+ end
13
+ subject { described_class.new(default_connection_opts, cmd_opts) }
14
+ let(:xml) { subject.build }
15
+ it 'creates a well formed message' do
16
+ expect(xml).to include('<w:OperationTimeout>PT60S</w:OperationTimeout>')
17
+ expect(xml).to include('<rsp:Signal CommandId="A2A2622B-B842-4EB8-8A78-0225C8A993DF">' \
18
+ '<rsp:Code>http://schemas.microsoft.com/wbem/wsman/1/windows/shell/signal/terminate' \
19
+ '</rsp:Code></rsp:Signal>')
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'winrm/wsmv/close_shell'
4
+
5
+ describe WinRM::WSMV::CloseShell do
6
+ context 'default session options' do
7
+ subject do
8
+ described_class.new(default_connection_opts, shell_id: 'F4A2622B-B842-4EB8-8A78-0225C8A993DF')
9
+ end
10
+ let(:xml) { subject.build }
11
+ it 'creates a well formed message' do
12
+ expect(xml).to include('<w:OperationTimeout>PT60S</w:OperationTimeout>')
13
+ expect(xml).to include('<a:Action mustUnderstand="true">' \
14
+ 'http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete</a:Action>')
15
+ end
16
+ end
17
+ end
@@ -1,37 +1,37 @@
1
- # encoding: UTF-8
2
-
3
- require 'winrm/command_output_decoder'
4
-
5
- describe WinRM::CommandOutputDecoder, unit: true do
6
- let(:raw_output_with_bom) do
7
- '77u/' \
8
- 'ICAgQ29ubmVjdGlvbi1zcGVjaWZpYyBETlMgU3VmZml4ICAuIDogDQogICBMaW5rLWxvY2FsIElQdjYgQWRkcmVzcyA' \
9
- 'uIC4gLiAuIC4gOiBmZTgwOjo5MTFkOjE2OTQ6NTcwNDo1YjI5JTEyDQogICBJUHY0IEFkZHJlc3MuIC4gLiAuIC4gLi' \
10
- 'AuIC4gLiAuIC4gOiAxMC4wLjIuMTUNCiAgIFN1Ym5ldCBNYXNrIC4gLiAuIC4gLiAuIC4gLiAuIC4gLiA6IDI1NS4yN' \
11
- 'TUuMjU1LjANCiAgIERlZmF1bHQgR2F0ZXdheSAuIC4gLiAuIC4gLiAuIC4gLiA6IDEwLjAuMi4yDQoNClR1bm5lbCBh' \
12
- 'ZGFwdGVyIGlzYXRhcC57RjBENTY2RDgtNzlCMS00QUYwLUJENUQtMkM5RkVEOEI3MTE3fToNCg0KICAgTWVkaWEgU3R' \
13
- 'hdGUgLiAuIC4gLiAuIC4gLiAuIC4gLiAuIDogTWVkaWEgZGlzY29ubmVjdGVkDQogICBDb25uZWN0aW9uLXNwZWNpZm' \
14
- 'ljIEROUyBTdWZmaXggIC4gOiANCg0KVHVubmVsIGFkYXB0ZXIgVGVyZWRvIFR1bm5lbGluZyBQc2V1ZG8tSW50ZXJmY' \
15
- 'WNlOg0KDQogICBDb25uZWN0aW9uLXNwZWNpZmljIEROUyBTdWZmaXggIC4gOiANCiAgIElQdjYgQWRkcmVzcy4gLiAu' \
16
- 'IC4gLiAuIC4gLiAuIC4gLiA6IDIwMDE6MDo5ZDM4OjZhYmQ6NGJiOjI4YjU6ZjVmZjpmZGYwDQogICBMaW5rLWxvY2F' \
17
- 'sIElQdjYgQWRkcmVzcyAuIC4gLiAuIC4gOiBmZTgwOjo0YmI6MjhiNTpmNWZmOmZkZjAlMTQNCiAgIERlZmF1bHQgR2' \
18
- 'F0ZXdheSAuIC4gLiAuIC4gLiAuIC4gLiA6IDo6DQo='
19
- end
20
- let(:expected) do
21
- " Connection-specific DNS Suffix . : \r\n Link-local IPv6 Address . . . . . : fe80::911" \
22
- "d:1694:5704:5b29%12\r\n IPv4 Address. . . . . . . . . . . : 10.0.2.15\r\n Subnet Mask ." \
23
- " . . . . . . . . . . : 255.255.255.0\r\n Default Gateway . . . . . . . . . : 10.0.2.2\r\n" \
24
- "\r\nTunnel adapter isatap.{F0D566D8-79B1-4AF0-BD5D-2C9FED8B7117}:\r\n\r\n Media State . ." \
25
- " . . . . . . . . . : Media disconnected\r\n Connection-specific DNS Suffix . : \r\n\r\nT" \
26
- "unnel adapter Teredo Tunneling Pseudo-Interface:\r\n\r\n Connection-specific DNS Suffix " \
27
- ". : \r\n IPv6 Address. . . . . . . . . . . : 2001:0:9d38:6abd:4bb:28b5:f5ff:fdf0\r\n Li" \
28
- "nk-local IPv6 Address . . . . . : fe80::4bb:28b5:f5ff:fdf0%14\r\n Default Gateway . . . ." \
29
- " . . . . . : ::\r\n"
30
- end
31
- subject { described_class.new }
32
- context 'valid UTF-8 raw output' do
33
- it 'decodes' do
34
- expect(subject.decode(raw_output_with_bom)).to eq(expected)
35
- end
36
- end
37
- end
1
+ # encoding: UTF-8
2
+
3
+ require 'winrm/wsmv/command_output_decoder'
4
+
5
+ describe WinRM::WSMV::CommandOutputDecoder do
6
+ let(:raw_output_with_bom) do
7
+ '77u/' \
8
+ 'ICAgQ29ubmVjdGlvbi1zcGVjaWZpYyBETlMgU3VmZml4ICAuIDogDQogICBMaW5rLWxvY2FsIElQdjYgQWRkcmVzcyA' \
9
+ 'uIC4gLiAuIC4gOiBmZTgwOjo5MTFkOjE2OTQ6NTcwNDo1YjI5JTEyDQogICBJUHY0IEFkZHJlc3MuIC4gLiAuIC4gLi' \
10
+ 'AuIC4gLiAuIC4gOiAxMC4wLjIuMTUNCiAgIFN1Ym5ldCBNYXNrIC4gLiAuIC4gLiAuIC4gLiAuIC4gLiA6IDI1NS4yN' \
11
+ 'TUuMjU1LjANCiAgIERlZmF1bHQgR2F0ZXdheSAuIC4gLiAuIC4gLiAuIC4gLiA6IDEwLjAuMi4yDQoNClR1bm5lbCBh' \
12
+ 'ZGFwdGVyIGlzYXRhcC57RjBENTY2RDgtNzlCMS00QUYwLUJENUQtMkM5RkVEOEI3MTE3fToNCg0KICAgTWVkaWEgU3R' \
13
+ 'hdGUgLiAuIC4gLiAuIC4gLiAuIC4gLiAuIDogTWVkaWEgZGlzY29ubmVjdGVkDQogICBDb25uZWN0aW9uLXNwZWNpZm' \
14
+ 'ljIEROUyBTdWZmaXggIC4gOiANCg0KVHVubmVsIGFkYXB0ZXIgVGVyZWRvIFR1bm5lbGluZyBQc2V1ZG8tSW50ZXJmY' \
15
+ 'WNlOg0KDQogICBDb25uZWN0aW9uLXNwZWNpZmljIEROUyBTdWZmaXggIC4gOiANCiAgIElQdjYgQWRkcmVzcy4gLiAu' \
16
+ 'IC4gLiAuIC4gLiAuIC4gLiA6IDIwMDE6MDo5ZDM4OjZhYmQ6NGJiOjI4YjU6ZjVmZjpmZGYwDQogICBMaW5rLWxvY2F' \
17
+ 'sIElQdjYgQWRkcmVzcyAuIC4gLiAuIC4gOiBmZTgwOjo0YmI6MjhiNTpmNWZmOmZkZjAlMTQNCiAgIERlZmF1bHQgR2' \
18
+ 'F0ZXdheSAuIC4gLiAuIC4gLiAuIC4gLiA6IDo6DQo='
19
+ end
20
+ let(:expected) do
21
+ " Connection-specific DNS Suffix . : \r\n Link-local IPv6 Address . . . . . : fe80::911" \
22
+ "d:1694:5704:5b29%12\r\n IPv4 Address. . . . . . . . . . . : 10.0.2.15\r\n Subnet Mask ." \
23
+ " . . . . . . . . . . : 255.255.255.0\r\n Default Gateway . . . . . . . . . : 10.0.2.2\r\n" \
24
+ "\r\nTunnel adapter isatap.{F0D566D8-79B1-4AF0-BD5D-2C9FED8B7117}:\r\n\r\n Media State . ." \
25
+ " . . . . . . . . . : Media disconnected\r\n Connection-specific DNS Suffix . : \r\n\r\nT" \
26
+ "unnel adapter Teredo Tunneling Pseudo-Interface:\r\n\r\n Connection-specific DNS Suffix " \
27
+ ". : \r\n IPv6 Address. . . . . . . . . . . : 2001:0:9d38:6abd:4bb:28b5:f5ff:fdf0\r\n Li" \
28
+ "nk-local IPv6 Address . . . . . : fe80::4bb:28b5:f5ff:fdf0%14\r\n Default Gateway . . . ." \
29
+ " . . . . . : ::\r\n"
30
+ end
31
+ subject { described_class.new }
32
+ context 'valid UTF-8 raw output' do
33
+ it 'decodes' do
34
+ expect(subject.decode(raw_output_with_bom)).to eq(expected)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,45 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'winrm/wsmv/command_output'
4
+ require 'winrm/wsmv/header'
5
+
6
+ describe WinRM::WSMV::CommandOutput do
7
+ context 'default session options' do
8
+ let(:cmd_out_opts) do
9
+ {
10
+ shell_id: 'F4A2622B-B842-4EB8-8A78-0225C8A993DF',
11
+ command_id: 'A2A2622B-B842-4EB8-8A78-0225C8A993DF'
12
+ }
13
+ end
14
+ subject { described_class.new(default_connection_opts, cmd_out_opts) }
15
+ let(:xml) { subject.build }
16
+ it 'creates a well formed message' do
17
+ expect(xml).to include('<w:OperationTimeout>PT60S</w:OperationTimeout>')
18
+ expect(xml).to include('<w:Option Name="WSMAN_CMDSHELL_OPTION_KEEPALIVE">TRUE</w:Option>')
19
+ expect(xml).to include('w:ResourceURI mustUnderstand="true">' \
20
+ 'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd</w:ResourceURI>')
21
+ expect(xml).to include('<rsp:DesiredStream ' \
22
+ 'CommandId="A2A2622B-B842-4EB8-8A78-0225C8A993DF">stdout stderr</rsp:DesiredStream>')
23
+ end
24
+ end
25
+ context 'powershell' do
26
+ let(:cmd_out_opts) do
27
+ {
28
+ shell_id: 'F4A2622B-B842-4EB8-8A78-0225C8A993DF',
29
+ command_id: 'A2A2622B-B842-4EB8-8A78-0225C8A993DF',
30
+ shell_uri: WinRM::WSMV::Header::RESOURCE_URI_POWERSHELL,
31
+ out_streams: %w(stdout)
32
+ }
33
+ end
34
+ subject { described_class.new(default_connection_opts, cmd_out_opts) }
35
+ let(:xml) { subject.build }
36
+ it 'creates a well formed message' do
37
+ expect(xml).to include('<w:OperationTimeout>PT60S</w:OperationTimeout>')
38
+ expect(xml).to include('<w:Option Name="WSMAN_CMDSHELL_OPTION_KEEPALIVE">TRUE</w:Option>')
39
+ expect(xml).to include('w:ResourceURI mustUnderstand="true">' \
40
+ 'http://schemas.microsoft.com/powershell/Microsoft.PowerShell</w:ResourceURI>')
41
+ expect(xml).to include('<rsp:DesiredStream ' \
42
+ 'CommandId="A2A2622B-B842-4EB8-8A78-0225C8A993DF">stdout</rsp:DesiredStream>')
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'winrm/wsmv/command'
4
+
5
+ describe WinRM::WSMV::Command do
6
+ context 'default session options' do
7
+ let(:cmd_opts) do
8
+ {
9
+ shell_id: 'D5A2622B-B842-4EB8-8A78-0225C8A993DF',
10
+ command: 'ipconfig'
11
+ }
12
+ end
13
+ subject { described_class.new(default_connection_opts, cmd_opts) }
14
+ let(:xml) { subject.build }
15
+ it 'creates a well formed message' do
16
+ expect(xml).to include('<w:OperationTimeout>PT60S</w:OperationTimeout>')
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'winrm/wsmv/configuration'
4
+
5
+ describe WinRM::WSMV::Configuration do
6
+ subject do
7
+ described_class.new(default_connection_opts)
8
+ end
9
+ let(:xml) { subject.build }
10
+ it 'creates a well formed message' do
11
+ expect(xml).to include('<w:OperationTimeout>PT60S</w:OperationTimeout>')
12
+ expect(xml).to include('<a:Action mustUnderstand="true">' \
13
+ 'http://schemas.xmlsoap.org/ws/2004/09/transfer/Get</a:Action>')
14
+ expect(xml).to include('w:ResourceURI mustUnderstand="true">' \
15
+ 'http://schemas.microsoft.com/wbem/wsman/1/config</w:ResourceURI>')
16
+ end
17
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'winrm/wsmv/create_pipeline'
4
+
5
+ describe WinRM::WSMV::CreatePipeline do
6
+ context 'default session options' do
7
+ let(:shell_id) { 'D5A2622B-B842-4EB8-8A78-0225C8A993DF' }
8
+ let(:command_id) { 'D5A2622B-B842-4EB8-8A78-0225C8A993DF' }
9
+ let(:fragment) { WinRM::PSRP::Fragment.new(0, [1, 2, 3]) }
10
+ let(:pipeline) { Base64.strict_encode64(fragment.bytes.pack('C*')) }
11
+
12
+ subject do
13
+ WinRM::WSMV::CreatePipeline.new(
14
+ default_connection_opts,
15
+ shell_id,
16
+ command_id,
17
+ fragment
18
+ )
19
+ end
20
+ let(:xml) { subject.build }
21
+ it 'creates a well formed message' do
22
+ expect(xml).to include('<w:OperationTimeout>PT60S</w:OperationTimeout>')
23
+ expect(xml).to include(
24
+ '<w:SelectorSet><w:Selector Name="ShellId">' \
25
+ "#{shell_id}</w:Selector></w:SelectorSet>")
26
+ expect(xml).to include("<rsp:CommandLine CommandId=\"#{command_id}\">")
27
+ expect(xml).to include('<rsp:Command>Invoke-Expression</rsp:Command>')
28
+ expect(xml).to include("<rsp:Arguments>#{pipeline}</rsp:Arguments>")
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,38 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'winrm/wsmv/create_shell'
4
+
5
+ describe WinRM::WSMV::CreateShell do
6
+ context 'default session options' do
7
+ subject { described_class.new(default_connection_opts) }
8
+ let(:xml) { subject.build }
9
+ it 'creates a well formed message' do
10
+ expect(xml).to include('<w:OperationTimeout>PT60S</w:OperationTimeout>')
11
+ expect(xml).to include('<w:Locale xml:lang="en-US" mustUnderstand="false"/>')
12
+ expect(xml).to include('<p:DataLocale xml:lang="en-US" mustUnderstand="false"/>')
13
+ expect(xml).to include(
14
+ '<p:SessionId mustUnderstand="false">' \
15
+ 'uuid:05A2622B-B842-4EB8-8A78-0225C8A993DF</p:SessionId>')
16
+ expect(xml).to include('<w:MaxEnvelopeSize mustUnderstand="true">153600</w:MaxEnvelopeSize>')
17
+ expect(xml).to include('<a:To>http://localhost:5985/wsman</a:To>')
18
+ expect(xml).to include('<rsp:InputStreams>stdin</rsp:InputStreams>')
19
+ expect(xml).to include('<rsp:OutputStreams>stdout stderr</rsp:OutputStreams>')
20
+ expect(xml).to include(
21
+ '<w:ResourceURI mustUnderstand="true">' \
22
+ 'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd</w:ResourceURI>')
23
+ end
24
+ context 'shell options w/env vars' do
25
+ let(:shell_opts) do
26
+ {
27
+ env_vars: { 'FOO' => 'BAR' }
28
+ }
29
+ end
30
+ subject { described_class.new(default_connection_opts, shell_opts) }
31
+ let(:xml) { subject.build }
32
+ it 'includes environemt vars' do
33
+ expect(xml).to include(
34
+ '<rsp:Environment><rsp:Variable Name="FOO">BAR</rsp:Variable></rsp:Environment>')
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,36 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'winrm/wsmv/init_runspace_pool'
4
+
5
+ describe WinRM::WSMV::InitRunspacePool do
6
+ context 'default session options' do
7
+ let(:shell_id) { SecureRandom.uuid.to_s.upcase }
8
+ let(:payload) { 'blah'.bytes }
9
+
10
+ subject { described_class.new(default_connection_opts, shell_id, payload) }
11
+
12
+ it 'creates a well formed message' do
13
+ xml = subject.build
14
+ expect(xml).to include('<w:OperationTimeout>PT60S</w:OperationTimeout>')
15
+ expect(xml).to include('<w:Locale xml:lang="en-US" mustUnderstand="false"/>')
16
+ expect(xml).to include('<p:DataLocale xml:lang="en-US" mustUnderstand="false"/>')
17
+ expect(xml).to include(
18
+ '<p:SessionId mustUnderstand="false">' \
19
+ 'uuid:05A2622B-B842-4EB8-8A78-0225C8A993DF</p:SessionId>')
20
+ expect(xml).to include('<w:MaxEnvelopeSize mustUnderstand="true">153600</w:MaxEnvelopeSize>')
21
+ expect(xml).to include('<a:To>http://localhost:5985/wsman</a:To>')
22
+ expect(xml).to include(
23
+ '<w:OptionSet env:mustUnderstand="true">' \
24
+ '<w:Option Name="protocolversion" MustComply="true">2.3</w:Option></w:OptionSet>')
25
+ expect(xml).to include('<rsp:InputStreams>stdin pr</rsp:InputStreams>')
26
+ expect(xml).to include('<rsp:OutputStreams>stdout</rsp:OutputStreams>')
27
+ expect(xml).to include("<rsp:Shell ShellId=\"#{subject.shell_id}\">")
28
+ expect(xml).to include(
29
+ '<w:ResourceURI mustUnderstand="true">' \
30
+ 'http://schemas.microsoft.com/powershell/Microsoft.PowerShell')
31
+ expect(xml).to include(
32
+ '<creationXml xmlns="http://schemas.microsoft.com/powershell">' \
33
+ "#{Base64.strict_encode64(payload.pack('C*'))}</creationXml>")
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'winrm/wsmv/keep_alive'
4
+
5
+ describe WinRM::WSMV::KeepAlive do
6
+ context 'default session options' do
7
+ let(:shell_id) { 'F4A2622B-B842-4EB8-8A78-0225C8A993DF' }
8
+ subject { described_class.new(default_connection_opts, shell_id) }
9
+ let(:xml) { subject.build }
10
+ it 'creates a well formed message' do
11
+ expect(xml).to include('<w:OperationTimeout>PT60S</w:OperationTimeout>')
12
+ expect(xml).to include(
13
+ '<w:OptionSet><w:Option Name="WSMAN_CMDSHELL_OPTION_KEEPALIVE">' \
14
+ 'TRUE</w:Option></w:OptionSet>')
15
+ expect(xml).to include(
16
+ '<w:SelectorSet><w:Selector Name="ShellId">' \
17
+ "#{shell_id}</w:Selector></w:SelectorSet>")
18
+ expect(xml).to include('<rsp:DesiredStream>stdout</rsp:DesiredStream>')
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,123 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'winrm/wsmv/receive_response_reader'
4
+
5
+ describe WinRM::WSMV::ReceiveResponseReader do
6
+ let(:shell_id) { 'F4A2622B-B842-4EB8-8A78-0225C8A993DF' }
7
+ let(:command_id) { 'A2A2622B-B842-4EB8-8A78-0225C8A993DF' }
8
+ let(:output_message) { double('output_message', build: 'output_message') }
9
+ let(:test_data_xml_template) do
10
+ ERB.new(stubbed_response('get_command_output_response.xml.erb'))
11
+ end
12
+ let(:test_data_xml_template_not_done) do
13
+ ERB.new(stubbed_response('get_command_output_response_not_done.xml.erb'))
14
+ end
15
+ let(:transport) do
16
+ {}
17
+ end
18
+
19
+ subject do
20
+ described_class.new(
21
+ transport,
22
+ Logging.logger['test']
23
+ )
24
+ end
25
+
26
+ describe '#read_output' do
27
+ context 'response doc stdout with invalid UTF-8 characters, issue 184' do
28
+ let(:test_data_stdout) { 'ffff' } # Base64-decodes to '}\xF7\xDF', an invalid sequence
29
+ let(:test_data_stderr) { '' }
30
+ let(:test_data_xml) { test_data_xml_template.result(binding) }
31
+
32
+ before do
33
+ allow(transport).to receive(:send_request).and_return(
34
+ REXML::Document.new(test_data_xml)
35
+ )
36
+ end
37
+
38
+ it 'does not raise an ArgumentError: invalid byte sequence in UTF-8' do
39
+ begin
40
+ expect(
41
+ subject.read_output(output_message)
42
+ ).not_to raise_error
43
+ rescue RSpec::Expectations::ExpectationNotMetError => e
44
+ expect(e.message).not_to include 'ArgumentError'
45
+ end
46
+ end
47
+
48
+ it 'does not have an empty stdout' do
49
+ expect(
50
+ subject.read_output(output_message).stdout
51
+ ).not_to be_empty
52
+ end
53
+ end
54
+
55
+ context 'response doc stdout with valid UTF-8' do
56
+ let(:test_data_raw) { '✓1234-äöü' }
57
+ let(:test_data_stdout) { Base64.encode64(test_data_raw) }
58
+ let(:test_data_stderr) { '' }
59
+ let(:test_data_xml) { test_data_xml_template.result(binding) }
60
+
61
+ before do
62
+ allow(transport).to receive(:send_request).and_return(
63
+ REXML::Document.new(test_data_xml)
64
+ )
65
+ end
66
+
67
+ it 'decodes to match input data' do
68
+ expect(
69
+ subject.read_output(output_message).stdout
70
+ ).to eq(test_data_raw)
71
+ end
72
+ end
73
+ end
74
+
75
+ describe '#read_response' do
76
+ context 'do not wait for done state' do
77
+ let(:test_data_raw) { 'output text' }
78
+ let(:test_error_raw) { 'error text' }
79
+ let(:test_data_stdout) { Base64.encode64(test_data_raw) }
80
+ let(:test_data_stderr) { Base64.encode64(test_error_raw) }
81
+ let(:test_data_xml) { test_data_xml_template.result(binding) }
82
+
83
+ before do
84
+ allow(transport).to receive(:send_request).and_return(
85
+ REXML::Document.new(test_data_xml)
86
+ ).once
87
+ end
88
+
89
+ it 'yields stream and document' do
90
+ subject.read_response(output_message) do |stream, doc|
91
+ expect(stream[:text]).to eq(test_data_stdout) if stream[:type] == :stdout
92
+ expect(stream[:text]).to eq(test_data_stderr) if stream[:type] == :stderr
93
+ expect(doc.to_s).to eq(REXML::Document.new(test_data_xml).to_s)
94
+ end
95
+ end
96
+ end
97
+
98
+ context 'wait for done state' do
99
+ let(:test_data_raw) { 'output text' }
100
+ let(:test_error_raw) { 'error text' }
101
+ let(:test_data_stdout) { Base64.encode64(test_data_raw) }
102
+ let(:test_data_stderr) { Base64.encode64(test_error_raw) }
103
+ let(:test_data_xml_not_done) { test_data_xml_template_not_done.result(binding) }
104
+ let(:test_data_xml_done) { test_data_xml_template.result(binding) }
105
+
106
+ it 'yields streams and both documents' do
107
+ allow(transport).to receive(:send_request).and_return(
108
+ REXML::Document.new(test_data_xml_not_done),
109
+ REXML::Document.new(test_data_xml_done)
110
+ )
111
+ times = 1
112
+
113
+ subject.read_response(output_message, true) do |stream, doc|
114
+ expect(stream[:text]).to eq(test_data_stdout) if stream[:type] == :stdout
115
+ expect(stream[:text]).to eq(test_data_stderr) if stream[:type] == :stderr
116
+ expect(doc.to_s).to eq(REXML::Document.new(test_data_xml_not_done).to_s) if times == 1
117
+ expect(doc.to_s).to eq(REXML::Document.new(test_data_xml_done).to_s) if times > 2
118
+ times += 1
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end