winrm 2.0.3 → 2.1.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 (127) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +10 -10
  3. data/.rubocop.yml +26 -26
  4. data/.travis.yml +11 -11
  5. data/Gemfile +3 -3
  6. data/README.md +260 -233
  7. data/Rakefile +34 -34
  8. data/Vagrantfile +6 -6
  9. data/WinrmAppveyor.psm1 +31 -31
  10. data/appveyor.yml +51 -51
  11. data/changelog.md +104 -101
  12. data/lib/winrm.rb +39 -39
  13. data/lib/winrm/connection.rb +83 -82
  14. data/lib/winrm/connection_opts.rb +91 -91
  15. data/lib/winrm/exceptions.rb +76 -76
  16. data/lib/winrm/http/response_handler.rb +96 -96
  17. data/lib/winrm/http/transport.rb +424 -424
  18. data/lib/winrm/http/transport_factory.rb +68 -68
  19. data/lib/winrm/output.rb +59 -59
  20. data/lib/winrm/psrp/create_pipeline.xml.erb +167 -167
  21. data/lib/winrm/psrp/fragment.rb +70 -70
  22. data/lib/winrm/psrp/init_runspace_pool.xml.erb +224 -224
  23. data/lib/winrm/psrp/message.rb +130 -130
  24. data/lib/winrm/psrp/message_data.rb +42 -42
  25. data/lib/winrm/psrp/message_data/base.rb +49 -49
  26. data/lib/winrm/psrp/message_data/error_record.rb +68 -68
  27. data/lib/winrm/psrp/message_data/pipeline_host_call.rb +32 -32
  28. data/lib/winrm/psrp/message_data/pipeline_output.rb +49 -49
  29. data/lib/winrm/psrp/message_data/pipeline_state.rb +40 -40
  30. data/lib/winrm/psrp/message_data/runspacepool_host_call.rb +32 -32
  31. data/lib/winrm/psrp/message_data/runspacepool_state.rb +39 -39
  32. data/lib/winrm/psrp/message_data/session_capability.rb +36 -36
  33. data/lib/winrm/psrp/message_defragmenter.rb +62 -62
  34. data/lib/winrm/psrp/message_factory.rb +75 -75
  35. data/lib/winrm/psrp/message_fragmenter.rb +60 -60
  36. data/lib/winrm/psrp/powershell_output_decoder.rb +139 -139
  37. data/lib/winrm/psrp/receive_response_reader.rb +97 -97
  38. data/lib/winrm/psrp/session_capability.xml.erb +7 -7
  39. data/lib/winrm/psrp/uuid.rb +40 -40
  40. data/lib/winrm/shells/base.rb +180 -175
  41. data/lib/winrm/shells/cmd.rb +65 -65
  42. data/lib/winrm/shells/power_shell.rb +202 -202
  43. data/lib/winrm/shells/retryable.rb +45 -45
  44. data/lib/winrm/shells/shell_factory.rb +58 -50
  45. data/lib/winrm/version.rb +7 -7
  46. data/lib/winrm/wsmv/base.rb +59 -59
  47. data/lib/winrm/wsmv/cleanup_command.rb +61 -61
  48. data/lib/winrm/wsmv/close_shell.rb +50 -50
  49. data/lib/winrm/wsmv/command.rb +101 -101
  50. data/lib/winrm/wsmv/command_output.rb +76 -76
  51. data/lib/winrm/wsmv/command_output_decoder.rb +55 -55
  52. data/lib/winrm/wsmv/configuration.rb +46 -46
  53. data/lib/winrm/wsmv/create_pipeline.rb +66 -66
  54. data/lib/winrm/wsmv/create_shell.rb +119 -119
  55. data/lib/winrm/wsmv/header.rb +203 -203
  56. data/lib/winrm/wsmv/init_runspace_pool.rb +95 -95
  57. data/lib/winrm/wsmv/iso8601_duration.rb +60 -60
  58. data/lib/winrm/wsmv/keep_alive.rb +68 -68
  59. data/lib/winrm/wsmv/receive_response_reader.rb +126 -126
  60. data/lib/winrm/wsmv/send_data.rb +68 -68
  61. data/lib/winrm/wsmv/soap.rb +51 -51
  62. data/lib/winrm/wsmv/wql_query.rb +79 -79
  63. data/lib/winrm/wsmv/write_stdin.rb +88 -88
  64. data/tests/integration/auth_timeout_spec.rb +18 -18
  65. data/tests/integration/cmd_spec.rb +131 -110
  66. data/tests/integration/config-example.yml +16 -16
  67. data/tests/integration/issue_59_spec.rb +26 -26
  68. data/tests/integration/powershell_spec.rb +165 -165
  69. data/tests/integration/spec_helper.rb +65 -65
  70. data/tests/integration/transport_spec.rb +99 -99
  71. data/tests/integration/wql_spec.rb +16 -16
  72. data/tests/matchers.rb +60 -60
  73. data/tests/spec/configuration_spec.rb +184 -184
  74. data/tests/spec/connection_spec.rb +39 -39
  75. data/tests/spec/exception_spec.rb +50 -50
  76. data/tests/spec/http/transport_factory_spec.rb +68 -68
  77. data/tests/spec/http/transport_spec.rb +44 -44
  78. data/tests/spec/output_spec.rb +127 -127
  79. data/tests/spec/psrp/fragment_spec.rb +62 -62
  80. data/tests/spec/psrp/message_data/base_spec.rb +13 -13
  81. data/tests/spec/psrp/message_data/error_record_spec.rb +41 -41
  82. data/tests/spec/psrp/message_data/pipeline_host_call_spec.rb +25 -25
  83. data/tests/spec/psrp/message_data/pipeline_output_spec.rb +32 -32
  84. data/tests/spec/psrp/message_data/pipeline_state_spec.rb +40 -40
  85. data/tests/spec/psrp/message_data/runspace_pool_host_call_spec.rb +25 -25
  86. data/tests/spec/psrp/message_data/runspacepool_state_spec.rb +16 -16
  87. data/tests/spec/psrp/message_data/session_capability_spec.rb +30 -30
  88. data/tests/spec/psrp/message_data_spec.rb +35 -35
  89. data/tests/spec/psrp/message_defragmenter_spec.rb +47 -47
  90. data/tests/spec/psrp/message_fragmenter_spec.rb +105 -105
  91. data/tests/spec/psrp/powershell_output_decoder_spec.rb +100 -100
  92. data/tests/spec/psrp/psrp_message_spec.rb +70 -70
  93. data/tests/spec/psrp/recieve_response_reader_spec.rb +172 -172
  94. data/tests/spec/psrp/uuid_spec.rb +28 -28
  95. data/tests/spec/response_handler_spec.rb +61 -61
  96. data/tests/spec/shells/base_spec.rb +202 -202
  97. data/tests/spec/shells/cmd_spec.rb +75 -75
  98. data/tests/spec/shells/powershell_spec.rb +175 -175
  99. data/tests/spec/spec_helper.rb +47 -47
  100. data/tests/spec/stubs/clixml/error_record.xml.erb +84 -84
  101. data/tests/spec/stubs/clixml/pipeline_state.xml.erb +88 -88
  102. data/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 -10
  104. data/tests/spec/stubs/responses/get_powershell_keepalive_response.xml.erb +10 -10
  105. data/tests/spec/stubs/responses/get_powershell_output_response.xml.erb +12 -12
  106. data/tests/spec/stubs/responses/get_powershell_output_response_not_done.xml.erb +9 -9
  107. data/tests/spec/stubs/responses/open_shell_v1.xml +19 -19
  108. data/tests/spec/stubs/responses/open_shell_v2.xml +20 -20
  109. data/tests/spec/stubs/responses/soap_fault_v1.xml +36 -36
  110. data/tests/spec/stubs/responses/soap_fault_v2.xml +42 -42
  111. data/tests/spec/stubs/responses/wmi_error_v2.xml +41 -41
  112. data/tests/spec/wsmv/cleanup_command_spec.rb +22 -22
  113. data/tests/spec/wsmv/close_shell_spec.rb +17 -17
  114. data/tests/spec/wsmv/command_output_decoder_spec.rb +37 -37
  115. data/tests/spec/wsmv/command_output_spec.rb +45 -45
  116. data/tests/spec/wsmv/command_spec.rb +19 -19
  117. data/tests/spec/wsmv/configuration_spec.rb +17 -17
  118. data/tests/spec/wsmv/create_pipeline_spec.rb +31 -31
  119. data/tests/spec/wsmv/create_shell_spec.rb +38 -38
  120. data/tests/spec/wsmv/init_runspace_pool_spec.rb +36 -36
  121. data/tests/spec/wsmv/keep_alive_spec.rb +21 -21
  122. data/tests/spec/wsmv/receive_response_reader_spec.rb +123 -123
  123. data/tests/spec/wsmv/send_data_spec.rb +30 -30
  124. data/tests/spec/wsmv/wql_query_spec.rb +13 -13
  125. data/tests/spec/wsmv/write_stdin_spec.rb +22 -22
  126. data/winrm.gemspec +42 -42
  127. metadata +2 -2
