winrm-elevated 1.0.0 → 1.0.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.
@@ -1,99 +1,99 @@
1
- # encoding: UTF-8
2
- #
3
- # Copyright 2015 Shawn Neal <sneal@sneal.net>
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
-
17
- require 'erubis'
18
- require 'winrm'
19
- require 'winrm-fs'
20
- require 'securerandom'
21
-
22
- module WinRM
23
- module Shells
24
- # Runs PowerShell commands elevated via a scheduled task
25
- class Elevated
26
- # Create a new elevated shell
27
- # @param connection_opts [ConnectionOpts] The WinRM connection options
28
- # @param transport [HttpTransport] The WinRM SOAP transport
29
- # @param logger [Logger] The logger to log diagnostic messages to
30
- def initialize(connection_opts, transport, logger)
31
- @logger = logger
32
- @username = connection_opts[:user]
33
- @password = connection_opts[:password]
34
- @shell = Powershell.new(connection_opts, transport, logger)
35
- @winrm_file_transporter = WinRM::FS::Core::FileTransporter.new(@shell)
36
- end
37
-
38
- # @return [String] The admin user name to execute the scheduled task as
39
- attr_accessor :username
40
-
41
- # @return [String] The admin user password
42
- attr_accessor :password
43
-
44
- # Run a command or PowerShell script elevated without any of the
45
- # restrictions that WinRM puts in place.
46
- #
47
- # @param [String] The command or PS script to wrap in a scheduled task
48
- #
49
- # @return [WinRM::Output] :stdout and :stderr
50
- def run(command, &block)
51
- # if an IO object is passed read it, otherwise assume the contents of the file were passed
52
- script_text = command.respond_to?(:read) ? command.read : command
53
-
54
- script_path = upload_elevated_shell_script(script_text)
55
- wrapped_script = wrap_in_scheduled_task(script_path, username, password)
56
- @shell.run(wrapped_script, &block)
57
- end
58
-
59
- # Closes the shell if one is open
60
- def close
61
- @shell.close
62
- end
63
-
64
- private
65
-
66
- def upload_elevated_shell_script(script_text)
67
- elevated_shell_path = 'c:/windows/temp/winrm-elevated-shell-' + SecureRandom.uuid + '.ps1'
68
- with_temp_file(script_text) do |temp_file|
69
- @winrm_file_transporter.upload(temp_file, elevated_shell_path)
70
- end
71
- elevated_shell_path
72
- end
73
-
74
- def with_temp_file(script_text)
75
- file = Tempfile.new(['winrm-elevated-shell', 'ps1'])
76
- file.write(script_text)
77
- file.write("\r\n$Host.SetShouldExit($LASTEXITCODE)")
78
- file.fsync
79
- file.close
80
- yield file.path
81
- ensure
82
- file.close
83
- file.unlink
84
- end
85
-
86
- def elevated_shell_script_content
87
- IO.read(File.expand_path('../../../winrm-elevated/scripts/elevated_shell.ps1', __FILE__))
88
- end
89
-
90
- def wrap_in_scheduled_task(script_path, username, password)
91
- Erubis::Eruby.new(elevated_shell_script_content).result(
92
- username: username,
93
- password: password,
94
- script_path: script_path
95
- )
96
- end
97
- end
98
- end
99
- end
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright 2015 Shawn Neal <sneal@sneal.net>
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'erubis'
18
+ require 'winrm'
19
+ require 'winrm-fs'
20
+ require 'securerandom'
21
+
22
+ module WinRM
23
+ module Shells
24
+ # Runs PowerShell commands elevated via a scheduled task
25
+ class Elevated
26
+ # Create a new elevated shell
27
+ # @param connection_opts [ConnectionOpts] The WinRM connection options
28
+ # @param transport [HttpTransport] The WinRM SOAP transport
29
+ # @param logger [Logger] The logger to log diagnostic messages to
30
+ def initialize(connection_opts, transport, logger)
31
+ @logger = logger
32
+ @username = connection_opts[:user]
33
+ @password = connection_opts[:password]
34
+ @shell = Powershell.new(connection_opts, transport, logger)
35
+ @winrm_file_transporter = WinRM::FS::Core::FileTransporter.new(@shell)
36
+ end
37
+
38
+ # @return [String] The admin user name to execute the scheduled task as
39
+ attr_accessor :username
40
+
41
+ # @return [String] The admin user password
42
+ attr_accessor :password
43
+
44
+ # Run a command or PowerShell script elevated without any of the
45
+ # restrictions that WinRM puts in place.
46
+ #
47
+ # @param [String] The command or PS script to wrap in a scheduled task
48
+ #
49
+ # @return [WinRM::Output] :stdout and :stderr
50
+ def run(command, &block)
51
+ # if an IO object is passed read it, otherwise assume the contents of the file were passed
52
+ script_text = command.respond_to?(:read) ? command.read : command
53
+
54
+ script_path = upload_elevated_shell_script(script_text)
55
+ wrapped_script = wrap_in_scheduled_task(script_path, username, password)
56
+ @shell.run(wrapped_script, &block)
57
+ end
58
+
59
+ # Closes the shell if one is open
60
+ def close
61
+ @shell.close
62
+ end
63
+
64
+ private
65
+
66
+ def upload_elevated_shell_script(script_text)
67
+ elevated_shell_path = 'c:/windows/temp/winrm-elevated-shell-' + SecureRandom.uuid + '.ps1'
68
+ with_temp_file(script_text) do |temp_file|
69
+ @winrm_file_transporter.upload(temp_file, elevated_shell_path)
70
+ end
71
+ elevated_shell_path
72
+ end
73
+
74
+ def with_temp_file(script_text)
75
+ file = Tempfile.new(['winrm-elevated-shell', 'ps1'])
76
+ file.write(script_text)
77
+ file.write("\r\n$Host.SetShouldExit($LASTEXITCODE)")
78
+ file.fsync
79
+ file.close
80
+ yield file.path
81
+ ensure
82
+ file.close
83
+ file.unlink
84
+ end
85
+
86
+ def elevated_shell_script_content
87
+ IO.read(File.expand_path('../../../winrm-elevated/scripts/elevated_shell.ps1', __FILE__))
88
+ end
89
+
90
+ def wrap_in_scheduled_task(script_path, username, password)
91
+ Erubis::Eruby.new(elevated_shell_script_content).result(
92
+ username: username,
93
+ password: password,
94
+ script_path: script_path
95
+ )
96
+ end
97
+ end
98
+ end
99
+ end
@@ -1,3 +1,3 @@
1
- endpoint: "http://localhost:55985/wsman"
2
- user: vagrant
3
- password: vagrant
1
+ endpoint: "http://localhost:55985/wsman"
2
+ user: vagrant
3
+ password: vagrant
@@ -1,50 +1,50 @@
1
- # encoding: UTF-8
2
- require 'rspec/expectations'
3
-
4
- # rspec matchers
5
- RSpec::Matchers.define :have_stdout_match do |expected_stdout|
6
- match do |actual_output|
7
- !expected_stdout.match(actual_output.stdout).nil?
8
- end
9
- failure_message do |actual_output|
10
- "expected that '#{actual_output.stdout}' would match #{expected_stdout}"
11
- end
12
- end
13
-
14
- RSpec::Matchers.define :have_stderr_match do |expected_stderr|
15
- match do |actual_output|
16
- !expected_stderr.match(actual_output.stderr).nil?
17
- end
18
- failure_message do |actual_output|
19
- "expected that '#{actual_output.stderr}' would match #{expected_stderr}"
20
- end
21
- end
22
-
23
- RSpec::Matchers.define :have_no_stdout do
24
- match do |actual_output|
25
- stdout = actual_output.stdout
26
- stdout == '\r\n' || stdout == ''
27
- end
28
- failure_message do |actual_output|
29
- "expected that '#{actual_output.stdout}' would have no stdout"
30
- end
31
- end
32
-
33
- RSpec::Matchers.define :have_no_stderr do
34
- match do |actual_output|
35
- stderr = actual_output.stderr
36
- stderr == '\r\n' || stderr == ''
37
- end
38
- failure_message do |actual_output|
39
- "expected that '#{actual_output.stderr}' would have no stderr"
40
- end
41
- end
42
-
43
- RSpec::Matchers.define :have_exit_code do |expected_exit_code|
44
- match do |actual_output|
45
- expected_exit_code == actual_output.exitcode
46
- end
47
- failure_message do |actual_output|
48
- "expected exit code #{expected_exit_code}, but got #{actual_output.exitcode}"
49
- end
50
- end
1
+ # encoding: UTF-8
2
+ require 'rspec/expectations'
3
+
4
+ # rspec matchers
5
+ RSpec::Matchers.define :have_stdout_match do |expected_stdout|
6
+ match do |actual_output|
7
+ !expected_stdout.match(actual_output.stdout).nil?
8
+ end
9
+ failure_message do |actual_output|
10
+ "expected that '#{actual_output.stdout}' would match #{expected_stdout}"
11
+ end
12
+ end
13
+
14
+ RSpec::Matchers.define :have_stderr_match do |expected_stderr|
15
+ match do |actual_output|
16
+ !expected_stderr.match(actual_output.stderr).nil?
17
+ end
18
+ failure_message do |actual_output|
19
+ "expected that '#{actual_output.stderr}' would match #{expected_stderr}"
20
+ end
21
+ end
22
+
23
+ RSpec::Matchers.define :have_no_stdout do
24
+ match do |actual_output|
25
+ stdout = actual_output.stdout
26
+ stdout == '\r\n' || stdout == ''
27
+ end
28
+ failure_message do |actual_output|
29
+ "expected that '#{actual_output.stdout}' would have no stdout"
30
+ end
31
+ end
32
+
33
+ RSpec::Matchers.define :have_no_stderr do
34
+ match do |actual_output|
35
+ stderr = actual_output.stderr
36
+ stderr == '\r\n' || stderr == ''
37
+ end
38
+ failure_message do |actual_output|
39
+ "expected that '#{actual_output.stderr}' would have no stderr"
40
+ end
41
+ end
42
+
43
+ RSpec::Matchers.define :have_exit_code do |expected_exit_code|
44
+ match do |actual_output|
45
+ expected_exit_code == actual_output.exitcode
46
+ end
47
+ failure_message do |actual_output|
48
+ "expected exit code #{expected_exit_code}, but got #{actual_output.exitcode}"
49
+ end
50
+ end
@@ -1,87 +1,87 @@
1
- # encoding: UTF-8
2
- describe 'powershell elevated runner', integration: true do
3
- describe 'ipconfig' do
4
- subject(:output) { elevated_shell.run('ipconfig') }
5
- it { should have_exit_code 0 }
6
- it { should have_stdout_match(/Windows IP Configuration/) }
7
- it { should have_no_stderr }
8
- end
9
-
10
- describe 'ipconfig as Service' do
11
- subject(:output) do
12
- elevated_shell.username = 'System'
13
- elevated_shell.password = nil
14
- elevated_shell.run('ipconfig')
15
- end
16
- it { should have_exit_code 0 }
17
- it { should have_stdout_match(/Windows IP Configuration/) }
18
- it { should have_no_stderr }
19
- end
20
-
21
- describe 'echo \'hello world\' using apostrophes' do
22
- subject(:output) { elevated_shell.run("echo 'hello world'") }
23
- it { should have_exit_code 0 }
24
- it { should have_stdout_match(/hello world/) }
25
- it { should have_no_stderr }
26
- end
27
-
28
- describe 'ipconfig with incorrect argument -z' do
29
- subject(:output) { elevated_shell.run('ipconfig 127.0.0.1 -z') }
30
- it { should have_exit_code 1 }
31
- end
32
-
33
- describe 'Math area calculation' do
34
- subject(:output) do
35
- cmd = <<-EOH
36
- $diameter = 4.5
37
- $area = [Math]::pow([Math]::PI * ($diameter/2), 2)
38
- Write-Host $area
39
- EOH
40
- elevated_shell.run(cmd)
41
- end
42
- it { should have_exit_code 0 }
43
- it { should have_stdout_match(/49.9648722805149/) }
44
- it { should have_no_stderr }
45
- end
46
-
47
- describe 'ipconfig with a block' do
48
- subject(:stdout) do
49
- outvar = ''
50
- elevated_shell.run('ipconfig') do |stdout, _stderr|
51
- outvar << stdout
52
- end
53
- outvar
54
- end
55
- it { should match(/Windows IP Configuration/) }
56
- end
57
-
58
- describe 'capturing output from Write-Host and Write-Error' do
59
- subject(:output) do
60
- script = <<-eos
61
- Write-Host 'Hello'
62
- $host.ui.WriteErrorLine(', world!')
63
- eos
64
-
65
- @captured_stdout = ''
66
- @captured_stderr = ''
67
- elevated_shell.run(script) do |stdout, stderr|
68
- @captured_stdout << stdout if stdout
69
- @captured_stderr << stderr if stderr
70
- end
71
- end
72
-
73
- it 'should have stdout' do
74
- expect(output.stdout).to eq("Hello\r\n")
75
- expect(output.stdout).to eq(@captured_stdout)
76
- end
77
-
78
- it 'should have stderr' do
79
- expect(output.stderr).to eq(", world!\r\n")
80
- expect(output.stderr).to eq(@captured_stderr)
81
- end
82
-
83
- it 'should have output' do
84
- expect(output.output).to eq("Hello\r\n, world!\r\n")
85
- end
86
- end
87
- end
1
+ # encoding: UTF-8
2
+ describe 'powershell elevated runner', integration: true do
3
+ describe 'ipconfig' do
4
+ subject(:output) { elevated_shell.run('ipconfig') }
5
+ it { should have_exit_code 0 }
6
+ it { should have_stdout_match(/Windows IP Configuration/) }
7
+ it { should have_no_stderr }
8
+ end
9
+
10
+ describe 'ipconfig as Service' do
11
+ subject(:output) do
12
+ elevated_shell.username = 'System'
13
+ elevated_shell.password = nil
14
+ elevated_shell.run('ipconfig')
15
+ end
16
+ it { should have_exit_code 0 }
17
+ it { should have_stdout_match(/Windows IP Configuration/) }
18
+ it { should have_no_stderr }
19
+ end
20
+
21
+ describe 'echo \'hello world\' using apostrophes' do
22
+ subject(:output) { elevated_shell.run("echo 'hello world'") }
23
+ it { should have_exit_code 0 }
24
+ it { should have_stdout_match(/hello world/) }
25
+ it { should have_no_stderr }
26
+ end
27
+
28
+ describe 'ipconfig with incorrect argument -z' do
29
+ subject(:output) { elevated_shell.run('ipconfig 127.0.0.1 -z') }
30
+ it { should have_exit_code 1 }
31
+ end
32
+
33
+ describe 'Math area calculation' do
34
+ subject(:output) do
35
+ cmd = <<-EOH
36
+ $diameter = 4.5
37
+ $area = [Math]::pow([Math]::PI * ($diameter/2), 2)
38
+ Write-Host $area
39
+ EOH
40
+ elevated_shell.run(cmd)
41
+ end
42
+ it { should have_exit_code 0 }
43
+ it { should have_stdout_match(/49.9648722805149/) }
44
+ it { should have_no_stderr }
45
+ end
46
+
47
+ describe 'ipconfig with a block' do
48
+ subject(:stdout) do
49
+ outvar = ''
50
+ elevated_shell.run('ipconfig') do |stdout, _stderr|
51
+ outvar << stdout
52
+ end
53
+ outvar
54
+ end
55
+ it { should match(/Windows IP Configuration/) }
56
+ end
57
+
58
+ describe 'capturing output from Write-Host and Write-Error' do
59
+ subject(:output) do
60
+ script = <<-eos
61
+ Write-Host 'Hello'
62
+ $host.ui.WriteErrorLine(', world!')
63
+ eos
64
+
65
+ @captured_stdout = ''
66
+ @captured_stderr = ''
67
+ elevated_shell.run(script) do |stdout, stderr|
68
+ @captured_stdout << stdout if stdout
69
+ @captured_stderr << stderr if stderr
70
+ end
71
+ end
72
+
73
+ it 'should have stdout' do
74
+ expect(output.stdout).to eq("Hello\r\n")
75
+ expect(output.stdout).to eq(@captured_stdout)
76
+ end
77
+
78
+ it 'should have stderr' do
79
+ expect(output.stderr).to eq(", world!\r\n")
80
+ expect(output.stderr).to eq(@captured_stderr)
81
+ end
82
+
83
+ it 'should have output' do
84
+ expect(output.output).to eq("Hello\r\n, world!\r\n")
85
+ end
86
+ end
87
+ end