winrm 1.3.0.dev.3 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +9 -0
- data/Gemfile +1 -0
- data/README.md +8 -27
- data/Rakefile +12 -10
- data/VERSION +1 -1
- data/Vagrantfile +3 -2
- data/bin/rwinrm +21 -15
- data/changelog.md +22 -1
- data/lib/winrm.rb +12 -9
- data/lib/winrm/exceptions/exceptions.rb +5 -10
- data/lib/winrm/helpers/iso8601_duration.rb +22 -15
- data/lib/winrm/helpers/powershell_script.rb +18 -3
- data/lib/winrm/http/response_handler.rb +32 -32
- data/lib/winrm/http/transport.rb +65 -37
- data/lib/winrm/output.rb +16 -0
- data/lib/winrm/soap_provider.rb +17 -14
- data/lib/winrm/winrm_service.rb +14 -6
- data/spec/auth_timeout_spec.rb +2 -1
- data/spec/cmd_spec.rb +12 -11
- data/spec/exception_spec.rb +6 -8
- data/spec/issue_59_spec.rb +15 -0
- data/spec/matchers.rb +5 -3
- data/spec/output_spec.rb +57 -53
- data/spec/powershell_spec.rb +16 -14
- data/spec/response_handler_spec.rb +12 -11
- data/spec/spec_helper.rb +10 -7
- data/spec/winrm_options_spec.rb +6 -5
- data/spec/winrm_primitives_spec.rb +9 -10
- data/spec/wql_spec.rb +2 -1
- data/winrm.gemspec +16 -15
- metadata +20 -4
@@ -1,11 +1,13 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
1
3
|
# Copyright 2014 Shawn Neal <sneal@sneal.net>
|
2
|
-
#
|
4
|
+
#
|
3
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
6
|
# you may not use this file except in compliance with the License.
|
5
7
|
# You may obtain a copy of the License at
|
6
|
-
#
|
8
|
+
#
|
7
9
|
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
10
|
+
#
|
9
11
|
# Unless required by applicable law or agreed to in writing, software
|
10
12
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
13
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
@@ -18,7 +20,6 @@ module WinRM
|
|
18
20
|
# Handles the raw WinRM HTTP response. Returns the body as an XML doc
|
19
21
|
# or raises the appropriate WinRM error if the response is an error.
|
20
22
|
class ResponseHandler
|
21
|
-
|
22
23
|
# @param [String] The raw unparsed response body, if any
|
23
24
|
# @param [Integer] The HTTP response status code
|
24
25
|
def initialize(response_body, status_code)
|
@@ -30,53 +31,52 @@ module WinRM
|
|
30
31
|
# doc or raises an appropriate error.
|
31
32
|
#
|
32
33
|
# @returns [REXML::Document] The parsed response body
|
33
|
-
def parse_to_xml
|
34
|
-
raise_if_error
|
34
|
+
def parse_to_xml
|
35
|
+
raise_if_error
|
35
36
|
response_xml
|
36
37
|
end
|
37
38
|
|
38
39
|
private
|
39
40
|
|
40
|
-
def response_xml
|
41
|
+
def response_xml
|
41
42
|
@response_xml ||= REXML::Document.new(@response_body)
|
42
43
|
rescue REXML::ParseException => e
|
43
|
-
raise WinRMHTTPTransportError.new(
|
44
|
+
raise WinRMHTTPTransportError.new(
|
45
|
+
"Unable to parse WinRM response: #{e.message}", @status_code)
|
44
46
|
end
|
45
47
|
|
46
|
-
def raise_if_error
|
47
|
-
return if @status_code == 200
|
48
|
-
raise_if_auth_error
|
49
|
-
raise_if_wsman_fault
|
50
|
-
raise_if_wmi_error
|
51
|
-
raise_transport_error
|
48
|
+
def raise_if_error
|
49
|
+
return if @status_code == 200
|
50
|
+
raise_if_auth_error
|
51
|
+
raise_if_wsman_fault
|
52
|
+
raise_if_wmi_error
|
53
|
+
raise_transport_error
|
52
54
|
end
|
53
55
|
|
54
|
-
def raise_if_auth_error
|
55
|
-
|
56
|
+
def raise_if_auth_error
|
57
|
+
fail WinRMAuthorizationError if @status_code == 401
|
56
58
|
end
|
57
59
|
|
58
|
-
def raise_if_wsman_fault
|
60
|
+
def raise_if_wsman_fault
|
59
61
|
soap_errors = REXML::XPath.match(response_xml, "//#{NS_SOAP_ENV}:Body/#{NS_SOAP_ENV}:Fault/*")
|
60
|
-
if
|
61
|
-
|
62
|
-
|
63
|
-
end
|
62
|
+
return if soap_errors.empty?
|
63
|
+
fault = REXML::XPath.first(soap_errors, "//#{NS_WSMAN_FAULT}:WSManFault")
|
64
|
+
fail WinRMWSManFault.new(fault.to_s, fault.attributes['Code']) unless fault.nil?
|
64
65
|
end
|
65
66
|
|
66
|
-
def raise_if_wmi_error
|
67
|
+
def raise_if_wmi_error
|
67
68
|
soap_errors = REXML::XPath.match(response_xml, "//#{NS_SOAP_ENV}:Body/#{NS_SOAP_ENV}:Fault/*")
|
68
|
-
if
|
69
|
-
error = REXML::XPath.first(soap_errors, "//#{NS_WSMAN_MSFT}:MSFT_WmiError")
|
70
|
-
if !error.nil?
|
71
|
-
error_code = REXML::XPath.first(error, "//#{NS_WSMAN_MSFT}:error_Code").text
|
72
|
-
raise WinRMWMIError.new(error.to_s, error_code)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
69
|
+
return if soap_errors.empty?
|
76
70
|
|
77
|
-
|
78
|
-
|
71
|
+
error = REXML::XPath.first(soap_errors, "//#{NS_WSMAN_MSFT}:MSFT_WmiError")
|
72
|
+
return if error.nil?
|
73
|
+
|
74
|
+
error_code = REXML::XPath.first(error, "//#{NS_WSMAN_MSFT}:error_Code").text
|
75
|
+
fail WinRMWMIError.new(error.to_s, error_code)
|
79
76
|
end
|
80
77
|
|
78
|
+
def raise_transport_error
|
79
|
+
fail WinRMHTTPTransportError.new('Bad HTTP response returned from server', @status_code)
|
80
|
+
end
|
81
81
|
end
|
82
82
|
end
|
data/lib/winrm/http/transport.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
1
3
|
# Copyright 2010 Dan Wanek <dan.wanek@gmail.com>
|
2
|
-
#
|
4
|
+
#
|
3
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
6
|
# you may not use this file except in compliance with the License.
|
5
7
|
# You may obtain a copy of the License at
|
6
|
-
#
|
8
|
+
#
|
7
9
|
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
10
|
+
#
|
9
11
|
# Unless required by applicable law or agreed to in writing, software
|
10
12
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
13
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
@@ -16,20 +18,18 @@ require_relative 'response_handler'
|
|
16
18
|
|
17
19
|
module WinRM
|
18
20
|
module HTTP
|
19
|
-
|
20
21
|
# A generic HTTP transport that utilized HTTPClient to send messages back and forth.
|
21
22
|
# This backend will maintain state for every WinRMWebService instance that is instantiated so it
|
22
23
|
# is possible to use GSSAPI with Keep-Alive.
|
23
24
|
class HttpTransport
|
24
|
-
|
25
25
|
# Set this to an unreasonable amount because WinRM has its own timeouts
|
26
|
-
DEFAULT_RECEIVE_TIMEOUT = 3600
|
26
|
+
DEFAULT_RECEIVE_TIMEOUT = 3600
|
27
27
|
|
28
28
|
attr_reader :endpoint
|
29
29
|
|
30
30
|
def initialize(endpoint)
|
31
31
|
@endpoint = endpoint.is_a?(String) ? URI.parse(endpoint) : endpoint
|
32
|
-
@httpcli = HTTPClient.new(:
|
32
|
+
@httpcli = HTTPClient.new(agent_name: 'Ruby WinRM Client')
|
33
33
|
@httpcli.receive_timeout = DEFAULT_RECEIVE_TIMEOUT
|
34
34
|
@logger = Logging.logger[self]
|
35
35
|
end
|
@@ -41,23 +41,25 @@ module WinRM
|
|
41
41
|
# @returns [REXML::Document] The parsed response body
|
42
42
|
def send_request(message)
|
43
43
|
log_soap_message(message)
|
44
|
-
hdr = {
|
44
|
+
hdr = {
|
45
|
+
'Content-Type' => 'application/soap+xml;charset=UTF-8',
|
46
|
+
'Content-Length' => message.length }
|
45
47
|
resp = @httpcli.post(@endpoint, message, hdr)
|
46
48
|
log_soap_message(resp.http_body.content)
|
47
49
|
handler = WinRM::ResponseHandler.new(resp.http_body.content, resp.status)
|
48
|
-
handler.parse_to_xml
|
50
|
+
handler.parse_to_xml
|
49
51
|
end
|
50
52
|
|
51
53
|
# We'll need this to force basic authentication if desired
|
52
54
|
def basic_auth_only!
|
53
55
|
auths = @httpcli.www_auth.instance_variable_get('@authenticator')
|
54
|
-
auths.delete_if {|i| i.scheme !~ /basic/i}
|
56
|
+
auths.delete_if { |i| i.scheme !~ /basic/i }
|
55
57
|
end
|
56
58
|
|
57
59
|
# Disable SSPI Auth
|
58
60
|
def no_sspi_auth!
|
59
61
|
auths = @httpcli.www_auth.instance_variable_get('@authenticator')
|
60
|
-
auths.delete_if {|i| i.is_a? HTTPClient::SSPINegotiateAuth }
|
62
|
+
auths.delete_if { |i| i.is_a? HTTPClient::SSPINegotiateAuth }
|
61
63
|
end
|
62
64
|
|
63
65
|
# Disable SSL Peer Verification
|
@@ -71,7 +73,7 @@ module WinRM
|
|
71
73
|
@httpcli.receive_timeout = sec
|
72
74
|
end
|
73
75
|
|
74
|
-
def receive_timeout
|
76
|
+
def receive_timeout
|
75
77
|
@httpcli.receive_timeout
|
76
78
|
end
|
77
79
|
|
@@ -79,7 +81,7 @@ module WinRM
|
|
79
81
|
|
80
82
|
def log_soap_message(message)
|
81
83
|
return unless @logger.debug?
|
82
|
-
|
84
|
+
|
83
85
|
xml_msg = REXML::Document.new(message)
|
84
86
|
formatter = REXML::Formatters::Pretty.new(2)
|
85
87
|
formatter.compact = true
|
@@ -90,7 +92,7 @@ module WinRM
|
|
90
92
|
end
|
91
93
|
end
|
92
94
|
|
93
|
-
|
95
|
+
# Plain text, insecure, HTTP transport
|
94
96
|
class HttpPlaintext < HttpTransport
|
95
97
|
def initialize(endpoint, user, pass, opts)
|
96
98
|
super(endpoint)
|
@@ -114,12 +116,15 @@ module WinRM
|
|
114
116
|
end
|
115
117
|
|
116
118
|
# Uses Kerberos/GSSAPI to authenticate and encrypt messages
|
119
|
+
# rubocop:disable Metrics/ClassLength
|
117
120
|
class HttpGSSAPI < HttpTransport
|
118
121
|
# @param [String,URI] endpoint the WinRM webservice endpoint
|
119
122
|
# @param [String] realm the Kerberos realm we are authenticating to
|
120
123
|
# @param [String<optional>] service the service name, default is HTTP
|
121
124
|
# @param [String<optional>] keytab the path to a keytab file if you are using one
|
125
|
+
# rubocop:disable Lint/UnusedMethodArgument
|
122
126
|
def initialize(endpoint, realm, service = nil, keytab = nil, opts)
|
127
|
+
# rubocop:enable Lint/UnusedMethodArgument
|
123
128
|
super(endpoint)
|
124
129
|
# Remove the GSSAPI auth from HTTPClient because we are doing our own thing
|
125
130
|
no_sspi_auth!
|
@@ -137,18 +142,20 @@ module WinRM
|
|
137
142
|
resp = send_kerberos_request(message)
|
138
143
|
|
139
144
|
if resp.status == 401
|
140
|
-
@logger.debug
|
145
|
+
@logger.debug 'Got 401 - reinitializing Kerberos and retrying one more time'
|
141
146
|
init_krb
|
142
147
|
resp = send_kerberos_request(message)
|
143
148
|
end
|
144
149
|
|
145
150
|
handler = WinRM::ResponseHandler.new(winrm_decrypt(resp.http_body.content), resp.status)
|
146
|
-
handler.parse_to_xml
|
151
|
+
handler.parse_to_xml
|
147
152
|
end
|
148
153
|
|
149
|
-
|
150
154
|
private
|
151
155
|
|
156
|
+
# rubocop:disable Metrics/MethodLength
|
157
|
+
# rubocop:disable Metrics/AbcSize
|
158
|
+
|
152
159
|
# Sends the SOAP payload to the WinRM service and returns the service's
|
153
160
|
# HTTP response.
|
154
161
|
#
|
@@ -159,8 +166,11 @@ module WinRM
|
|
159
166
|
original_length = message.length
|
160
167
|
pad_len, emsg = winrm_encrypt(message)
|
161
168
|
hdr = {
|
162
|
-
|
163
|
-
|
169
|
+
'Connection' => 'Keep-Alive',
|
170
|
+
'Content-Type' =>
|
171
|
+
'multipart/encrypted;' \
|
172
|
+
'protocol="application/HTTP-Kerberos-session-encrypted";' \
|
173
|
+
'boundary="Encrypted Boundary"'
|
164
174
|
}
|
165
175
|
|
166
176
|
body = <<-EOF
|
@@ -183,13 +193,14 @@ Content-Type: application/octet-stream\r
|
|
183
193
|
token = @gsscli.init_context
|
184
194
|
auth = Base64.strict_encode64 token
|
185
195
|
|
186
|
-
hdr = {
|
187
|
-
|
188
|
-
|
196
|
+
hdr = {
|
197
|
+
'Authorization' => "Kerberos #{auth}",
|
198
|
+
'Connection' => 'Keep-Alive',
|
199
|
+
'Content-Type' => 'application/soap+xml;charset=UTF-8'
|
189
200
|
}
|
190
|
-
@logger.debug
|
201
|
+
@logger.debug 'Sending HTTP POST for Kerberos Authentication'
|
191
202
|
r = @httpcli.post(@endpoint, '', hdr)
|
192
|
-
itok = r.header[
|
203
|
+
itok = r.header['WWW-Authenticate'].pop
|
193
204
|
itok = itok.split.last
|
194
205
|
itok = Base64.strict_decode64(itok)
|
195
206
|
@gsscli.init_context(itok)
|
@@ -202,19 +213,30 @@ Content-Type: application/octet-stream\r
|
|
202
213
|
iov = FFI::MemoryPointer.new(GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * iov_cnt)
|
203
214
|
|
204
215
|
iov0 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(FFI::Pointer.new(iov.address))
|
205
|
-
iov0[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_HEADER |
|
216
|
+
iov0[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_HEADER | \
|
217
|
+
GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_FLAG_ALLOCATE)
|
206
218
|
|
207
|
-
iov1 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(
|
219
|
+
iov1 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(
|
220
|
+
FFI::Pointer.new(iov.address + (GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * 1)))
|
208
221
|
iov1[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_DATA)
|
209
222
|
iov1[:buffer].value = str
|
210
223
|
|
211
|
-
iov2 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(
|
212
|
-
|
224
|
+
iov2 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(
|
225
|
+
FFI::Pointer.new(iov.address + (GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * 2)))
|
226
|
+
iov2[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_PADDING | \
|
227
|
+
GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_FLAG_ALLOCATE)
|
213
228
|
|
214
229
|
conf_state = FFI::MemoryPointer.new :uint32
|
215
230
|
min_stat = FFI::MemoryPointer.new :uint32
|
216
231
|
|
217
|
-
|
232
|
+
GSSAPI::LibGSSAPI.gss_wrap_iov(
|
233
|
+
min_stat,
|
234
|
+
@gsscli.context,
|
235
|
+
1,
|
236
|
+
GSSAPI::LibGSSAPI::GSS_C_QOP_DEFAULT,
|
237
|
+
conf_state,
|
238
|
+
iov,
|
239
|
+
iov_cnt)
|
218
240
|
|
219
241
|
token = [iov0[:buffer].length].pack('L')
|
220
242
|
token += iov0[:buffer].value
|
@@ -224,7 +246,6 @@ Content-Type: application/octet-stream\r
|
|
224
246
|
[pad_len, token]
|
225
247
|
end
|
226
248
|
|
227
|
-
|
228
249
|
# @return [String] the unencrypted response string
|
229
250
|
def winrm_decrypt(str)
|
230
251
|
@logger.debug "Decrypting SOAP message:\n#{str}"
|
@@ -232,18 +253,21 @@ Content-Type: application/octet-stream\r
|
|
232
253
|
iov = FFI::MemoryPointer.new(GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * iov_cnt)
|
233
254
|
|
234
255
|
iov0 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(FFI::Pointer.new(iov.address))
|
235
|
-
iov0[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_HEADER |
|
256
|
+
iov0[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_HEADER | \
|
257
|
+
GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_FLAG_ALLOCATE)
|
236
258
|
|
237
|
-
iov1 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(
|
259
|
+
iov1 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(
|
260
|
+
FFI::Pointer.new(iov.address + (GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * 1)))
|
238
261
|
iov1[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_DATA)
|
239
262
|
|
240
|
-
iov2 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(
|
263
|
+
iov2 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(
|
264
|
+
FFI::Pointer.new(iov.address + (GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * 2)))
|
241
265
|
iov2[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_DATA)
|
242
266
|
|
243
267
|
str.force_encoding('BINARY')
|
244
268
|
str.sub!(/^.*Content-Type: application\/octet-stream\r\n(.*)--Encrypted.*$/m, '\1')
|
245
269
|
|
246
|
-
len = str.unpack(
|
270
|
+
len = str.unpack('L').first
|
247
271
|
iov_data = str.unpack("LA#{len}A*")
|
248
272
|
iov0[:buffer].value = iov_data[1]
|
249
273
|
iov1[:buffer].value = iov_data[2]
|
@@ -254,13 +278,17 @@ Content-Type: application/octet-stream\r
|
|
254
278
|
qop_state = FFI::MemoryPointer.new :uint32
|
255
279
|
qop_state.write_int(0)
|
256
280
|
|
257
|
-
maj_stat = GSSAPI::LibGSSAPI.gss_unwrap_iov(
|
281
|
+
maj_stat = GSSAPI::LibGSSAPI.gss_unwrap_iov(
|
282
|
+
min_stat, @gsscli.context, conf_state, qop_state, iov, iov_cnt)
|
258
283
|
|
259
|
-
@logger.debug "SOAP message decrypted (MAJ: #{maj_stat},
|
284
|
+
@logger.debug "SOAP message decrypted (MAJ: #{maj_stat}, " \
|
285
|
+
"MIN: #{min_stat.read_int}):\n#{iov1[:buffer].value}"
|
260
286
|
|
261
287
|
iov1[:buffer].value
|
262
288
|
end
|
263
|
-
|
289
|
+
# rubocop:enable Metrics/MethodLength
|
290
|
+
# rubocop:enable Metrics/AbcSize
|
264
291
|
end
|
292
|
+
# rubocop:enable Metrics/ClassLength
|
265
293
|
end
|
266
294
|
end # WinRM
|
data/lib/winrm/output.rb
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Copyright 2014 Max Lincoln <max@devopsy.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
|
+
|
1
17
|
module WinRM
|
2
18
|
# This class holds raw output as a hash, and has convenience methods to parse.
|
3
19
|
class Output < Hash
|
data/lib/winrm/soap_provider.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
1
3
|
# Copyright 2010 Dan Wanek <dan.wanek@gmail.com>
|
2
|
-
#
|
4
|
+
#
|
3
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
6
|
# you may not use this file except in compliance with the License.
|
5
7
|
# You may obtain a copy of the License at
|
6
|
-
#
|
8
|
+
#
|
7
9
|
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
10
|
+
#
|
9
11
|
# Unless required by applicable law or agreed to in writing, software
|
10
12
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
13
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
@@ -18,18 +20,19 @@ require 'gyoku'
|
|
18
20
|
require 'uuidtools'
|
19
21
|
require 'base64'
|
20
22
|
|
23
|
+
# SOAP constants for WinRM
|
21
24
|
module WinRM
|
22
|
-
NS_SOAP_ENV ='s' # http://www.w3.org/2003/05/soap-envelope
|
23
|
-
NS_ADDRESSING ='a' # http://schemas.xmlsoap.org/ws/2004/08/addressing
|
24
|
-
NS_CIMBINDING ='b' # http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd
|
25
|
-
NS_ENUM ='n' # http://schemas.xmlsoap.org/ws/2004/09/enumeration
|
26
|
-
NS_TRANSFER ='x' # http://schemas.xmlsoap.org/ws/2004/09/transfer
|
27
|
-
NS_WSMAN_DMTF ='w' # http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
|
28
|
-
NS_WSMAN_MSFT ='p' # http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd
|
29
|
-
NS_SCHEMA_INST ='xsi' # http://www.w3.org/2001/XMLSchema-instance
|
30
|
-
NS_WIN_SHELL ='rsp' # http://schemas.microsoft.com/wbem/wsman/1/windows/shell
|
31
|
-
NS_WSMAN_FAULT = 'f'
|
32
|
-
NS_WSMAN_CONF = 'cfg'# http://schemas.microsoft.com/wbem/wsman/1/config
|
25
|
+
NS_SOAP_ENV = 's' # http://www.w3.org/2003/05/soap-envelope
|
26
|
+
NS_ADDRESSING = 'a' # http://schemas.xmlsoap.org/ws/2004/08/addressing
|
27
|
+
NS_CIMBINDING = 'b' # http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd
|
28
|
+
NS_ENUM = 'n' # http://schemas.xmlsoap.org/ws/2004/09/enumeration
|
29
|
+
NS_TRANSFER = 'x' # http://schemas.xmlsoap.org/ws/2004/09/transfer
|
30
|
+
NS_WSMAN_DMTF = 'w' # http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
|
31
|
+
NS_WSMAN_MSFT = 'p' # http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd
|
32
|
+
NS_SCHEMA_INST = 'xsi' # http://www.w3.org/2001/XMLSchema-instance
|
33
|
+
NS_WIN_SHELL = 'rsp' # http://schemas.microsoft.com/wbem/wsman/1/windows/shell
|
34
|
+
NS_WSMAN_FAULT = 'f' # http://schemas.microsoft.com/wbem/wsman/1/wsmanfault
|
35
|
+
NS_WSMAN_CONF = 'cfg' # http://schemas.microsoft.com/wbem/wsman/1/config
|
33
36
|
end
|
34
37
|
|
35
38
|
require 'winrm/exceptions/exceptions'
|
data/lib/winrm/winrm_service.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
1
3
|
# Copyright 2010 Dan Wanek <dan.wanek@gmail.com>
|
2
|
-
#
|
4
|
+
#
|
3
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
6
|
# you may not use this file except in compliance with the License.
|
5
7
|
# You may obtain a copy of the License at
|
6
|
-
#
|
8
|
+
#
|
7
9
|
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
10
|
+
#
|
9
11
|
# Unless required by applicable law or agreed to in writing, software
|
10
12
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
13
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
@@ -17,10 +19,9 @@ require 'rexml/document'
|
|
17
19
|
require_relative 'helpers/powershell_script'
|
18
20
|
|
19
21
|
module WinRM
|
20
|
-
# This is the main class that does the SOAP request/response logic. There are a few helper
|
21
|
-
#
|
22
|
+
# This is the main class that does the SOAP request/response logic. There are a few helper
|
23
|
+
# classes, but pretty much everything comes through here first.
|
22
24
|
class WinRMWebService
|
23
|
-
|
24
25
|
DEFAULT_TIMEOUT = 'PT60S'
|
25
26
|
DEFAULT_MAX_ENV_SIZE = 153600
|
26
27
|
DEFAULT_LOCALE = 'en-US'
|
@@ -249,6 +250,13 @@ module WinRM
|
|
249
250
|
output[:exitcode] = REXML::XPath.first(resp_doc, "//#{NS_WIN_SHELL}:ExitCode").text.to_i
|
250
251
|
end
|
251
252
|
output
|
253
|
+
rescue WinRMWSManFault => e
|
254
|
+
# If no output is available before the wsman:OperationTimeout expires,
|
255
|
+
# the server MUST return a WSManFault with the Code attribute equal to
|
256
|
+
# 2150858793. When the client receives this fault, it SHOULD issue
|
257
|
+
# another Receive request.
|
258
|
+
# http://msdn.microsoft.com/en-us/library/cc251676.aspx
|
259
|
+
retry if e.fault_code == '2150858793'
|
252
260
|
end
|
253
261
|
|
254
262
|
# Clean-up after a command.
|