winrm 1.6.0 → 1.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/changelog.md +3 -0
- data/lib/winrm/command_executor.rb +33 -51
- data/lib/winrm/helpers/powershell_script.rb +6 -1
- data/lib/winrm/version.rb +1 -1
- data/spec/command_executor_spec.rb +42 -53
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa96ea262bfb740bcf397684129464232f76321f
|
4
|
+
data.tar.gz: ca5894916562e3d5243c2099f8a439b10922d140
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87d111e8d6597aeb11a24dcf2a33f569426c48bd91940c25e27f461c4ca2e4d2c939eaa518f1b479e35f163700559fa152a5346c0ffd71693f3021bedeb77dfa
|
7
|
+
data.tar.gz: f349d8858850cb6f3017b67cab69fc8c843f5d188eecaec95903e7f7bedb098160babfe7fa83e58d2b77999dc23c8a0d6891617d6c4d069daf8a2c1d8c7a2fe4
|
data/changelog.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# WinRM Gem Changelog
|
2
2
|
|
3
|
+
# 1.6.1
|
4
|
+
- Use codepage 437 by default on os versions older than Windows 7 and Windows Server 2008 R2
|
5
|
+
|
3
6
|
# 1.6.0
|
4
7
|
- Adding `:negotiate` transport providing NTLM/Negotiate encryption of WinRM requests and responses
|
5
8
|
- Removed dependency on UUIDTools gem
|
@@ -35,11 +35,6 @@ module WinRM
|
|
35
35
|
proc { service.close_shell(shell_id) }
|
36
36
|
end
|
37
37
|
|
38
|
-
# @return [Integer,nil] the safe maximum number of commands that can
|
39
|
-
# be executed in one remote shell session, or `nil` if the
|
40
|
-
# threshold has not yet been determined
|
41
|
-
attr_reader :max_commands
|
42
|
-
|
43
38
|
# @return [WinRM::WinRMWebService] a WinRM web service object
|
44
39
|
attr_reader :service
|
45
40
|
|
@@ -53,7 +48,6 @@ module WinRM
|
|
53
48
|
# responds to `#debug` and `#info` (default: `nil`)
|
54
49
|
def initialize(service)
|
55
50
|
@service = service
|
56
|
-
@logger = service.logger
|
57
51
|
@command_count = 0
|
58
52
|
end
|
59
53
|
|
@@ -74,10 +68,11 @@ module WinRM
|
|
74
68
|
# @return [String] the remote shell session indentifier
|
75
69
|
def open
|
76
70
|
close
|
77
|
-
retryable(service.retry_limit, service.retry_delay)
|
71
|
+
retryable(service.retry_limit, service.retry_delay) do
|
72
|
+
@shell = service.open_shell(codepage: code_page)
|
73
|
+
end
|
78
74
|
add_finalizer(shell)
|
79
75
|
@command_count = 0
|
80
|
-
determine_max_commands unless max_commands
|
81
76
|
shell
|
82
77
|
end
|
83
78
|
|
@@ -91,7 +86,7 @@ module WinRM
|
|
91
86
|
# @return [WinRM::Output] output object with stdout, stderr, and
|
92
87
|
# exit code
|
93
88
|
def run_cmd(command, arguments = [], &block)
|
94
|
-
reset if
|
89
|
+
reset if command_count > max_commands
|
95
90
|
ensure_open_shell!
|
96
91
|
|
97
92
|
@command_count += 1
|
@@ -120,39 +115,34 @@ module WinRM
|
|
120
115
|
[
|
121
116
|
'-encodedCommand',
|
122
117
|
::WinRM::PowershellScript.new(
|
123
|
-
|
118
|
+
script_file.is_a?(IO) ? script_file.read : script_file
|
124
119
|
).encoded
|
125
120
|
],
|
126
121
|
&block
|
127
122
|
)
|
128
123
|
end
|
129
124
|
|
130
|
-
|
131
|
-
|
132
|
-
#
|
133
|
-
#
|
134
|
-
|
135
|
-
|
125
|
+
# Code page appropriate to os version. utf-8 (65001) is buggy pre win7/2k8r2
|
126
|
+
# So send MS-DOS (437) for earlier versions
|
127
|
+
#
|
128
|
+
# @return [Integer] code page in use
|
129
|
+
def code_page
|
130
|
+
@code_page ||= os_version < '6.1' ? 437 : 65_001
|
131
|
+
end
|
136
132
|
|
137
|
-
# @return [Integer] the
|
138
|
-
# executed in one remote shell session
|
139
|
-
|
140
|
-
|
133
|
+
# @return [Integer] the safe maximum number of commands that can
|
134
|
+
# be executed in one remote shell session
|
135
|
+
def max_commands
|
136
|
+
@max_commands ||= (os_version < '6.2' ? 15 : 1500) - 2
|
137
|
+
end
|
141
138
|
|
142
|
-
|
143
|
-
# of Windows
|
144
|
-
# @api private
|
145
|
-
PS1_OS_VERSION = '[environment]::OSVersion.Version.tostring()'.freeze
|
139
|
+
private
|
146
140
|
|
147
141
|
# @return [Integer] the number of executed commands on the remote
|
148
142
|
# shell session
|
149
143
|
# @api private
|
150
144
|
attr_accessor :command_count
|
151
145
|
|
152
|
-
# @return [#debug,#info] the logger
|
153
|
-
# @api private
|
154
|
-
attr_reader :logger
|
155
|
-
|
156
146
|
# Creates a finalizer for this connection which will close the open
|
157
147
|
# remote shell session when the object is garabage collected or on
|
158
148
|
# Ruby VM shutdown.
|
@@ -163,13 +153,6 @@ module WinRM
|
|
163
153
|
ObjectSpace.define_finalizer(self, self.class.finalize(shell_id, service))
|
164
154
|
end
|
165
155
|
|
166
|
-
# @return [true,false] whether or not the number of exeecuted commands
|
167
|
-
# have exceeded the maxiumum threshold
|
168
|
-
# @api private
|
169
|
-
def command_count_exceeded?
|
170
|
-
command_count > max_commands.to_i
|
171
|
-
end
|
172
|
-
|
173
156
|
# Ensures that there is an open remote shell session.
|
174
157
|
#
|
175
158
|
# @raise [WinRM::WinRMError] if there is no open shell
|
@@ -179,14 +162,19 @@ module WinRM
|
|
179
162
|
'before any run methods are invoked' if shell.nil?
|
180
163
|
end
|
181
164
|
|
182
|
-
#
|
183
|
-
# on a remote shell session by interrogating the remote host.
|
165
|
+
# Fetches the OS build bersion of the remote endpoint
|
184
166
|
#
|
185
167
|
# @api private
|
186
|
-
def
|
187
|
-
os_version
|
188
|
-
|
189
|
-
|
168
|
+
def os_version
|
169
|
+
@os_version ||= begin
|
170
|
+
version = nil
|
171
|
+
wql = service.run_wql('select version from Win32_OperatingSystem')
|
172
|
+
if wql[:xml_fragment]
|
173
|
+
version = wql[:xml_fragment].first[:version] if wql[:xml_fragment].first[:version]
|
174
|
+
end
|
175
|
+
fail ::WinRM::WinRMError, 'Unable to determine endpoint os version' if version.nil?
|
176
|
+
version
|
177
|
+
end
|
190
178
|
end
|
191
179
|
|
192
180
|
# Removes any finalizers for this connection.
|
@@ -200,7 +188,7 @@ module WinRM
|
|
200
188
|
#
|
201
189
|
# @api private
|
202
190
|
def reset
|
203
|
-
logger.debug("Resetting WinRM shell (Max command limit is #{max_commands})")
|
191
|
+
service.logger.debug("Resetting WinRM shell (Max command limit is #{max_commands})")
|
204
192
|
open
|
205
193
|
end
|
206
194
|
|
@@ -215,11 +203,11 @@ module WinRM
|
|
215
203
|
yield
|
216
204
|
rescue *RESCUE_EXCEPTIONS_ON_ESTABLISH.call => e
|
217
205
|
if (retries -= 1) > 0
|
218
|
-
logger.info("[WinRM] connection failed. retrying in #{delay} seconds
|
206
|
+
service.logger.info("[WinRM] connection failed. retrying in #{delay} seconds: #{e.inspect}")
|
219
207
|
sleep(delay)
|
220
208
|
retry
|
221
209
|
else
|
222
|
-
logger.warn("[WinRM] connection failed, terminating (#{e.inspect})")
|
210
|
+
service.logger.warn("[WinRM] connection failed, terminating (#{e.inspect})")
|
223
211
|
raise
|
224
212
|
end
|
225
213
|
end
|
@@ -229,14 +217,8 @@ module WinRM
|
|
229
217
|
Errno::EACCES, Errno::EADDRINUSE, Errno::ECONNREFUSED, Errno::ETIMEDOUT,
|
230
218
|
Errno::ECONNRESET, Errno::ENETUNREACH, Errno::EHOSTUNREACH,
|
231
219
|
::WinRM::WinRMHTTPTransportError, ::WinRM::WinRMAuthorizationError,
|
232
|
-
HTTPClient::KeepAliveDisconnected,
|
233
|
-
HTTPClient::ConnectTimeoutError
|
220
|
+
HTTPClient::KeepAliveDisconnected, HTTPClient::ConnectTimeoutError
|
234
221
|
].freeze
|
235
222
|
end
|
236
|
-
|
237
|
-
# suppress the progress stream from leaking to stderr
|
238
|
-
def safe_script(script)
|
239
|
-
"$ProgressPreference='SilentlyContinue';" + script
|
240
|
-
end
|
241
223
|
end
|
242
224
|
end
|
@@ -30,8 +30,13 @@ module WinRM
|
|
30
30
|
# --EncodedCommand argument.
|
31
31
|
# @return [String] The UTF-16LE base64 encoded script
|
32
32
|
def encoded
|
33
|
-
encoded_script = text.encode('UTF-16LE', 'UTF-8')
|
33
|
+
encoded_script = safe_script(text).encode('UTF-16LE', 'UTF-8')
|
34
34
|
Base64.strict_encode64(encoded_script)
|
35
35
|
end
|
36
|
+
|
37
|
+
# suppress the progress stream from leaking to stderr
|
38
|
+
def safe_script(script)
|
39
|
+
"$ProgressPreference='SilentlyContinue';" + script
|
40
|
+
end
|
36
41
|
end
|
37
42
|
end
|
data/lib/winrm/version.rb
CHANGED
@@ -35,21 +35,11 @@ describe WinRM::CommandExecutor, unit: true do
|
|
35
35
|
)
|
36
36
|
end
|
37
37
|
|
38
|
-
let(:version_output)
|
39
|
-
o = ::WinRM::Output.new
|
40
|
-
o[:exitcode] = 0
|
41
|
-
o[:data].concat([{ stdout: '6.3.9600.0\r\n' }])
|
42
|
-
o
|
43
|
-
end
|
38
|
+
let(:version_output) { { xml_fragment: [{ version: '6.3.9600' }] } }
|
44
39
|
|
45
40
|
before do
|
46
41
|
allow(service).to receive(:open_shell).and_return(shell_id)
|
47
|
-
|
48
|
-
stub_powershell_script(
|
49
|
-
shell_id,
|
50
|
-
"$ProgressPreference='SilentlyContinue';[environment]::OSVersion.Version.tostring()",
|
51
|
-
version_output
|
52
|
-
)
|
42
|
+
allow(service).to receive(:run_wql).and_return(version_output)
|
53
43
|
end
|
54
44
|
|
55
45
|
describe '#close' do
|
@@ -124,35 +114,50 @@ describe WinRM::CommandExecutor, unit: true do
|
|
124
114
|
end
|
125
115
|
|
126
116
|
describe 'for modern windows distributions' do
|
127
|
-
let(:version_output)
|
128
|
-
o = ::WinRM::Output.new
|
129
|
-
o[:exitcode] = 0
|
130
|
-
o[:data].concat([{ stdout: '6.3.9600.0\r\n' }])
|
131
|
-
o
|
132
|
-
end
|
117
|
+
let(:version_output) { { xml_fragment: [{ version: '6.3.9600' }] } }
|
133
118
|
|
134
119
|
it 'sets #max_commands to 1500 - 2' do
|
135
|
-
expect(executor.max_commands).to eq nil
|
136
|
-
executor.open
|
137
|
-
|
138
120
|
expect(executor.max_commands).to eq(1500 - 2)
|
139
121
|
end
|
122
|
+
|
123
|
+
it 'sets code_page to UTF-8' do
|
124
|
+
expect(executor.code_page).to eq 65_001
|
125
|
+
end
|
140
126
|
end
|
141
127
|
|
142
128
|
describe 'for older/legacy windows distributions' do
|
143
|
-
let(:version_output)
|
144
|
-
o = ::WinRM::Output.new
|
145
|
-
o[:exitcode] = 0
|
146
|
-
o[:data].concat([{ stdout: '6.1.8500.0\r\n' }])
|
147
|
-
o
|
148
|
-
end
|
129
|
+
let(:version_output) { { xml_fragment: [{ version: '6.1.8500' }] } }
|
149
130
|
|
150
131
|
it 'sets #max_commands to 15 - 2' do
|
151
|
-
expect(executor.max_commands).to eq
|
152
|
-
|
132
|
+
expect(executor.max_commands).to eq(15 - 2)
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'sets code_page to UTF-8' do
|
136
|
+
expect(executor.code_page).to eq 65_001
|
137
|
+
end
|
138
|
+
end
|
153
139
|
|
140
|
+
describe 'for super duper older/legacy windows distributions' do
|
141
|
+
let(:version_output) { { xml_fragment: [{ version: '6.0.8500' }] } }
|
142
|
+
|
143
|
+
it 'sets #max_commands to 15 - 2' do
|
154
144
|
expect(executor.max_commands).to eq(15 - 2)
|
155
145
|
end
|
146
|
+
|
147
|
+
it 'sets code_page to MS-DOS' do
|
148
|
+
expect(executor.code_page).to eq 437
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe 'when unable to find os version' do
|
153
|
+
let(:version_output) { { xml_fragment: [{ funny_clowns: 'haha' }] } }
|
154
|
+
|
155
|
+
it 'raises WinRMError' do
|
156
|
+
expect { executor.code_page }.to raise_error(
|
157
|
+
::WinRM::WinRMError,
|
158
|
+
'Unable to determine endpoint os version'
|
159
|
+
)
|
160
|
+
end
|
156
161
|
end
|
157
162
|
end
|
158
163
|
|
@@ -232,12 +237,7 @@ describe WinRM::CommandExecutor, unit: true do
|
|
232
237
|
describe 'when called many times over time' do
|
233
238
|
# use a 'old' version of windows with lower max_commands threshold
|
234
239
|
# to trigger quicker shell recyles
|
235
|
-
let(:version_output)
|
236
|
-
o = ::WinRM::Output.new
|
237
|
-
o[:exitcode] = 0
|
238
|
-
o[:data].concat([{ stdout: '6.1.8500.0\r\n' }])
|
239
|
-
o
|
240
|
-
end
|
240
|
+
let(:version_output) { { xml_fragment: [{ version: '6.1.8500' }] } }
|
241
241
|
|
242
242
|
let(:echo_output) do
|
243
243
|
o = ::WinRM::Output.new
|
@@ -251,11 +251,8 @@ describe WinRM::CommandExecutor, unit: true do
|
|
251
251
|
allow(service).to receive(:close_shell)
|
252
252
|
allow(service).to receive(:run_command).and_yield('command-xxx')
|
253
253
|
allow(service).to receive(:get_command_output).and_return(echo_output)
|
254
|
-
|
255
|
-
|
256
|
-
"$ProgressPreference='SilentlyContinue';[environment]::OSVersion.Version.tostring()",
|
257
|
-
version_output
|
258
|
-
)
|
254
|
+
allow(service).to receive(:run_wql).with('select version from Win32_OperatingSystem')
|
255
|
+
.and_return(version_output)
|
259
256
|
end
|
260
257
|
|
261
258
|
it 'resets the shell when #max_commands threshold is tripped' do
|
@@ -295,7 +292,7 @@ describe WinRM::CommandExecutor, unit: true do
|
|
295
292
|
before do
|
296
293
|
stub_powershell_script(
|
297
294
|
shell_id,
|
298
|
-
|
295
|
+
'echo Hello',
|
299
296
|
echo_output,
|
300
297
|
command_id
|
301
298
|
)
|
@@ -309,7 +306,7 @@ describe WinRM::CommandExecutor, unit: true do
|
|
309
306
|
'powershell',
|
310
307
|
[
|
311
308
|
'-encodedCommand',
|
312
|
-
::WinRM::PowershellScript.new(
|
309
|
+
::WinRM::PowershellScript.new('echo Hello')
|
313
310
|
.encoded
|
314
311
|
]
|
315
312
|
)
|
@@ -353,12 +350,7 @@ describe WinRM::CommandExecutor, unit: true do
|
|
353
350
|
describe 'when called many times over time' do
|
354
351
|
# use a 'old' version of windows with lower max_commands threshold
|
355
352
|
# to trigger quicker shell recyles
|
356
|
-
let(:version_output)
|
357
|
-
o = ::WinRM::Output.new
|
358
|
-
o[:exitcode] = 0
|
359
|
-
o[:data].concat([{ stdout: '6.1.8500.0\r\n' }])
|
360
|
-
o
|
361
|
-
end
|
353
|
+
let(:version_output) { { xml_fragment: [{ version: '6.1.8500' }] } }
|
362
354
|
|
363
355
|
let(:echo_output) do
|
364
356
|
o = ::WinRM::Output.new
|
@@ -372,11 +364,8 @@ describe WinRM::CommandExecutor, unit: true do
|
|
372
364
|
allow(service).to receive(:close_shell)
|
373
365
|
allow(service).to receive(:run_command).and_yield('command-xxx')
|
374
366
|
allow(service).to receive(:get_command_output).and_return(echo_output)
|
375
|
-
|
376
|
-
|
377
|
-
"$ProgressPreference='SilentlyContinue';[environment]::OSVersion.Version.tostring()",
|
378
|
-
version_output
|
379
|
-
)
|
367
|
+
allow(service).to receive(:wsman_identify).with('select version from Win32_OperatingSystem')
|
368
|
+
.and_return(version_output)
|
380
369
|
end
|
381
370
|
|
382
371
|
it 'resets the shell when #max_commands threshold is tripped' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: winrm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.6.
|
4
|
+
version: 1.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Wanek
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-02-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: gssapi
|