winrm 1.3.0.dev.2 → 1.3.0.dev.3
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/.gitignore +1 -0
- data/README.md +14 -6
- data/Rakefile +3 -1
- data/VERSION +1 -1
- data/Vagrantfile +8 -0
- data/bin/rwinrm +34 -70
- data/lib/winrm/exceptions/exceptions.rb +17 -1
- data/lib/winrm/helpers/powershell_script.rb +22 -0
- data/lib/winrm/http/response_handler.rb +15 -3
- data/lib/winrm/http/transport.rb +14 -1
- data/lib/winrm/output.rb +27 -0
- data/lib/winrm/winrm_service.rb +21 -11
- data/lib/winrm.rb +1 -1
- data/spec/cmd_spec.rb +32 -0
- data/spec/config-example.yml +1 -1
- data/spec/exception_spec.rb +17 -0
- data/spec/output_spec.rb +106 -0
- data/spec/powershell_spec.rb +34 -0
- data/spec/response_handler_spec.rb +14 -0
- data/spec/stubs/responses/wmi_error_v2.xml +41 -0
- data/spec/winrm_options_spec.rb +75 -0
- data/spec/winrm_primitives_spec.rb +0 -18
- data/winrm.gemspec +1 -3
- metadata +10 -38
- data/lib/winrm/file_transfer/remote_file.rb +0 -184
- data/lib/winrm/file_transfer/remote_zip_file.rb +0 -60
- data/lib/winrm/file_transfer.rb +0 -39
- data/spec/file_transfer/remote_file_spec.rb +0 -71
- data/spec/file_transfer/remote_zip_file_spec.rb +0 -51
- data/spec/file_transfer_spec.rb +0 -39
@@ -41,4 +41,18 @@ describe 'response handler', :unit => true do
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
44
|
+
|
45
|
+
describe "failed 500 WMI error response" do
|
46
|
+
let(:wmi_error) { File.read("spec/stubs/responses/wmi_error_v2.xml") }
|
47
|
+
|
48
|
+
it 'raises a WinRMWMIError' do
|
49
|
+
handler = WinRM::ResponseHandler.new(wmi_error, 500)
|
50
|
+
begin
|
51
|
+
handler.parse_to_xml()
|
52
|
+
rescue WinRM::WinRMWMIError => e
|
53
|
+
expect(e.error_code).to eq('2150859173')
|
54
|
+
expect(e.error).to include('The WS-Management service cannot process the request.')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
44
58
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
<s:Envelope xmlns:a='http://schemas.xmlsoap.org/ws/2004/08/addressing' xmlns:e='http://schemas.xmlsoap.org/ws/2004/08/eventing' xml:lang='en-US' xmlns:n='http://schemas.xmlsoap.org/ws/2004/09/enumeration' xmlns:p='http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd' xmlns:s='http://www.w3.org/2003/05/soap-envelope' xmlns:w='http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd' xmlns:x='http://schemas.xmlsoap.org/ws/2004/09/transfer'>
|
2
|
+
<s:Header>
|
3
|
+
<a:Action>http://schemas.dmtf.org/wbem/wsman/1/wsman/fault</a:Action>
|
4
|
+
<a:MessageID>uuid:B8829021-48C3-4F27-B94B-491DAC4F29B1</a:MessageID>
|
5
|
+
<a:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:To>
|
6
|
+
</s:Header>
|
7
|
+
<s:Body>
|
8
|
+
<s:Fault>
|
9
|
+
<s:Code>
|
10
|
+
<s:Value>s:Sender</s:Value>
|
11
|
+
<s:Subcode>
|
12
|
+
<s:Value>w:QuotaLimit</s:Value>
|
13
|
+
</s:Subcode>
|
14
|
+
</s:Code>
|
15
|
+
<s:Reason>
|
16
|
+
<s:Text xml:lang='en-US'>The WS-Management service cannot process the request. The maximum number of concurrent shells for this user has been exceeded. Close existing shells or raise the quota for this user. </s:Text>
|
17
|
+
</s:Reason>
|
18
|
+
<s:Detail>
|
19
|
+
<p:MSFT_WmiError b:IsCIM_Error='true' xmlns:b='http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd' xmlns:cim='http://schemas.dmtf.org/wbem/wscim/1/common' xmlns:p='http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/MSFT_WmiError' xsi:type='p:MSFT_WmiError_Type' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
|
20
|
+
<p:CIMStatusCode xsi:type='cim:cimUnsignedInt'>27</p:CIMStatusCode>
|
21
|
+
<p:CIMStatusCodeDescription xsi:nil='true' xsi:type='cim:cimString'/>
|
22
|
+
<p:ErrorSource xsi:nil='true' xsi:type='cim:cimString'/>
|
23
|
+
<p:ErrorSourceFormat xsi:type='cim:cimUnsignedShort'>0</p:ErrorSourceFormat>
|
24
|
+
<p:ErrorType xsi:type='cim:cimUnsignedShort'>0</p:ErrorType>
|
25
|
+
<p:Message xsi:type='cim:cimString'>The WS-Management service cannot process the request. This user is allowed a maximum number of 30 concurrent shells, which has been exceeded. Close existing shells or raise the quota for this user. </p:Message>
|
26
|
+
<p:MessageID xsi:type='cim:cimString'>HRESULT 0x803381a5</p:MessageID>
|
27
|
+
<p:OtherErrorSourceFormat xsi:nil='true' xsi:type='cim:cimString'/>
|
28
|
+
<p:OtherErrorType xsi:nil='true' xsi:type='cim:cimString'/>
|
29
|
+
<p:OwningEntity xsi:nil='true' xsi:type='cim:cimString'/>
|
30
|
+
<p:PerceivedSeverity xsi:type='cim:cimUnsignedShort'>0</p:PerceivedSeverity>
|
31
|
+
<p:ProbableCause xsi:type='cim:cimUnsignedShort'>0</p:ProbableCause>
|
32
|
+
<p:ProbableCauseDescription xsi:nil='true' xsi:type='cim:cimString'/>
|
33
|
+
<p:error_Category xsi:type='cim:cimUnsignedInt'>30</p:error_Category>
|
34
|
+
<p:error_Code xsi:type='cim:cimUnsignedInt'>2150859173</p:error_Code>
|
35
|
+
<p:error_Type xsi:type='cim:cimString'>HRESULT</p:error_Type>
|
36
|
+
<p:error_WindowsErrorMessage xsi:type='cim:cimString'>The WS-Management service cannot process the request. This user is allowed a maximum number of 30 concurrent shells, which has been exceeded. Close existing shells or raise the quota for this user. </p:error_WindowsErrorMessage>
|
37
|
+
</p:MSFT_WmiError>
|
38
|
+
</s:Detail>
|
39
|
+
</s:Fault>
|
40
|
+
</s:Body>
|
41
|
+
</s:Envelope>
|
@@ -0,0 +1,75 @@
|
|
1
|
+
describe 'WinRM options', :unit => true do
|
2
|
+
let(:subject) { WinRM::WinRMWebService.new('http://localhost:55985/wsman', :plaintext) }
|
3
|
+
|
4
|
+
context 'when operations timeout is set to 60' do
|
5
|
+
before(:each) { subject.set_timeout(60) }
|
6
|
+
describe '#receive_timeout' do
|
7
|
+
it 'is set to 70s' do
|
8
|
+
transportclass = subject.instance_variable_get(:@xfer)
|
9
|
+
expect(transportclass.receive_timeout).to eql(70)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
describe '#op_timeout' do
|
13
|
+
it 'is set to 60s' do
|
14
|
+
expect(subject.timeout).to eql('PT60S')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when operations timeout is set to 30 and receive timeout is set to 120' do
|
20
|
+
before(:each) { subject.set_timeout(30, 120) }
|
21
|
+
describe '#receive_timeout' do
|
22
|
+
it 'is set to 120s' do
|
23
|
+
transportclass = subject.instance_variable_get(:@xfer)
|
24
|
+
expect(transportclass.receive_timeout).to eql(120)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
describe '#op_timeout' do
|
28
|
+
it 'is set to 30s' do
|
29
|
+
expect(subject.timeout).to eql('PT30S')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when max_env_size is set to 614400' do
|
35
|
+
before(:each) { subject.max_env_size(614400) }
|
36
|
+
describe '@max_env_sz' do
|
37
|
+
it 'is set to 614400' do
|
38
|
+
expect(subject.instance_variable_get('@max_env_sz')).to eq(614400)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when locale is set to en-CA' do
|
44
|
+
before(:each) { subject.locale('en-CA') }
|
45
|
+
describe '@locale' do
|
46
|
+
it 'is set to en-CA' do
|
47
|
+
expect(subject.instance_variable_get('@locale')).to eq('en-CA')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'default' do
|
53
|
+
describe '#receive_timeout' do
|
54
|
+
it 'should be 3600ms' do
|
55
|
+
transportclass = subject.instance_variable_get(:@xfer)
|
56
|
+
expect(transportclass.receive_timeout).to eql(3600)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
describe '#timeout' do
|
60
|
+
it 'should be 60s' do
|
61
|
+
expect(subject.timeout).to eql('PT60S')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
describe '@locale' do
|
65
|
+
it 'should be en-US' do
|
66
|
+
expect(subject.instance_variable_get('@locale')).to eq('en-US')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
describe '@max_env_sz' do
|
70
|
+
it 'should be 153600' do
|
71
|
+
expect(subject.instance_variable_get('@max_env_sz')).to eq(153600)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -49,22 +49,4 @@ describe "winrm client primitives" do
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
describe "simple values", :unit => true do
|
53
|
-
it 'should set #op_timeout' do
|
54
|
-
expect(@winrm.op_timeout(120)).to eq('PT2M0S')
|
55
|
-
expect(@winrm.op_timeout(1202)).to eq('PT20M2S')
|
56
|
-
expect(@winrm.op_timeout(86400)).to eq('PT24H0S')
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'should set #max_env_size' do
|
60
|
-
@winrm.max_env_size(153600 * 4)
|
61
|
-
expect(@winrm.instance_variable_get('@max_env_sz')).to eq(614400)
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'should set #locale' do
|
65
|
-
@winrm.locale('en-ca')
|
66
|
-
expect(@winrm.instance_variable_get('@locale')).to eq('en-ca')
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
52
|
end
|
data/winrm.gemspec
CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |s|
|
|
26
26
|
s.bindir = "bin"
|
27
27
|
s.executables = ['rwinrm']
|
28
28
|
s.required_ruby_version = '>= 1.9.0'
|
29
|
-
s.add_runtime_dependency 'gssapi', '~> 1.
|
29
|
+
s.add_runtime_dependency 'gssapi', '~> 1.2'
|
30
30
|
s.add_runtime_dependency 'httpclient', '~> 2.2', '>= 2.2.0.2'
|
31
31
|
s.add_runtime_dependency 'rubyntlm', '~> 0.4.0'
|
32
32
|
s.add_runtime_dependency 'uuidtools', '~> 2.1.2'
|
@@ -34,8 +34,6 @@ Gem::Specification.new do |s|
|
|
34
34
|
s.add_runtime_dependency 'nori', '~> 2.0'
|
35
35
|
s.add_runtime_dependency 'gyoku', '~> 1.0'
|
36
36
|
s.add_runtime_dependency 'builder', '>= 2.1.2'
|
37
|
-
s.add_runtime_dependency 'rubyzip', '~> 1.1'
|
38
|
-
s.add_runtime_dependency 'ruby-progressbar', '~> 1.6'
|
39
37
|
s.add_development_dependency 'rspec', '~> 3.0.0'
|
40
38
|
s.add_development_dependency 'rake', '~> 10.3.2'
|
41
39
|
end
|
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.3.0.dev.
|
4
|
+
version: 1.3.0.dev.3
|
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:
|
12
|
+
date: 2015-01-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: gssapi
|
@@ -17,14 +17,14 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - ~>
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: '1.
|
20
|
+
version: '1.2'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - ~>
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: '1.
|
27
|
+
version: '1.2'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: httpclient
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -135,34 +135,6 @@ dependencies:
|
|
135
135
|
- - '>='
|
136
136
|
- !ruby/object:Gem::Version
|
137
137
|
version: 2.1.2
|
138
|
-
- !ruby/object:Gem::Dependency
|
139
|
-
name: rubyzip
|
140
|
-
requirement: !ruby/object:Gem::Requirement
|
141
|
-
requirements:
|
142
|
-
- - ~>
|
143
|
-
- !ruby/object:Gem::Version
|
144
|
-
version: '1.1'
|
145
|
-
type: :runtime
|
146
|
-
prerelease: false
|
147
|
-
version_requirements: !ruby/object:Gem::Requirement
|
148
|
-
requirements:
|
149
|
-
- - ~>
|
150
|
-
- !ruby/object:Gem::Version
|
151
|
-
version: '1.1'
|
152
|
-
- !ruby/object:Gem::Dependency
|
153
|
-
name: ruby-progressbar
|
154
|
-
requirement: !ruby/object:Gem::Requirement
|
155
|
-
requirements:
|
156
|
-
- - ~>
|
157
|
-
- !ruby/object:Gem::Version
|
158
|
-
version: '1.6'
|
159
|
-
type: :runtime
|
160
|
-
prerelease: false
|
161
|
-
version_requirements: !ruby/object:Gem::Requirement
|
162
|
-
requirements:
|
163
|
-
- - ~>
|
164
|
-
- !ruby/object:Gem::Version
|
165
|
-
version: '1.6'
|
166
138
|
- !ruby/object:Gem::Dependency
|
167
139
|
name: rspec
|
168
140
|
requirement: !ruby/object:Gem::Requirement
|
@@ -211,16 +183,16 @@ files:
|
|
211
183
|
- README.md
|
212
184
|
- Rakefile
|
213
185
|
- VERSION
|
186
|
+
- Vagrantfile
|
214
187
|
- bin/rwinrm
|
215
188
|
- changelog.md
|
216
189
|
- lib/winrm.rb
|
217
190
|
- lib/winrm/exceptions/exceptions.rb
|
218
|
-
- lib/winrm/file_transfer.rb
|
219
|
-
- lib/winrm/file_transfer/remote_file.rb
|
220
|
-
- lib/winrm/file_transfer/remote_zip_file.rb
|
221
191
|
- lib/winrm/helpers/iso8601_duration.rb
|
192
|
+
- lib/winrm/helpers/powershell_script.rb
|
222
193
|
- lib/winrm/http/response_handler.rb
|
223
194
|
- lib/winrm/http/transport.rb
|
195
|
+
- lib/winrm/output.rb
|
224
196
|
- lib/winrm/soap_provider.rb
|
225
197
|
- lib/winrm/winrm_service.rb
|
226
198
|
- preamble
|
@@ -228,10 +200,8 @@ files:
|
|
228
200
|
- spec/cmd_spec.rb
|
229
201
|
- spec/config-example.yml
|
230
202
|
- spec/exception_spec.rb
|
231
|
-
- spec/file_transfer/remote_file_spec.rb
|
232
|
-
- spec/file_transfer/remote_zip_file_spec.rb
|
233
|
-
- spec/file_transfer_spec.rb
|
234
203
|
- spec/matchers.rb
|
204
|
+
- spec/output_spec.rb
|
235
205
|
- spec/powershell_spec.rb
|
236
206
|
- spec/response_handler_spec.rb
|
237
207
|
- spec/spec_helper.rb
|
@@ -239,6 +209,8 @@ files:
|
|
239
209
|
- spec/stubs/responses/open_shell_v2.xml
|
240
210
|
- spec/stubs/responses/soap_fault_v1.xml
|
241
211
|
- spec/stubs/responses/soap_fault_v2.xml
|
212
|
+
- spec/stubs/responses/wmi_error_v2.xml
|
213
|
+
- spec/winrm_options_spec.rb
|
242
214
|
- spec/winrm_primitives_spec.rb
|
243
215
|
- spec/wql_spec.rb
|
244
216
|
- winrm.gemspec
|
@@ -1,184 +0,0 @@
|
|
1
|
-
require 'io/console'
|
2
|
-
require 'json'
|
3
|
-
require 'ruby-progressbar'
|
4
|
-
|
5
|
-
module WinRM
|
6
|
-
class RemoteFile
|
7
|
-
|
8
|
-
attr_reader :local_path
|
9
|
-
attr_reader :remote_path
|
10
|
-
attr_reader :closed
|
11
|
-
attr_reader :options
|
12
|
-
|
13
|
-
def initialize(service, local_path, remote_path, opts = {})
|
14
|
-
@logger = Logging.logger[self]
|
15
|
-
@options = opts
|
16
|
-
@closed = false
|
17
|
-
@service = service
|
18
|
-
@shell = service.open_shell
|
19
|
-
@local_path = local_path
|
20
|
-
@remote_path = full_remote_path(local_path, remote_path)
|
21
|
-
@logger.debug("Creating RemoteFile of local '#{local_path}' at '#{@remote_path}'")
|
22
|
-
ensure
|
23
|
-
if !shell.nil?
|
24
|
-
ObjectSpace.define_finalizer( self, self.class.close(shell, service) )
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def upload
|
29
|
-
raise WinRMUploadFailed.new("This RemoteFile is closed.") if closed
|
30
|
-
raise WinRMUploadFailed.new("Cannot find path: '#{local_path}'") unless File.exist?(local_path)
|
31
|
-
|
32
|
-
@remote_path, should_upload = powershell_batch do | builder |
|
33
|
-
builder << resolve_remote_command
|
34
|
-
builder << is_dirty_command
|
35
|
-
end
|
36
|
-
|
37
|
-
if should_upload
|
38
|
-
size = upload_to_remote
|
39
|
-
powershell_batch {|builder| builder << create_post_upload_command}
|
40
|
-
else
|
41
|
-
size = 0
|
42
|
-
logger.debug("Files are equal. Not copying #{local_path} to #{remote_path}")
|
43
|
-
end
|
44
|
-
size
|
45
|
-
end
|
46
|
-
|
47
|
-
def close
|
48
|
-
service.close_shell(shell) unless shell.nil? or closed
|
49
|
-
@closed = true
|
50
|
-
end
|
51
|
-
|
52
|
-
protected
|
53
|
-
|
54
|
-
attr_reader :logger
|
55
|
-
attr_reader :service
|
56
|
-
attr_reader :shell
|
57
|
-
|
58
|
-
def self.close(shell_id, service)
|
59
|
-
proc { service.close_shell(shell_id) }
|
60
|
-
end
|
61
|
-
|
62
|
-
def full_remote_path(local_path, remote_path)
|
63
|
-
base_file_name = File.basename(local_path)
|
64
|
-
if File.basename(remote_path) != base_file_name
|
65
|
-
remote_path = File.join(remote_path, base_file_name)
|
66
|
-
end
|
67
|
-
remote_path
|
68
|
-
end
|
69
|
-
|
70
|
-
def resolve_remote_command
|
71
|
-
<<-EOH
|
72
|
-
$dest_file_path = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("#{remote_path}")
|
73
|
-
|
74
|
-
if (!(Test-Path $dest_file_path)) {
|
75
|
-
$dest_dir = ([System.IO.Path]::GetDirectoryName($dest_file_path))
|
76
|
-
New-Item -ItemType directory -Force -Path $dest_dir | Out-Null
|
77
|
-
}
|
78
|
-
|
79
|
-
$dest_file_path
|
80
|
-
EOH
|
81
|
-
end
|
82
|
-
|
83
|
-
def is_dirty_command
|
84
|
-
local_md5 = Digest::MD5.file(local_path).hexdigest
|
85
|
-
<<-EOH
|
86
|
-
$dest_file_path = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("#{remote_path}")
|
87
|
-
|
88
|
-
if (Test-Path $dest_file_path) {
|
89
|
-
$crypto_prov = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
|
90
|
-
try {
|
91
|
-
$file = [System.IO.File]::Open($dest_file_path,
|
92
|
-
[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)
|
93
|
-
$guest_md5 = ([System.BitConverter]::ToString($crypto_prov.ComputeHash($file)))
|
94
|
-
$guest_md5 = $guest_md5.Replace("-","").ToLower()
|
95
|
-
}
|
96
|
-
finally {
|
97
|
-
$file.Dispose()
|
98
|
-
}
|
99
|
-
if ($guest_md5 -eq '#{local_md5}') {
|
100
|
-
return $false
|
101
|
-
}
|
102
|
-
}
|
103
|
-
if(Test-Path $dest_file_path){remove-item $dest_file_path -Force}
|
104
|
-
return $true
|
105
|
-
EOH
|
106
|
-
end
|
107
|
-
|
108
|
-
def upload_to_remote
|
109
|
-
logger.debug("Uploading '#{local_path}' to temp file '#{remote_path}'")
|
110
|
-
base64_host_file = Base64.encode64(IO.binread(local_path)).gsub("\n", "")
|
111
|
-
base64_array = base64_host_file.chars.to_a
|
112
|
-
unless options[:quiet]
|
113
|
-
console_width = IO.console.winsize[1]
|
114
|
-
bar = ProgressBar.create(:title => "Copying #{File.basename(local_path)}...", :total => base64_array.count, :length => console_width-1)
|
115
|
-
end
|
116
|
-
base64_array.each_slice(8000 - remote_path.size) do |chunk|
|
117
|
-
cmd("echo #{chunk.join} >> \"#{remote_path}\"")
|
118
|
-
bar.progress += chunk.count unless options[:quiet]
|
119
|
-
end
|
120
|
-
base64_array.length
|
121
|
-
end
|
122
|
-
|
123
|
-
def decode_command
|
124
|
-
<<-EOH
|
125
|
-
$base64_string = Get-Content '#{remote_path}'
|
126
|
-
$bytes = [System.Convert]::FromBase64String($base64_string)
|
127
|
-
[System.IO.File]::WriteAllBytes('#{remote_path}', $bytes) | Out-Null
|
128
|
-
EOH
|
129
|
-
end
|
130
|
-
|
131
|
-
def create_post_upload_command
|
132
|
-
[decode_command]
|
133
|
-
end
|
134
|
-
|
135
|
-
def powershell_batch(&block)
|
136
|
-
ps_builder = []
|
137
|
-
yield ps_builder
|
138
|
-
|
139
|
-
commands = [ "$result = @{}" ]
|
140
|
-
idx = 0
|
141
|
-
ps_builder.flatten.each do |cmd_item|
|
142
|
-
commands << <<-EOH
|
143
|
-
$result.ret#{idx} = Invoke-Command { #{cmd_item} }
|
144
|
-
EOH
|
145
|
-
idx += 1
|
146
|
-
end
|
147
|
-
commands << "$(ConvertTo-Json $result)"
|
148
|
-
|
149
|
-
result = []
|
150
|
-
JSON.parse(powershell(commands.join("\n"))).each do |k,v|
|
151
|
-
result << v unless v.nil?
|
152
|
-
end
|
153
|
-
result unless result.empty?
|
154
|
-
end
|
155
|
-
|
156
|
-
def powershell(script)
|
157
|
-
script = "$ProgressPreference='SilentlyContinue';" + script
|
158
|
-
logger.debug("executing powershell script: \n#{script}")
|
159
|
-
script = script.encode('UTF-16LE', 'UTF-8')
|
160
|
-
script = Base64.strict_encode64(script)
|
161
|
-
cmd("powershell", ['-encodedCommand', script])
|
162
|
-
end
|
163
|
-
|
164
|
-
def cmd(command, arguments = [])
|
165
|
-
command_output = nil
|
166
|
-
out_stream = []
|
167
|
-
err_stream = []
|
168
|
-
service.run_command(shell, command, arguments) do |command_id|
|
169
|
-
command_output = service.get_command_output(shell, command_id) do |stdout, stderr|
|
170
|
-
out_stream << stdout if stdout
|
171
|
-
err_stream << stderr if stderr
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
if !command_output[:exitcode].zero? or !err_stream.empty?
|
176
|
-
raise WinRMUploadFailed,
|
177
|
-
:from => local_path,
|
178
|
-
:to => remote_path,
|
179
|
-
:message => command_output.inspect
|
180
|
-
end
|
181
|
-
out_stream.join.chomp
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
@@ -1,60 +0,0 @@
|
|
1
|
-
require 'zip'
|
2
|
-
|
3
|
-
module WinRM
|
4
|
-
class RemoteZipFile < RemoteFile
|
5
|
-
|
6
|
-
attr_reader :archive
|
7
|
-
|
8
|
-
def initialize(service, remote_path, opts = {})
|
9
|
-
@logger = Logging.logger[self]
|
10
|
-
@archive = create_archive(remote_path)
|
11
|
-
@unzip_remote_path = remote_path
|
12
|
-
remote_path = "$env:temp/WinRM_file_transfer"
|
13
|
-
super(service, @archive, remote_path, opts)
|
14
|
-
end
|
15
|
-
|
16
|
-
def add_file(path)
|
17
|
-
path = path.gsub("\\","/")
|
18
|
-
logger.debug("adding '#{path}' to zip file")
|
19
|
-
raise WinRMUploadFailed.new("Cannot find path: '#{path}'") unless File.exist?(path)
|
20
|
-
File.directory?(path) ? glob = File.join(path, "**/*") : glob = path
|
21
|
-
logger.debug("iterating files in '#{glob}'")
|
22
|
-
Zip::File.open(archive, 'w') do |zipfile|
|
23
|
-
Dir.glob(glob).each do |file|
|
24
|
-
logger.debug("adding zip entry for '#{file}'")
|
25
|
-
entry = Zip::Entry.new(archive, file.sub(File.dirname(path)+'/',''), nil, nil, nil, nil, nil, nil, ::Zip::DOSTime.new(2000))
|
26
|
-
zipfile.add(entry,file)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
protected
|
32
|
-
|
33
|
-
def create_post_upload_command
|
34
|
-
super << extract_zip_command
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
def create_archive(remote_path)
|
40
|
-
archive_folder = File.join(ENV['TMP'] || ENV['TMPDIR'] || '/tmp', 'WinRM_file_transfer_local')
|
41
|
-
Dir.mkdir(archive_folder) unless File.exist?(archive_folder)
|
42
|
-
archive = File.join(archive_folder,File.basename(remote_path))+'.zip'
|
43
|
-
FileUtils.rm archive, :force=>true
|
44
|
-
|
45
|
-
archive
|
46
|
-
end
|
47
|
-
|
48
|
-
def extract_zip_command
|
49
|
-
<<-EOH
|
50
|
-
$destination = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("#{@unzip_remote_path}")
|
51
|
-
$shellApplication = new-object -com shell.application
|
52
|
-
|
53
|
-
$zipPackage = $shellApplication.NameSpace('#{remote_path}')
|
54
|
-
mkdir $destination -ErrorAction SilentlyContinue | Out-Null
|
55
|
-
$destinationFolder = $shellApplication.NameSpace($destination)
|
56
|
-
$destinationFolder.CopyHere($zipPackage.Items(),0x10) | Out-Null
|
57
|
-
EOH
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
data/lib/winrm/file_transfer.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
require 'winrm/file_transfer/remote_file'
|
2
|
-
require 'winrm/file_transfer/remote_zip_file'
|
3
|
-
|
4
|
-
module WinRM
|
5
|
-
# Perform file transfer operations between a local machine and winrm endpoint
|
6
|
-
class FileTransfer
|
7
|
-
# Upload one or more local files and directories to a remote directory
|
8
|
-
# @example copy a single directory to a winrm endpoint
|
9
|
-
#
|
10
|
-
# WinRM::FileTransfer.upload(client, 'c:/dev/my_dir', '$env:AppData')
|
11
|
-
#
|
12
|
-
# @example copy several paths to the winrm endpoint
|
13
|
-
#
|
14
|
-
# WinRM::FileTransfer.upload(client, ['c:/dev/file1.txt','c:/dev/dir1'], '$env:AppData')
|
15
|
-
#
|
16
|
-
# @param [WinRM::WinRMService] a winrm service client connected to the endpoint where the remote path resides
|
17
|
-
# @param [Array<String>] One or more paths that will be copied to the remote path. These can be files or directories to be deeply copied
|
18
|
-
# @param [String] The directory on the remote endpoint to copy the local items to. This path may contain powershell style environment variables
|
19
|
-
# @option opts [String] options to be used for the copy. Currently only :quiet is supported to suppress the progress bar
|
20
|
-
# @return [Fixnum] The total number of bytes copied
|
21
|
-
def self.upload(service, local_path, remote_path, opts = {})
|
22
|
-
file = nil
|
23
|
-
local_path = [local_path] if local_path.is_a? String
|
24
|
-
|
25
|
-
if local_path.count == 1 && !File.directory?(local_path[0])
|
26
|
-
file = RemoteFile.new(service, local_path[0], remote_path, opts)
|
27
|
-
else
|
28
|
-
file = RemoteZipFile.new(service, remote_path, opts)
|
29
|
-
local_path.each do |path|
|
30
|
-
file.add_file(path)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
file.upload
|
35
|
-
ensure
|
36
|
-
file.close unless file.nil?
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
@@ -1,71 +0,0 @@
|
|
1
|
-
describe WinRM::RemoteFile, :integration => true do
|
2
|
-
|
3
|
-
let(:this_file) { __FILE__ }
|
4
|
-
let(:service) { winrm_connection }
|
5
|
-
let(:destination) {"#{ENV['temp']}/WinRM_tests"}
|
6
|
-
after {
|
7
|
-
subject.close
|
8
|
-
FileUtils.rm_rf(destination)
|
9
|
-
}
|
10
|
-
|
11
|
-
context 'Upload a new file to directory path' do
|
12
|
-
subject {WinRM::RemoteFile.new(service, this_file, destination, :quiet => true)}
|
13
|
-
|
14
|
-
it 'copies the file inside the directory' do
|
15
|
-
expect(subject.upload).to be > 0
|
16
|
-
expect(File.exist?(File.join(destination, File.basename(this_file)))).to be_truthy
|
17
|
-
end
|
18
|
-
it 'copies the exact file content' do
|
19
|
-
expect(subject.upload).to be > 0
|
20
|
-
expect(File.read(File.join(destination, File.basename(this_file)))).to eq(File.read(this_file))
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
context 'Upload an identical file to directory path' do
|
26
|
-
subject {WinRM::RemoteFile.new(service, this_file, destination, :quiet => true)}
|
27
|
-
let (:next_transfer) {WinRM::RemoteFile.new(service, this_file, destination, :quiet => true)}
|
28
|
-
|
29
|
-
it 'does not copy the file' do
|
30
|
-
expect(subject.upload).to be > 0
|
31
|
-
expect(next_transfer.upload).to be == 0
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
context 'Upload a file to file path' do
|
36
|
-
subject {WinRM::RemoteFile.new(service, this_file, File.join(destination, File.basename(this_file)), :quiet => true)}
|
37
|
-
|
38
|
-
it 'copies the file to the exact path' do
|
39
|
-
expect(subject.upload).to be > 0
|
40
|
-
expect(File.exist?(File.join(destination, File.basename(this_file)))).to be_truthy
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
context 'Upload a new file to nested directory' do
|
45
|
-
let (:nested) {File.join(destination, 'nested')}
|
46
|
-
subject {WinRM::RemoteFile.new(service, this_file, nested, :quiet => true)}
|
47
|
-
|
48
|
-
it 'copies the file to the nested path' do
|
49
|
-
expect(subject.upload).to be > 0
|
50
|
-
expect(File.exist?(File.join(nested, File.basename(this_file)))).to be_truthy
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
context 'Upload a file after RemoteFile is closed' do
|
55
|
-
subject {WinRM::RemoteFile.new(service, this_file, destination, :quiet => true)}
|
56
|
-
|
57
|
-
it 'raises WinRMUploadFailed' do
|
58
|
-
expect(subject.upload).to be > 0
|
59
|
-
subject.close
|
60
|
-
expect{subject.upload}.to raise_error(WinRM::WinRMUploadFailed)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
context 'Upload a bad path' do
|
65
|
-
subject {WinRM::RemoteFile.new(service, 'c:/some/bad/path', destination, :quiet => true)}
|
66
|
-
|
67
|
-
it 'raises WinRMUploadFailed' do
|
68
|
-
expect { subject.upload }.to raise_error(WinRM::WinRMUploadFailed)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|