@@ -1,62 +1,62 @@
1
- # encoding: UTF-8
2
- #
3
- # Copyright 2016 Matt Wrock <matt@mattwrock.com>
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the 'License');
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an 'AS IS' BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
-
17
- require_relative 'fragment'
18
-
19
- module WinRM
20
- # PowerShell Remoting Protcol module
21
- module PSRP
22
- # PowerShell Remoting Protocol message fragmenter.
23
- class MessageDefragmenter
24
- def initialize
25
- @messages = {}
26
- end
27
-
28
- def defragment(base64_bytes)
29
- fragment = fragment_from(Base64.decode64(base64_bytes))
30
-
31
- @messages[fragment.object_id] ||= []
32
- @messages[fragment.object_id].push fragment
33
-
34
- if fragment.end_fragment
35
- blob = []
36
- @messages.delete(fragment.object_id).each { |frag| blob += frag.blob }
37
- return message_from(blob.pack('C*'))
38
- end
39
- end
40
-
41
- def fragment_from(byte_string)
42
- Fragment.new(
43
- byte_string[0..7].reverse.unpack('Q')[0],
44
- byte_string[21..-1].bytes,
45
- byte_string[8..15].reverse.unpack('Q')[0],
46
- byte_string[16].unpack('C')[0][0] == 1,
47
- byte_string[16].unpack('C')[0][1] == 1
48
- )
49
- end
50
-
51
- def message_from(byte_string)
52
- Message.new(
53
- '00000000-0000-0000-0000-000000000000',
54
- byte_string[4..7].unpack('V')[0],
55
- byte_string[40..-1],
56
- '00000000-0000-0000-0000-000000000000',
57
- byte_string[0..3].unpack('V')[0]
58
- )
59
- end
60
- end
61
- end
62
- end
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright 2016 Matt Wrock <matt@mattwrock.com>
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the 'License');
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an 'AS IS' BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require_relative 'fragment'
18
+
19
+ module WinRM
20
+ # PowerShell Remoting Protcol module
21
+ module PSRP
22
+ # PowerShell Remoting Protocol message fragmenter.
23
+ class MessageDefragmenter
24
+ def initialize
25
+ @messages = {}
26
+ end
27
+
28
+ def defragment(base64_bytes)
29
+ fragment = fragment_from(Base64.decode64(base64_bytes))
30
+
31
+ @messages[fragment.object_id] ||= []
32
+ @messages[fragment.object_id].push fragment
33
+
34
+ if fragment.end_fragment
35
+ blob = []
36
+ @messages.delete(fragment.object_id).each { |frag| blob += frag.blob }
37
+ return message_from(blob.pack('C*'))
38
+ end
39
+ end
40
+
41
+ def fragment_from(byte_string)
42
+ Fragment.new(
43
+ byte_string[0..7].reverse.unpack('Q')[0],
44
+ byte_string[21..-1].bytes,
45
+ byte_string[8..15].reverse.unpack('Q')[0],
46
+ byte_string[16].unpack('C')[0][0] == 1,
47
+ byte_string[16].unpack('C')[0][1] == 1
48
+ )
49
+ end
50
+
51
+ def message_from(byte_string)
52
+ Message.new(
53
+ '00000000-0000-0000-0000-000000000000',
54
+ byte_string[4..7].unpack('V')[0],
55
+ byte_string[40..-1],
56
+ '00000000-0000-0000-0000-000000000000',
57
+ byte_string[0..3].unpack('V')[0]
58
+ )
59
+ end
60
+ end
61
+ end
62
+ end
@@ -1,75 +1,75 @@
1
- # encoding: UTF-8
2
- #
3
- # Copyright 2016 Shawn Neal <sneal@sneal.net>
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
-
17
- require 'erubis'
18
- require_relative 'message'
19
-
20
- module WinRM
21
- module PSRP
22
- # Creates WinRM::PSRP::Message instances for various PSRP messages
23
- class MessageFactory
24
- class << self
25
- # Creates a new session capability PSRP message.
26
- # @param runspace_pool_id [String] The UUID of the remote shell/runspace pool.
27
- def session_capability_message(runspace_pool_id)
28
- Message.new(
29
- runspace_pool_id,
30
- Message::MESSAGE_TYPES[:session_capability],
31
- render('session_capability')
32
- )
33
- end
34
-
35
- # Creates a new init runspace pool PSRP message.
36
- # @param runspace_pool_id [String] The UUID of the remote shell/runspace pool.
37
- def init_runspace_pool_message(runspace_pool_id)
38
- Message.new(
39
- runspace_pool_id,
40
- Message::MESSAGE_TYPES[:init_runspacepool],
41
- render('init_runspace_pool')
42
- )
43
- end
44
-
45
- # Creates a new PSRP message that creates pipline to execute a command.
46
- # @param runspace_pool_id [String] The UUID of the remote shell/runspace pool.
47
- # @param pipeline_id [String] The UUID to correlate the command/pipeline
48
- # response.
49
- # @param command [String] The command passed to Invoke-Expression.
50
- def create_pipeline_message(runspace_pool_id, pipeline_id, command)
51
- Message.new(
52
- runspace_pool_id,
53
- Message::MESSAGE_TYPES[:create_pipeline],
54
- render('create_pipeline', command: command.encode(xml: :text)),
55
- pipeline_id
56
- )
57
- end
58
-
59
- private
60
-
61
- # Renders the specified template with the given context
62
- # @param template [String] The base filename of the PSRP message template.
63
- # @param context [Hash] Any options required for rendering the template.
64
- # @return [String] The rendered XML PSRP message.
65
- # @api private
66
- def render(template, context = nil)
67
- template_path = File.expand_path(
68
- "#{File.dirname(__FILE__)}/#{template}.xml.erb")
69
- template = File.read(template_path)
70
- Erubis::Eruby.new(template).result(context)
71
- end
72
- end
73
- end
74
- end
75
- end
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright 2016 Shawn Neal <sneal@sneal.net>
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'erubis'
18
+ require_relative 'message'
19
+
20
+ module WinRM
21
+ module PSRP
22
+ # Creates WinRM::PSRP::Message instances for various PSRP messages
23
+ class MessageFactory
24
+ class << self
25
+ # Creates a new session capability PSRP message.
26
+ # @param runspace_pool_id [String] The UUID of the remote shell/runspace pool.
27
+ def session_capability_message(runspace_pool_id)
28
+ Message.new(
29
+ runspace_pool_id,
30
+ Message::MESSAGE_TYPES[:session_capability],
31
+ render('session_capability')
32
+ )
33
+ end
34
+
35
+ # Creates a new init runspace pool PSRP message.
36
+ # @param runspace_pool_id [String] The UUID of the remote shell/runspace pool.
37
+ def init_runspace_pool_message(runspace_pool_id)
38
+ Message.new(
39
+ runspace_pool_id,
40
+ Message::MESSAGE_TYPES[:init_runspacepool],
41
+ render('init_runspace_pool')
42
+ )
43
+ end
44
+
45
+ # Creates a new PSRP message that creates pipline to execute a command.
46
+ # @param runspace_pool_id [String] The UUID of the remote shell/runspace pool.
47
+ # @param pipeline_id [String] The UUID to correlate the command/pipeline
48
+ # response.
49
+ # @param command [String] The command passed to Invoke-Expression.
50
+ def create_pipeline_message(runspace_pool_id, pipeline_id, command)
51
+ Message.new(
52
+ runspace_pool_id,
53
+ Message::MESSAGE_TYPES[:create_pipeline],
54
+ render('create_pipeline', command: command.encode(xml: :text)),
55
+ pipeline_id
56
+ )
57
+ end
58
+
59
+ private
60
+
61
+ # Renders the specified template with the given context
62
+ # @param template [String] The base filename of the PSRP message template.
63
+ # @param context [Hash] Any options required for rendering the template.
64
+ # @return [String] The rendered XML PSRP message.
65
+ # @api private
66
+ def render(template, context = nil)
67
+ template_path = File.expand_path(
68
+ "#{File.dirname(__FILE__)}/#{template}.xml.erb")
69
+ template = File.read(template_path)
70
+ Erubis::Eruby.new(template).result(context)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -1,60 +1,60 @@
1
- # encoding: UTF-8
2
- #
3
- # Copyright 2016 Matt Wrock <matt@mattwrock.com>
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the 'License');
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an 'AS IS' BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
-
17
- require_relative 'fragment'
18
-
19
- module WinRM
20
- # PowerShell Remoting Protcol module
21
- module PSRP
22
- # PowerShell Remoting Protocol message fragmenter.
23
- class MessageFragmenter
24
- DEFAULT_BLOB_LENGTH = 32_768
25
-
26
- def initialize(max_blob_length = DEFAULT_BLOB_LENGTH)
27
- @object_id = 0
28
- @max_blob_length = max_blob_length || DEFAULT_BLOB_LENGTH
29
- end
30
-
31
- attr_reader :object_id
32
- attr_accessor :max_blob_length
33
-
34
- def fragment(message)
35
- @object_id += 1
36
- message_bytes = message.bytes
37
- bytes_fragmented = 0
38
- fragment_id = 0
39
- fragment = nil
40
-
41
- while bytes_fragmented < message_bytes.length
42
- last_byte = bytes_fragmented + max_blob_length
43
- last_byte = message_bytes.length if last_byte > message_bytes.length
44
- fragment = Fragment.new(
45
- object_id,
46
- message.bytes[bytes_fragmented..last_byte - 1],
47
- fragment_id,
48
- bytes_fragmented == 0,
49
- last_byte == message_bytes.length
50
- )
51
- fragment_id += 1
52
- bytes_fragmented = last_byte
53
- yield fragment if block_given?
54
- end
55
-
56
- fragment
57
- end
58
- end
59
- end
60
- end
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright 2016 Matt Wrock <matt@mattwrock.com>
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the 'License');
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an 'AS IS' BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require_relative 'fragment'
18
+
19
+ module WinRM
20
+ # PowerShell Remoting Protcol module
21
+ module PSRP
22
+ # PowerShell Remoting Protocol message fragmenter.
23
+ class MessageFragmenter
24
+ DEFAULT_BLOB_LENGTH = 32_768
25
+
26
+ def initialize(max_blob_length = DEFAULT_BLOB_LENGTH)
27
+ @object_id = 0
28
+ @max_blob_length = max_blob_length || DEFAULT_BLOB_LENGTH
29
+ end
30
+
31
+ attr_reader :object_id
32
+ attr_accessor :max_blob_length
33
+
34
+ def fragment(message)
35
+ @object_id += 1
36
+ message_bytes = message.bytes
37
+ bytes_fragmented = 0
38
+ fragment_id = 0
39
+ fragment = nil
40
+
41
+ while bytes_fragmented < message_bytes.length
42
+ last_byte = bytes_fragmented + max_blob_length
43
+ last_byte = message_bytes.length if last_byte > message_bytes.length
44
+ fragment = Fragment.new(
45
+ object_id,
46
+ message.bytes[bytes_fragmented..last_byte - 1],
47
+ fragment_id,
48
+ bytes_fragmented == 0,
49
+ last_byte == message_bytes.length
50
+ )
51
+ fragment_id += 1
52
+ bytes_fragmented = last_byte
53
+ yield fragment if block_given?
54
+ end
55
+
56
+ fragment
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,139 +1,139 @@
1
- # -*- encoding: utf-8 -*-
2
- #
3
- # Copyright 2016 Matt Wrock <matt@mattwrock.com>
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
-
17
- require 'base64'
18
- require_relative 'message'
19
- require_relative 'message_data/pipeline_state'
20
-
21
- module WinRM
22
- module PSRP
23
- # Handles decoding a raw powershell output response
24
- class PowershellOutputDecoder
25
- # rubocop:disable Metrics/CyclomaticComplexity
26
- # Decode the raw SOAP output into decoded PSRP message,
27
- # Removes BOM and replaces encoded line endings
28
- # @param raw_output [String] The raw encoded output
29
- # @return [String] The decoded output
30
- def decode(message)
31
- case message.type
32
- when WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_output]
33
- decode_pipeline_output(message)
34
- when WinRM::PSRP::Message::MESSAGE_TYPES[:runspacepool_host_call]
35
- decode_host_call(message)
36
- when WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_host_call]
37
- decode_host_call(message)
38
- when WinRM::PSRP::Message::MESSAGE_TYPES[:error_record]
39
- decode_error_record(message)
40
- when WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_state]
41
- if message.parsed_data.pipeline_state == WinRM::PSRP::MessageData::PipelineState::FAILED
42
- decode_error_record(message)
43
- end
44
- end
45
- end
46
- # rubocop:enable Metrics/CyclomaticComplexity
47
-
48
- protected
49
-
50
- def decode_pipeline_output(message)
51
- message.parsed_data.output
52
- end
53
-
54
- def decode_host_call(message)
55
- text = begin
56
- case message.parsed_data.method_identifier
57
- when /WriteLine/, 'WriteErrorLine'
58
- "#{message.parsed_data.method_parameters[:s]}\r\n"
59
- when 'WriteDebugLine'
60
- "Debug: #{message.parsed_data.method_parameters[:s]}\r\n"
61
- when 'WriteWarningLine'
62
- "Warning: #{message.parsed_data.method_parameters[:s]}\r\n"
63
- when 'WriteVerboseLine'
64
- "Verbose: #{message.parsed_data.method_parameters[:s]}\r\n"
65
- when /Write[1-2]/
66
- message.parsed_data.method_parameters[:s]
67
- end
68
- end
69
-
70
- hex_decode(text)
71
- end
72
-
73
- def decode_error_record(message)
74
- parsed = message.parsed_data
75
- text = begin
76
- if message.type == WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_state]
77
- render_exception_as_error_record(parsed.exception_as_error_record)
78
- else
79
- case parsed.fully_qualified_error_id
80
- when 'Microsoft.PowerShell.Commands.WriteErrorException'
81
- render_write_error_exception(parsed)
82
- when 'NativeCommandError'
83
- render_native_command_error(parsed)
84
- when 'NativeCommandErrorMessage'
85
- parsed.exception[:message]
86
- else
87
- render_exception(parsed)
88
- end
89
- end
90
- end
91
-
92
- hex_decode(text)
93
- end
94
-
95
- def render_write_error_exception(parsed)
96
- <<EOH
97
- #{parsed.invocation_info[:line]} : #{parsed.exception[:message]}
98
- + CategoryInfo : #{parsed.error_category_message}
99
- + FullyQualifiedErrorId : #{parsed.fully_qualified_error_id}
100
- EOH
101
- end
102
-
103
- def render_exception(parsed)
104
- <<EOH
105
- #{parsed.exception[:message]}
106
- #{parsed.invocation_info[:position_message]}
107
- + CategoryInfo : #{parsed.error_category_message}
108
- + FullyQualifiedErrorId : #{parsed.fully_qualified_error_id}
109
- EOH
110
- end
111
-
112
- def render_native_command_error(parsed)
113
- <<EOH
114
- #{parsed.invocation_info[:my_command]} : #{parsed.exception[:message]}
115
- + CategoryInfo : #{parsed.error_category_message}
116
- + FullyQualifiedErrorId : #{parsed.fully_qualified_error_id}
117
- EOH
118
- end
119
-
120
- def render_exception_as_error_record(parsed)
121
- <<EOH
122
- #{parsed.exception[:message]}
123
- + CategoryInfo : #{parsed.error_category_message}
124
- + FullyQualifiedErrorId : #{parsed.fully_qualified_error_id}
125
- EOH
126
- end
127
-
128
- private
129
-
130
- def hex_decode(text)
131
- return unless text
132
-
133
- text.gsub(/_x(\h\h\h\h)_/) do
134
- Regexp.last_match[1].hex.chr
135
- end
136
- end
137
- end
138
- end
139
- end
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2016 Matt Wrock <matt@mattwrock.com>
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'base64'
18
+ require_relative 'message'
19
+ require_relative 'message_data/pipeline_state'
20
+
21
+ module WinRM
22
+ module PSRP
23
+ # Handles decoding a raw powershell output response
24
+ class PowershellOutputDecoder
25
+ # rubocop:disable Metrics/CyclomaticComplexity
26
+ # Decode the raw SOAP output into decoded PSRP message,
27
+ # Removes BOM and replaces encoded line endings
28
+ # @param raw_output [String] The raw encoded output
29
+ # @return [String] The decoded output
30
+ def decode(message)
31
+ case message.type
32
+ when WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_output]
33
+ decode_pipeline_output(message)
34
+ when WinRM::PSRP::Message::MESSAGE_TYPES[:runspacepool_host_call]
35
+ decode_host_call(message)
36
+ when WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_host_call]
37
+ decode_host_call(message)
38
+ when WinRM::PSRP::Message::MESSAGE_TYPES[:error_record]
39
+ decode_error_record(message)
40
+ when WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_state]
41
+ if message.parsed_data.pipeline_state == WinRM::PSRP::MessageData::PipelineState::FAILED
42
+ decode_error_record(message)
43
+ end
44
+ end
45
+ end
46
+ # rubocop:enable Metrics/CyclomaticComplexity
47
+
48
+ protected
49
+
50
+ def decode_pipeline_output(message)
51
+ message.parsed_data.output
52
+ end
53
+
54
+ def decode_host_call(message)
55
+ text = begin
56
+ case message.parsed_data.method_identifier
57
+ when /WriteLine/, 'WriteErrorLine'
58
+ "#{message.parsed_data.method_parameters[:s]}\r\n"
59
+ when 'WriteDebugLine'
60
+ "Debug: #{message.parsed_data.method_parameters[:s]}\r\n"
61
+ when 'WriteWarningLine'
62
+ "Warning: #{message.parsed_data.method_parameters[:s]}\r\n"
63
+ when 'WriteVerboseLine'
64
+ "Verbose: #{message.parsed_data.method_parameters[:s]}\r\n"
65
+ when /Write[1-2]/
66
+ message.parsed_data.method_parameters[:s]
67
+ end
68
+ end
69
+
70
+ hex_decode(text)
71
+ end
72
+
73
+ def decode_error_record(message)
74
+ parsed = message.parsed_data
75
+ text = begin
76
+ if message.type == WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_state]
77
+ render_exception_as_error_record(parsed.exception_as_error_record)
78
+ else
79
+ case parsed.fully_qualified_error_id
80
+ when 'Microsoft.PowerShell.Commands.WriteErrorException'
81
+ render_write_error_exception(parsed)
82
+ when 'NativeCommandError'
83
+ render_native_command_error(parsed)
84
+ when 'NativeCommandErrorMessage'
85
+ parsed.exception[:message]
86
+ else
87
+ render_exception(parsed)
88
+ end
89
+ end
90
+ end
91
+
92
+ hex_decode(text)
93
+ end
94
+
95
+ def render_write_error_exception(parsed)
96
+ <<EOH
97
+ #{parsed.invocation_info[:line]} : #{parsed.exception[:message]}
98
+ + CategoryInfo : #{parsed.error_category_message}
99
+ + FullyQualifiedErrorId : #{parsed.fully_qualified_error_id}
100
+ EOH
101
+ end
102
+
103
+ def render_exception(parsed)
104
+ <<EOH
105
+ #{parsed.exception[:message]}
106
+ #{parsed.invocation_info[:position_message]}
107
+ + CategoryInfo : #{parsed.error_category_message}
108
+ + FullyQualifiedErrorId : #{parsed.fully_qualified_error_id}
109
+ EOH
110
+ end
111
+
112
+ def render_native_command_error(parsed)
113
+ <<EOH
114
+ #{parsed.invocation_info[:my_command]} : #{parsed.exception[:message]}
115
+ + CategoryInfo : #{parsed.error_category_message}
116
+ + FullyQualifiedErrorId : #{parsed.fully_qualified_error_id}
117
+ EOH
118
+ end
119
+
120
+ def render_exception_as_error_record(parsed)
121
+ <<EOH
122
+ #{parsed.exception[:message]}
123
+ + CategoryInfo : #{parsed.error_category_message}
124
+ + FullyQualifiedErrorId : #{parsed.fully_qualified_error_id}
125
+ EOH
126
+ end
127
+
128
+ private
129
+
130
+ def hex_decode(text)
131
+ return unless text
132
+
133
+ text.gsub(/_x(\h\h\h\h)_/) do
134
+ Regexp.last_match[1].hex.chr
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end