winrm 1.6.0 → 1.6.1
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/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
|