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.
- checksums.yaml +4 -4
- data/.gitignore +10 -10
- data/.rubocop.yml +26 -26
- data/.travis.yml +11 -11
- data/Gemfile +3 -3
- data/README.md +260 -233
- data/Rakefile +34 -34
- data/Vagrantfile +6 -6
- data/WinrmAppveyor.psm1 +31 -31
- data/appveyor.yml +51 -51
- data/changelog.md +104 -101
- data/lib/winrm.rb +39 -39
- data/lib/winrm/connection.rb +83 -82
- data/lib/winrm/connection_opts.rb +91 -91
- data/lib/winrm/exceptions.rb +76 -76
- data/lib/winrm/http/response_handler.rb +96 -96
- data/lib/winrm/http/transport.rb +424 -424
- data/lib/winrm/http/transport_factory.rb +68 -68
- data/lib/winrm/output.rb +59 -59
- data/lib/winrm/psrp/create_pipeline.xml.erb +167 -167
- data/lib/winrm/psrp/fragment.rb +70 -70
- data/lib/winrm/psrp/init_runspace_pool.xml.erb +224 -224
- data/lib/winrm/psrp/message.rb +130 -130
- data/lib/winrm/psrp/message_data.rb +42 -42
- data/lib/winrm/psrp/message_data/base.rb +49 -49
- data/lib/winrm/psrp/message_data/error_record.rb +68 -68
- data/lib/winrm/psrp/message_data/pipeline_host_call.rb +32 -32
- data/lib/winrm/psrp/message_data/pipeline_output.rb +49 -49
- data/lib/winrm/psrp/message_data/pipeline_state.rb +40 -40
- data/lib/winrm/psrp/message_data/runspacepool_host_call.rb +32 -32
- data/lib/winrm/psrp/message_data/runspacepool_state.rb +39 -39
- data/lib/winrm/psrp/message_data/session_capability.rb +36 -36
- data/lib/winrm/psrp/message_defragmenter.rb +62 -62
- data/lib/winrm/psrp/message_factory.rb +75 -75
- data/lib/winrm/psrp/message_fragmenter.rb +60 -60
- data/lib/winrm/psrp/powershell_output_decoder.rb +139 -139
- data/lib/winrm/psrp/receive_response_reader.rb +97 -97
- data/lib/winrm/psrp/session_capability.xml.erb +7 -7
- data/lib/winrm/psrp/uuid.rb +40 -40
- data/lib/winrm/shells/base.rb +180 -175
- data/lib/winrm/shells/cmd.rb +65 -65
- data/lib/winrm/shells/power_shell.rb +202 -202
- data/lib/winrm/shells/retryable.rb +45 -45
- data/lib/winrm/shells/shell_factory.rb +58 -50
- data/lib/winrm/version.rb +7 -7
- data/lib/winrm/wsmv/base.rb +59 -59
- data/lib/winrm/wsmv/cleanup_command.rb +61 -61
- data/lib/winrm/wsmv/close_shell.rb +50 -50
- data/lib/winrm/wsmv/command.rb +101 -101
- data/lib/winrm/wsmv/command_output.rb +76 -76
- data/lib/winrm/wsmv/command_output_decoder.rb +55 -55
- data/lib/winrm/wsmv/configuration.rb +46 -46
- data/lib/winrm/wsmv/create_pipeline.rb +66 -66
- data/lib/winrm/wsmv/create_shell.rb +119 -119
- data/lib/winrm/wsmv/header.rb +203 -203
- data/lib/winrm/wsmv/init_runspace_pool.rb +95 -95
- data/lib/winrm/wsmv/iso8601_duration.rb +60 -60
- data/lib/winrm/wsmv/keep_alive.rb +68 -68
- data/lib/winrm/wsmv/receive_response_reader.rb +126 -126
- data/lib/winrm/wsmv/send_data.rb +68 -68
- data/lib/winrm/wsmv/soap.rb +51 -51
- data/lib/winrm/wsmv/wql_query.rb +79 -79
- data/lib/winrm/wsmv/write_stdin.rb +88 -88
- data/tests/integration/auth_timeout_spec.rb +18 -18
- data/tests/integration/cmd_spec.rb +131 -110
- data/tests/integration/config-example.yml +16 -16
- data/tests/integration/issue_59_spec.rb +26 -26
- data/tests/integration/powershell_spec.rb +165 -165
- data/tests/integration/spec_helper.rb +65 -65
- data/tests/integration/transport_spec.rb +99 -99
- data/tests/integration/wql_spec.rb +16 -16
- data/tests/matchers.rb +60 -60
- data/tests/spec/configuration_spec.rb +184 -184
- data/tests/spec/connection_spec.rb +39 -39
- data/tests/spec/exception_spec.rb +50 -50
- data/tests/spec/http/transport_factory_spec.rb +68 -68
- data/tests/spec/http/transport_spec.rb +44 -44
- data/tests/spec/output_spec.rb +127 -127
- data/tests/spec/psrp/fragment_spec.rb +62 -62
- data/tests/spec/psrp/message_data/base_spec.rb +13 -13
- data/tests/spec/psrp/message_data/error_record_spec.rb +41 -41
- data/tests/spec/psrp/message_data/pipeline_host_call_spec.rb +25 -25
- data/tests/spec/psrp/message_data/pipeline_output_spec.rb +32 -32
- data/tests/spec/psrp/message_data/pipeline_state_spec.rb +40 -40
- data/tests/spec/psrp/message_data/runspace_pool_host_call_spec.rb +25 -25
- data/tests/spec/psrp/message_data/runspacepool_state_spec.rb +16 -16
- data/tests/spec/psrp/message_data/session_capability_spec.rb +30 -30
- data/tests/spec/psrp/message_data_spec.rb +35 -35
- data/tests/spec/psrp/message_defragmenter_spec.rb +47 -47
- data/tests/spec/psrp/message_fragmenter_spec.rb +105 -105
- data/tests/spec/psrp/powershell_output_decoder_spec.rb +100 -100
- data/tests/spec/psrp/psrp_message_spec.rb +70 -70
- data/tests/spec/psrp/recieve_response_reader_spec.rb +172 -172
- data/tests/spec/psrp/uuid_spec.rb +28 -28
- data/tests/spec/response_handler_spec.rb +61 -61
- data/tests/spec/shells/base_spec.rb +202 -202
- data/tests/spec/shells/cmd_spec.rb +75 -75
- data/tests/spec/shells/powershell_spec.rb +175 -175
- data/tests/spec/spec_helper.rb +47 -47
- data/tests/spec/stubs/clixml/error_record.xml.erb +84 -84
- data/tests/spec/stubs/clixml/pipeline_state.xml.erb +88 -88
- data/tests/spec/stubs/responses/get_command_output_response.xml.erb +13 -13
- data/tests/spec/stubs/responses/get_command_output_response_not_done.xml.erb +10 -10
- data/tests/spec/stubs/responses/get_powershell_keepalive_response.xml.erb +10 -10
- data/tests/spec/stubs/responses/get_powershell_output_response.xml.erb +12 -12
- data/tests/spec/stubs/responses/get_powershell_output_response_not_done.xml.erb +9 -9
- data/tests/spec/stubs/responses/open_shell_v1.xml +19 -19
- data/tests/spec/stubs/responses/open_shell_v2.xml +20 -20
- data/tests/spec/stubs/responses/soap_fault_v1.xml +36 -36
- data/tests/spec/stubs/responses/soap_fault_v2.xml +42 -42
- data/tests/spec/stubs/responses/wmi_error_v2.xml +41 -41
- data/tests/spec/wsmv/cleanup_command_spec.rb +22 -22
- data/tests/spec/wsmv/close_shell_spec.rb +17 -17
- data/tests/spec/wsmv/command_output_decoder_spec.rb +37 -37
- data/tests/spec/wsmv/command_output_spec.rb +45 -45
- data/tests/spec/wsmv/command_spec.rb +19 -19
- data/tests/spec/wsmv/configuration_spec.rb +17 -17
- data/tests/spec/wsmv/create_pipeline_spec.rb +31 -31
- data/tests/spec/wsmv/create_shell_spec.rb +38 -38
- data/tests/spec/wsmv/init_runspace_pool_spec.rb +36 -36
- data/tests/spec/wsmv/keep_alive_spec.rb +21 -21
- data/tests/spec/wsmv/receive_response_reader_spec.rb +123 -123
- data/tests/spec/wsmv/send_data_spec.rb +30 -30
- data/tests/spec/wsmv/wql_query_spec.rb +13 -13
- data/tests/spec/wsmv/write_stdin_spec.rb +22 -22
- data/winrm.gemspec +42 -42
- metadata +2 -2
|
@@ -1,97 +1,97 @@
|
|
|
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 'nori'
|
|
18
|
-
require_relative 'powershell_output_decoder'
|
|
19
|
-
require_relative 'message_defragmenter'
|
|
20
|
-
|
|
21
|
-
module WinRM
|
|
22
|
-
module PSRP
|
|
23
|
-
# Class for reading powershell responses in Receive_Response messages
|
|
24
|
-
class ReceiveResponseReader < WSMV::ReceiveResponseReader
|
|
25
|
-
# Creates a new ReceiveResponseReader
|
|
26
|
-
# @param transport [HttpTransport] The WinRM SOAP transport
|
|
27
|
-
# @param logger [Logger] The logger to log diagnostic messages to
|
|
28
|
-
def initialize(transport, logger)
|
|
29
|
-
super
|
|
30
|
-
@output_decoder = PowershellOutputDecoder.new
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Reads PSRP messages sent in one or more receive response messages
|
|
34
|
-
# @param wsmv_message [WinRM::WSMV::Base] A wsmv message to send to endpoint
|
|
35
|
-
# @param wait_for_done_state whether to poll for a CommandState of Done
|
|
36
|
-
# @yield [Message] PSRP Message in response
|
|
37
|
-
# @yieldreturn [Array<Message>] All messages in response
|
|
38
|
-
def read_message(wsmv_message, wait_for_done_state = false)
|
|
39
|
-
messages = []
|
|
40
|
-
defragmenter = MessageDefragmenter.new
|
|
41
|
-
read_response(wsmv_message, wait_for_done_state) do |stream|
|
|
42
|
-
message = defragmenter.defragment(stream[:text])
|
|
43
|
-
next unless message
|
|
44
|
-
if block_given?
|
|
45
|
-
yield message
|
|
46
|
-
else
|
|
47
|
-
messages.push(message)
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
messages unless block_given?
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# Reads streams and returns decoded output
|
|
54
|
-
# @param wsmv_message [WinRM::WSMV::Base] A wsmv message to send to endpoint
|
|
55
|
-
# @yieldparam [string] standard out response text
|
|
56
|
-
# @yieldparam [string] standard error response text
|
|
57
|
-
# @yieldreturn [WinRM::Output] The command output
|
|
58
|
-
def read_output(wsmv_message)
|
|
59
|
-
with_output do |output|
|
|
60
|
-
read_message(wsmv_message, true) do |message|
|
|
61
|
-
exit_code = find_exit_code(message)
|
|
62
|
-
output.exitcode = exit_code if exit_code
|
|
63
|
-
decoded_text = @output_decoder.decode(message)
|
|
64
|
-
next unless decoded_text
|
|
65
|
-
out = { stream_type(message) => decoded_text }
|
|
66
|
-
output << out
|
|
67
|
-
yield [out[:stdout], out[:stderr]] if block_given?
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
private
|
|
73
|
-
|
|
74
|
-
def stream_type(message)
|
|
75
|
-
type = :stdout
|
|
76
|
-
case message.type
|
|
77
|
-
when WinRM::PSRP::Message::MESSAGE_TYPES[:error_record]
|
|
78
|
-
type = :stderr
|
|
79
|
-
when WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_host_call]
|
|
80
|
-
type = :stderr if message.data.include?('WriteError')
|
|
81
|
-
when WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_state]
|
|
82
|
-
if message.parsed_data.pipeline_state == WinRM::PSRP::MessageData::PipelineState::FAILED
|
|
83
|
-
type = :stderr
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
type
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def find_exit_code(message)
|
|
90
|
-
parsed = message.parsed_data
|
|
91
|
-
return nil unless parsed.is_a?(MessageData::PipelineHostCall)
|
|
92
|
-
|
|
93
|
-
parsed.method_parameters[:i32].to_i if parsed.method_identifier == 'SetShouldExit'
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
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 'nori'
|
|
18
|
+
require_relative 'powershell_output_decoder'
|
|
19
|
+
require_relative 'message_defragmenter'
|
|
20
|
+
|
|
21
|
+
module WinRM
|
|
22
|
+
module PSRP
|
|
23
|
+
# Class for reading powershell responses in Receive_Response messages
|
|
24
|
+
class ReceiveResponseReader < WSMV::ReceiveResponseReader
|
|
25
|
+
# Creates a new ReceiveResponseReader
|
|
26
|
+
# @param transport [HttpTransport] The WinRM SOAP transport
|
|
27
|
+
# @param logger [Logger] The logger to log diagnostic messages to
|
|
28
|
+
def initialize(transport, logger)
|
|
29
|
+
super
|
|
30
|
+
@output_decoder = PowershellOutputDecoder.new
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Reads PSRP messages sent in one or more receive response messages
|
|
34
|
+
# @param wsmv_message [WinRM::WSMV::Base] A wsmv message to send to endpoint
|
|
35
|
+
# @param wait_for_done_state whether to poll for a CommandState of Done
|
|
36
|
+
# @yield [Message] PSRP Message in response
|
|
37
|
+
# @yieldreturn [Array<Message>] All messages in response
|
|
38
|
+
def read_message(wsmv_message, wait_for_done_state = false)
|
|
39
|
+
messages = []
|
|
40
|
+
defragmenter = MessageDefragmenter.new
|
|
41
|
+
read_response(wsmv_message, wait_for_done_state) do |stream|
|
|
42
|
+
message = defragmenter.defragment(stream[:text])
|
|
43
|
+
next unless message
|
|
44
|
+
if block_given?
|
|
45
|
+
yield message
|
|
46
|
+
else
|
|
47
|
+
messages.push(message)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
messages unless block_given?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Reads streams and returns decoded output
|
|
54
|
+
# @param wsmv_message [WinRM::WSMV::Base] A wsmv message to send to endpoint
|
|
55
|
+
# @yieldparam [string] standard out response text
|
|
56
|
+
# @yieldparam [string] standard error response text
|
|
57
|
+
# @yieldreturn [WinRM::Output] The command output
|
|
58
|
+
def read_output(wsmv_message)
|
|
59
|
+
with_output do |output|
|
|
60
|
+
read_message(wsmv_message, true) do |message|
|
|
61
|
+
exit_code = find_exit_code(message)
|
|
62
|
+
output.exitcode = exit_code if exit_code
|
|
63
|
+
decoded_text = @output_decoder.decode(message)
|
|
64
|
+
next unless decoded_text
|
|
65
|
+
out = { stream_type(message) => decoded_text }
|
|
66
|
+
output << out
|
|
67
|
+
yield [out[:stdout], out[:stderr]] if block_given?
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def stream_type(message)
|
|
75
|
+
type = :stdout
|
|
76
|
+
case message.type
|
|
77
|
+
when WinRM::PSRP::Message::MESSAGE_TYPES[:error_record]
|
|
78
|
+
type = :stderr
|
|
79
|
+
when WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_host_call]
|
|
80
|
+
type = :stderr if message.data.include?('WriteError')
|
|
81
|
+
when WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_state]
|
|
82
|
+
if message.parsed_data.pipeline_state == WinRM::PSRP::MessageData::PipelineState::FAILED
|
|
83
|
+
type = :stderr
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
type
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def find_exit_code(message)
|
|
90
|
+
parsed = message.parsed_data
|
|
91
|
+
return nil unless parsed.is_a?(MessageData::PipelineHostCall)
|
|
92
|
+
|
|
93
|
+
parsed.method_parameters[:i32].to_i if parsed.method_identifier == 'SetShouldExit'
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
<Obj RefId="0">
|
|
2
|
-
<MS>
|
|
3
|
-
<Version N="protocolversion">2.3</Version>
|
|
4
|
-
<Version N="PSVersion">2.0</Version>
|
|
5
|
-
<Version N="SerializationVersion">1.1.0.1</Version>
|
|
6
|
-
</MS>
|
|
7
|
-
</Obj>
|
|
1
|
+
<Obj RefId="0">
|
|
2
|
+
<MS>
|
|
3
|
+
<Version N="protocolversion">2.3</Version>
|
|
4
|
+
<Version N="PSVersion">2.0</Version>
|
|
5
|
+
<Version N="SerializationVersion">1.1.0.1</Version>
|
|
6
|
+
</MS>
|
|
7
|
+
</Obj>
|
data/lib/winrm/psrp/uuid.rb
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
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
|
-
module WinRM
|
|
18
|
-
module PSRP
|
|
19
|
-
# UUID helper methods
|
|
20
|
-
module UUID
|
|
21
|
-
# Format a UUID into a GUID compatible byte array for Windows
|
|
22
|
-
#
|
|
23
|
-
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa373931(v=vs.85).aspx
|
|
24
|
-
# typedef struct _GUID {
|
|
25
|
-
# DWORD Data1;
|
|
26
|
-
# WORD Data2;
|
|
27
|
-
# WORD Data3;
|
|
28
|
-
# BYTE Data4[8];
|
|
29
|
-
# } GUID;
|
|
30
|
-
#
|
|
31
|
-
# @param uuid [String] Canonical hex format with hypens.
|
|
32
|
-
# @return [Array<byte>] UUID in a Windows GUID compatible byte array layout.
|
|
33
|
-
def uuid_to_windows_guid_bytes(uuid)
|
|
34
|
-
return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] unless uuid
|
|
35
|
-
b = uuid.scan(/[0-9a-fA-F]{2}/).map { |x| x.to_i(16) }
|
|
36
|
-
b[0..3].reverse + b[4..5].reverse + b[6..7].reverse + b[8..15]
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
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
|
+
module WinRM
|
|
18
|
+
module PSRP
|
|
19
|
+
# UUID helper methods
|
|
20
|
+
module UUID
|
|
21
|
+
# Format a UUID into a GUID compatible byte array for Windows
|
|
22
|
+
#
|
|
23
|
+
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa373931(v=vs.85).aspx
|
|
24
|
+
# typedef struct _GUID {
|
|
25
|
+
# DWORD Data1;
|
|
26
|
+
# WORD Data2;
|
|
27
|
+
# WORD Data3;
|
|
28
|
+
# BYTE Data4[8];
|
|
29
|
+
# } GUID;
|
|
30
|
+
#
|
|
31
|
+
# @param uuid [String] Canonical hex format with hypens.
|
|
32
|
+
# @return [Array<byte>] UUID in a Windows GUID compatible byte array layout.
|
|
33
|
+
def uuid_to_windows_guid_bytes(uuid)
|
|
34
|
+
return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] unless uuid
|
|
35
|
+
b = uuid.scan(/[0-9a-fA-F]{2}/).map { |x| x.to_i(16) }
|
|
36
|
+
b[0..3].reverse + b[4..5].reverse + b[6..7].reverse + b[8..15]
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
data/lib/winrm/shells/base.rb
CHANGED
|
@@ -1,175 +1,180 @@
|
|
|
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_relative 'retryable'
|
|
18
|
-
require_relative '../http/transport'
|
|
19
|
-
require_relative '../wsmv/cleanup_command'
|
|
20
|
-
require_relative '../wsmv/close_shell'
|
|
21
|
-
require_relative '../wsmv/command'
|
|
22
|
-
require_relative '../wsmv/command_output'
|
|
23
|
-
require_relative '../wsmv/receive_response_reader'
|
|
24
|
-
require_relative '../wsmv/create_shell'
|
|
25
|
-
require_relative '../wsmv/soap'
|
|
26
|
-
|
|
27
|
-
module WinRM
|
|
28
|
-
module Shells
|
|
29
|
-
# Base class for remote shell
|
|
30
|
-
class Base
|
|
31
|
-
TOO_MANY_COMMANDS = '2150859174'.freeze
|
|
32
|
-
ERROR_OPERATION_ABORTED = '995'.freeze
|
|
33
|
-
|
|
34
|
-
FAULTS_FOR_RESET = [
|
|
35
|
-
'2150858843', # Shell has been closed
|
|
36
|
-
'2147943418', # Error reading registry key
|
|
37
|
-
TOO_MANY_COMMANDS, # Maximum commands per user exceeded
|
|
38
|
-
].freeze
|
|
39
|
-
|
|
40
|
-
include Retryable
|
|
41
|
-
|
|
42
|
-
# Create a new Cmd shell
|
|
43
|
-
# @param connection_opts [ConnectionOpts] The WinRM connection options
|
|
44
|
-
# @param transport [HttpTransport] The WinRM SOAP transport
|
|
45
|
-
# @param logger [Logger] The logger to log diagnostic messages to
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
@
|
|
49
|
-
@
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
# @
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
#
|
|
73
|
-
# @
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
logger.debug(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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_relative 'retryable'
|
|
18
|
+
require_relative '../http/transport'
|
|
19
|
+
require_relative '../wsmv/cleanup_command'
|
|
20
|
+
require_relative '../wsmv/close_shell'
|
|
21
|
+
require_relative '../wsmv/command'
|
|
22
|
+
require_relative '../wsmv/command_output'
|
|
23
|
+
require_relative '../wsmv/receive_response_reader'
|
|
24
|
+
require_relative '../wsmv/create_shell'
|
|
25
|
+
require_relative '../wsmv/soap'
|
|
26
|
+
|
|
27
|
+
module WinRM
|
|
28
|
+
module Shells
|
|
29
|
+
# Base class for remote shell
|
|
30
|
+
class Base
|
|
31
|
+
TOO_MANY_COMMANDS = '2150859174'.freeze
|
|
32
|
+
ERROR_OPERATION_ABORTED = '995'.freeze
|
|
33
|
+
|
|
34
|
+
FAULTS_FOR_RESET = [
|
|
35
|
+
'2150858843', # Shell has been closed
|
|
36
|
+
'2147943418', # Error reading registry key
|
|
37
|
+
TOO_MANY_COMMANDS, # Maximum commands per user exceeded
|
|
38
|
+
].freeze
|
|
39
|
+
|
|
40
|
+
include Retryable
|
|
41
|
+
|
|
42
|
+
# Create a new Cmd shell
|
|
43
|
+
# @param connection_opts [ConnectionOpts] The WinRM connection options
|
|
44
|
+
# @param transport [HttpTransport] The WinRM SOAP transport
|
|
45
|
+
# @param logger [Logger] The logger to log diagnostic messages to
|
|
46
|
+
# @param shell_opts [Hash] Options targeted for the created shell
|
|
47
|
+
def initialize(connection_opts, transport, logger, shell_opts = {})
|
|
48
|
+
@connection_opts = connection_opts
|
|
49
|
+
@transport = transport
|
|
50
|
+
@logger = logger
|
|
51
|
+
@shell_opts = shell_opts
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @return [String] shell id of the currently opn shell or nil if shell is closed
|
|
55
|
+
attr_reader :shell_id
|
|
56
|
+
|
|
57
|
+
# @return [String] uri that SOAP calls use to identify shell type
|
|
58
|
+
attr_reader :shell_uri
|
|
59
|
+
|
|
60
|
+
# @return [ConnectionOpts] connection options of the shell
|
|
61
|
+
attr_reader :connection_opts
|
|
62
|
+
|
|
63
|
+
# @return [WinRM::HTTP::HttpTransport] transport used to talk with endpoint
|
|
64
|
+
attr_reader :transport
|
|
65
|
+
|
|
66
|
+
# @return [Logger] logger used for diagnostic messages
|
|
67
|
+
attr_reader :logger
|
|
68
|
+
|
|
69
|
+
# @return [Hash] Options targeted for the created shell
|
|
70
|
+
attr_reader :shell_opts
|
|
71
|
+
|
|
72
|
+
# Runs the specified command with optional arguments
|
|
73
|
+
# @param command [String] The command or executable to run
|
|
74
|
+
# @param arguments [Array] The optional command arguments
|
|
75
|
+
# @param block [&block] The optional callback for any realtime output
|
|
76
|
+
# @yieldparam [string] standard out response text
|
|
77
|
+
# @yieldparam [string] standard error response text
|
|
78
|
+
# @yieldreturn [WinRM::Output] The command output
|
|
79
|
+
def run(command, arguments = [], &block)
|
|
80
|
+
with_command_shell(command, arguments) do |shell, cmd|
|
|
81
|
+
response_reader.read_output(command_output_message(shell, cmd), &block)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Closes the shell if one is open
|
|
86
|
+
def close
|
|
87
|
+
return unless shell_id
|
|
88
|
+
self.class.close_shell(connection_opts, transport, shell_id)
|
|
89
|
+
remove_finalizer
|
|
90
|
+
@shell_id = nil
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
protected
|
|
94
|
+
|
|
95
|
+
def send_command(_command, _arguments)
|
|
96
|
+
raise NotImplementedError
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def response_reader
|
|
100
|
+
raise NotImplementedError
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def open_shell
|
|
104
|
+
raise NotImplementedError
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def out_streams
|
|
108
|
+
raise NotImplementedError
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def command_output_message(shell_id, command_id)
|
|
112
|
+
cmd_out_opts = {
|
|
113
|
+
shell_id: shell_id,
|
|
114
|
+
command_id: command_id,
|
|
115
|
+
shell_uri: shell_uri,
|
|
116
|
+
out_streams: out_streams
|
|
117
|
+
}
|
|
118
|
+
WinRM::WSMV::CommandOutput.new(connection_opts, cmd_out_opts)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def with_command_shell(command, arguments = [])
|
|
122
|
+
tries ||= 2
|
|
123
|
+
|
|
124
|
+
open unless shell_id
|
|
125
|
+
command_id = send_command(command, arguments)
|
|
126
|
+
logger.debug("[WinRM] creating command_id: #{command_id} on shell_id #{shell_id}")
|
|
127
|
+
yield shell_id, command_id
|
|
128
|
+
rescue WinRMWSManFault => e
|
|
129
|
+
raise unless FAULTS_FOR_RESET.include?(e.fault_code) && (tries -= 1) > 0
|
|
130
|
+
reset_on_error(e)
|
|
131
|
+
retry
|
|
132
|
+
ensure
|
|
133
|
+
cleanup_command(command_id) if command_id
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
private
|
|
137
|
+
|
|
138
|
+
def reset_on_error(error)
|
|
139
|
+
close if error.fault_code == TOO_MANY_COMMANDS
|
|
140
|
+
logger.debug('[WinRM] opening new shell since the current one was deleted')
|
|
141
|
+
@shell_id = nil
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def cleanup_command(command_id)
|
|
145
|
+
logger.debug("[WinRM] cleaning up command_id: #{command_id} on shell_id #{shell_id}")
|
|
146
|
+
cleanup_msg = WinRM::WSMV::CleanupCommand.new(
|
|
147
|
+
connection_opts,
|
|
148
|
+
shell_uri: shell_uri,
|
|
149
|
+
shell_id: shell_id,
|
|
150
|
+
command_id: command_id)
|
|
151
|
+
transport.send_request(cleanup_msg.build)
|
|
152
|
+
rescue WinRMWSManFault => e
|
|
153
|
+
raise unless e.fault_code == ERROR_OPERATION_ABORTED
|
|
154
|
+
rescue WinRMHTTPTransportError => t
|
|
155
|
+
# dont let the cleanup raise so we dont lose any errors from the command
|
|
156
|
+
logger.info("[WinRM] #{t.status_code} returned in cleanup with error: #{t.message}")
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def open
|
|
160
|
+
close
|
|
161
|
+
retryable(connection_opts[:retry_limit], connection_opts[:retry_delay]) do
|
|
162
|
+
logger.debug("[WinRM] opening remote shell on #{connection_opts[:endpoint]}")
|
|
163
|
+
@shell_id = open_shell
|
|
164
|
+
end
|
|
165
|
+
logger.debug("[WinRM] remote shell created with shell_id: #{shell_id}")
|
|
166
|
+
add_finalizer
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def add_finalizer
|
|
170
|
+
ObjectSpace.define_finalizer(
|
|
171
|
+
self,
|
|
172
|
+
self.class.finalize(connection_opts, transport, shell_id))
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def remove_finalizer
|
|
176
|
+
ObjectSpace.undefine_finalizer(self)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|