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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bc4d15623138a5d39c308936ad8e6738621317c0
4
- data.tar.gz: 64064ba319d3d5d856ba346a383823ccd0054f40
3
+ metadata.gz: aa96ea262bfb740bcf397684129464232f76321f
4
+ data.tar.gz: ca5894916562e3d5243c2099f8a439b10922d140
5
5
  SHA512:
6
- metadata.gz: dab6833383b786a008734ef928a4f7ed2346b912f6e342fde139053053bede56296e097f17726e801b5ef7d0023ba9ee8b373ff7b5d545e78564c6ff13900f94
7
- data.tar.gz: 5c7c43892944ed073c2cc66a6bf590e4164e052c6b6d596dec684408dd11594d3da8ea275f39d724d197571ce746ce65378a2e1f9a6394bae4955f4c09ed1efd
6
+ metadata.gz: 87d111e8d6597aeb11a24dcf2a33f569426c48bd91940c25e27f461c4ca2e4d2c939eaa518f1b479e35f163700559fa152a5346c0ffd71693f3021bedeb77dfa
7
+ data.tar.gz: f349d8858850cb6f3017b67cab69fc8c843f5d188eecaec95903e7f7bedb098160babfe7fa83e58d2b77999dc23c8a0d6891617d6c4d069daf8a2c1d8c7a2fe4
@@ -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) { @shell = service.open_shell }
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 command_count_exceeded?
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
- safe_script(script_file.is_a?(IO) ? script_file.read : script_file)
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
- private
131
-
132
- # @return [Integer] the default maximum number of commands which can be
133
- # executed in one remote shell session on "older" versions of Windows
134
- # @api private
135
- LEGACY_LIMIT = 15
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 default maximum number of commands which can be
138
- # executed in one remote shell session on "modern" versions of Windows
139
- # @api private
140
- MODERN_LIMIT = 1500
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
- # @return [String] the PowerShell command used to determine the version
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
- # Determines the safe maximum number of commands that can be executed
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 determine_max_commands
187
- os_version = run_powershell_script(PS1_OS_VERSION).stdout.chomp
188
- @max_commands = os_version < '6.2' ? LEGACY_LIMIT : MODERN_LIMIT
189
- @max_commands -= 2 # to be safe
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 (#{e.inspect})")
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
@@ -3,5 +3,5 @@
3
3
  # WinRM module
4
4
  module WinRM
5
5
  # The version of the WinRM library
6
- VERSION = '1.6.0'
6
+ VERSION = '1.6.1'
7
7
  end
@@ -35,21 +35,11 @@ describe WinRM::CommandExecutor, unit: true do
35
35
  )
36
36
  end
37
37
 
38
- let(:version_output) do
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) do
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) do
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 nil
152
- executor.open
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) do
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
- stub_powershell_script(
255
- 's1',
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
- "$ProgressPreference='SilentlyContinue';echo Hello",
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("$ProgressPreference='SilentlyContinue';echo Hello")
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) do
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
- stub_powershell_script(
376
- 's1',
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.0
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-01-22 00:00:00.000000000 Z
12
+ date: 2016-02-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: gssapi