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 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