winrm-elevated 0.4.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,82 +1,86 @@
1
- # Runs PowerShell commands as elevated over Windows Remote Management (WinRM) via a scheduled task
2
- [![Gem Version](https://badge.fury.io/rb/winrm-elevated.svg)](http://badge.fury.io/rb/winrm-elevated)
3
-
4
- This gem allows you to break out of the magical WinRM constraints thus allowing to reach out to network shares and even install Windows updates, .NET, SQL Server etc.
5
-
6
- ## Running commands elevated
7
- ```ruby
8
- require 'winrm'
9
- require 'winrm-elevated'
10
-
11
- service = WinRM::WinRMWebService.new(...
12
- service.create_executor do |executor|
13
- elevated_runner = WinRM::Elevated::Runner.new(executor)
14
- result = elevated_runner.powershell_elevated('dir', 'Administrator', 'password')
15
- puts "Std out: #{result.output}"
16
- end
17
- ```
18
-
19
- ### Impersonating a service account
20
- By passing a `nil` password, winrm-elevated will assume that the command should run as a service account:
21
- ```ruby
22
- require 'winrm'
23
- require 'winrm-elevated'
24
-
25
- service = WinRM::WinRMWebService.new(...
26
- service.create_executor do |executor|
27
- elevated_runner = WinRM::Elevated::Runner.new(service)
28
- result = elevated_runner.powershell_elevated('dir', 'System', nil)
29
- puts "Std out: #{result.output}"
30
- end
31
- ```
32
-
33
- ## How does it work?
34
-
35
- The gem works by creating a new logon session local to the Windows box by using a scheduled task. After this point WinRM is just used to read output from the scheduled task via a log file.
36
-
37
- 1. The command you'd like to run outside the WinRM context is encoded and placed inside the PowerShell script elevated_shell.ps1.
38
- 2. The script is uploaded to the machine over WinRM.
39
- 3. The script is executed over WinRM and the script does the following:
40
- 1. Scheduled task is created which will execute your command and redirect stdout and stderr to a location known by elevated_shell.ps1.
41
- 2. The scheduled task is executed.
42
- 3. elevated_shell.ps1 polls the stdout and stderr log files and writes them back to WinRM. The script continues in this loop until the scheduled task is complete.
43
-
44
- ## Troubleshooting
45
-
46
- If you're having trouble, first of all its most likely a network or WinRM configuration
47
- issue. Take a look at the [WinRM gem troubleshooting](https://github.com/WinRb/WinRM#troubleshooting)
48
- first.
49
-
50
- ## Contributing
51
-
52
- 1. Fork it.
53
- 2. Create a branch (git checkout -b my_feature_branch)
54
- 3. Run the unit and integration tests (bundle exec rake integration)
55
- 4. Commit your changes (git commit -am "Added a sweet feature")
56
- 5. Push to the branch (git push origin my_feature_branch)
57
- 6. Create a pull requst from your branch into master (Please be sure to provide enough detail for us to cipher what this change is doing)
58
-
59
- ### Running the tests
60
-
61
- We use Bundler to manage dependencies during development.
62
-
63
- ```
64
- $ bundle install
65
- ```
66
-
67
- Once you have the dependencies, you can run the unit tests with `rake`:
68
-
69
- ```
70
- $ bundle exec rake spec
71
- ```
72
-
73
- To run the integration tests you will need a Windows box with the WinRM service properly configured. Its easiest to use the Vagrant Windows box in the Vagrantilfe of this repo.
74
-
75
- 1. Create a Windows VM with WinRM configured (see above).
76
- 2. Copy the config-example.yml to config.yml - edit this file with your WinRM connection details.
77
- 3. Run `bundle exec rake integration`
78
-
79
- ## WinRM-elevated Authors
80
- * Shawn Neal (https://github.com/sneal)
81
-
82
- [Contributors](https://github.com/WinRb/winrm-elevated/graphs/contributors)
1
+ # Runs PowerShell commands as elevated over Windows Remote Management (WinRM) via a scheduled task
2
+ [![Gem Version](https://badge.fury.io/rb/winrm-elevated.svg)](http://badge.fury.io/rb/winrm-elevated)
3
+
4
+ This gem allows you to break out of the magical WinRM constraints thus allowing to reach out to network shares and even install Windows updates, .NET, SQL Server etc.
5
+
6
+ ## Running commands elevated
7
+ ```ruby
8
+ require 'winrm'
9
+ require 'winrm-elevated'
10
+
11
+ conn = WinRM::Connection.new(...
12
+ conn.shell(:elevated) do |shell|
13
+ shell.run('$PSVersionTable') do |stdout, stderr|
14
+ STDOUT.print stdout
15
+ STDERR.print stderr
16
+ end
17
+ end
18
+ ```
19
+
20
+ ### Impersonating a service account
21
+ By passing a `nil` password, winrm-elevated will assume that the command should run as a service account:
22
+ ```ruby
23
+ require 'winrm'
24
+ require 'winrm-elevated'
25
+
26
+ conn = WinRM::Connection.new(...
27
+ conn.shell(:elevated) do |shell|
28
+ shell.username = 'System'
29
+ shell.password = nil
30
+ shell.run('$PSVersionTable') do |stdout, stderr|
31
+ STDOUT.print stdout
32
+ STDERR.print stderr
33
+ end
34
+ end
35
+ ```
36
+
37
+ ## How does it work?
38
+
39
+ The gem works by creating a new logon session local to the Windows box by using a scheduled task. After this point WinRM is just used to read output from the scheduled task via a log file.
40
+
41
+ 1. The command you'd like to run outside the WinRM context is saved to a temporary file.
42
+ 2. This file is uploaded to the machine over WinRM.
43
+ 3. A script is executed over WinRM and does the following:
44
+ 1. Scheduled task is created which will execute your command and redirect stdout and stderr to a location known by elevated_shell.ps1.
45
+ 2. The scheduled task is executed.
46
+ 3. elevated_shell.ps1 polls the stdout and stderr log files and writes them back to WinRM. The script continues in this loop until the scheduled task is complete.
47
+
48
+ ## Troubleshooting
49
+
50
+ If you're having trouble, first of all its most likely a network or WinRM configuration
51
+ issue. Take a look at the [WinRM gem troubleshooting](https://github.com/WinRb/WinRM#troubleshooting)
52
+ first.
53
+
54
+ ## Contributing
55
+
56
+ 1. Fork it.
57
+ 2. Create a branch (git checkout -b my_feature_branch)
58
+ 3. Run the unit and integration tests (bundle exec rake integration)
59
+ 4. Commit your changes (git commit -am "Added a sweet feature")
60
+ 5. Push to the branch (git push origin my_feature_branch)
61
+ 6. Create a pull requst from your branch into master (Please be sure to provide enough detail for us to cipher what this change is doing)
62
+
63
+ ### Running the tests
64
+
65
+ We use Bundler to manage dependencies during development.
66
+
67
+ ```
68
+ $ bundle install
69
+ ```
70
+
71
+ Once you have the dependencies, you can run the unit tests with `rake`:
72
+
73
+ ```
74
+ $ bundle exec rake spec
75
+ ```
76
+
77
+ To run the integration tests you will need a Windows box with the WinRM service properly configured. Its easiest to use the Vagrant Windows box in the Vagrantilfe of this repo.
78
+
79
+ 1. Create a Windows VM with WinRM configured (see above).
80
+ 2. Copy the config-example.yml to config.yml - edit this file with your WinRM connection details.
81
+ 3. Run `bundle exec rake integration`
82
+
83
+ ## WinRM-elevated Authors
84
+ * Shawn Neal (https://github.com/sneal)
85
+
86
+ [Contributors](https://github.com/WinRb/winrm-elevated/graphs/contributors)
data/Rakefile CHANGED
@@ -1,28 +1,28 @@
1
- # encoding: UTF-8
2
- require 'rubygems'
3
- require 'bundler/setup'
4
- require 'rspec/core/rake_task'
5
- require 'rubocop/rake_task'
6
- require 'bundler/gem_tasks'
7
-
8
- # Change to the directory of this file.
9
- Dir.chdir(File.expand_path('../', __FILE__))
10
-
11
- RSpec::Core::RakeTask.new(:spec) do |task|
12
- task.pattern = 'spec/*_spec.rb'
13
- task.rspec_opts = ['--color', '-f documentation']
14
- task.rspec_opts << '-tunit'
15
- end
16
-
17
- # Run the integration test suite
18
- RSpec::Core::RakeTask.new(:integration) do |task|
19
- task.pattern = 'spec/*_spec.rb'
20
- task.rspec_opts = ['--color', '-f documentation']
21
- task.rspec_opts << '-tintegration'
22
- end
23
-
24
- RuboCop::RakeTask.new
25
-
26
- task default: [:spec, :rubocop]
27
-
28
- task all: [:default, :integration]
1
+ # encoding: UTF-8
2
+ require 'rubygems'
3
+ require 'bundler/setup'
4
+ require 'rspec/core/rake_task'
5
+ require 'rubocop/rake_task'
6
+ require 'bundler/gem_tasks'
7
+
8
+ # Change to the directory of this file.
9
+ Dir.chdir(File.expand_path('../', __FILE__))
10
+
11
+ RSpec::Core::RakeTask.new(:spec) do |task|
12
+ task.pattern = 'spec/*_spec.rb'
13
+ task.rspec_opts = ['--color', '-f documentation']
14
+ task.rspec_opts << '-tunit'
15
+ end
16
+
17
+ # Run the integration test suite
18
+ RSpec::Core::RakeTask.new(:integration) do |task|
19
+ task.pattern = 'spec/*_spec.rb'
20
+ task.rspec_opts = ['--color', '-f documentation']
21
+ task.rspec_opts << '-tintegration'
22
+ end
23
+
24
+ RuboCop::RakeTask.new
25
+
26
+ task default: [:spec, :rubocop]
27
+
28
+ task all: [:default, :integration]
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.0
1
+ 1.0.0
data/appveyor.yml CHANGED
@@ -1,39 +1,39 @@
1
- version: "master-{build}"
2
-
3
- os: Windows Server 2012 R2
4
- platform:
5
- - x64
6
-
7
- environment:
8
- winrm_user: test_user
9
- winrm_pass: Pass@word1
10
-
11
- matrix:
12
- - ruby_version: "21"
13
- winrm_endpoint: http://localhost:5985/wsman
14
-
15
- clone_folder: c:\projects\winrm-elevated
16
- clone_depth: 1
17
- branches:
18
- only:
19
- - master
20
-
21
- install:
22
- - ps: net user /add $env:winrm_user $env:winrm_pass
23
- - ps: net localgroup administrators $env:winrm_user /add
24
- - ps: winrm set winrm/config/client/auth '@{Basic="true"}'
25
- - ps: winrm set winrm/config/service/auth '@{Basic="true"}'
26
- - ps: winrm set winrm/config/service '@{AllowUnencrypted="true"}'
27
- - ps: $env:PATH="C:\Ruby$env:ruby_version\bin;$env:PATH"
28
- - ps: Write-Host $env:PATH
29
- - ps: ruby --version
30
- - ps: gem --version
31
- - ps: gem install bundler --quiet --no-ri --no-rdoc
32
- - ps: bundler --version
33
-
34
- build_script:
35
- - bundle install || bundle install || bundle install
36
-
37
- test_script:
38
- - SET SPEC_OPTS=--format progress
39
- - bundle exec rake integration
1
+ version: "master-{build}"
2
+
3
+ os: Windows Server 2012 R2
4
+ platform:
5
+ - x64
6
+
7
+ environment:
8
+ winrm_user: test_user
9
+ winrm_password: Pass@word1
10
+
11
+ matrix:
12
+ - ruby_version: "21"
13
+ winrm_endpoint: http://localhost:5985/wsman
14
+
15
+ clone_folder: c:\projects\winrm-elevated
16
+ clone_depth: 1
17
+ branches:
18
+ only:
19
+ - master
20
+
21
+ install:
22
+ - ps: net user /add $env:winrm_user $env:winrm_password
23
+ - ps: net localgroup administrators $env:winrm_user /add
24
+ - ps: winrm set winrm/config/client/auth '@{Basic="true"}'
25
+ - ps: winrm set winrm/config/service/auth '@{Basic="true"}'
26
+ - ps: winrm set winrm/config/service '@{AllowUnencrypted="true"}'
27
+ - ps: $env:PATH="C:\Ruby$env:ruby_version\bin;$env:PATH"
28
+ - ps: Write-Host $env:PATH
29
+ - ps: ruby --version
30
+ - ps: gem --version
31
+ - ps: gem install bundler --quiet --no-ri --no-rdoc
32
+ - ps: bundler --version
33
+
34
+ build_script:
35
+ - bundle install || bundle install || bundle install
36
+
37
+ test_script:
38
+ - SET SPEC_OPTS=--format progress
39
+ - bundle exec rake integration
data/changelog.md CHANGED
@@ -1,18 +1,18 @@
1
- # WinRM-Elevated Gem Changelog
2
-
3
- # 0.4.0
4
- - Initialize `Elevated::Runner` with a `CommandExecutor` instead of a `WinrmService` client
5
- - Run commands from newer winrm executor
6
- - Use latest winrm-fs 0.4.2
7
- - Allow task to run as a service account
8
- - Provide an artificially long timeout to the task to keep the task from dying after 60 seconds
9
-
10
- # 0.3.0
11
- - [Name Powershell Script and Log Files Uniquely](https://github.com/WinRb/winrm-elevated/pull/6)
12
-
13
- # 0.2.0
14
- - [Only upload the elevated runner script once per winrm session](https://github.com/WinRb/winrm-elevated/pull/3)
15
- - Bump WinRM (1.5) and WinRM-fs (0.3.0) gem constraints
16
-
17
- # 0.1.0
18
- - Initial Release
1
+ # WinRM-Elevated Gem Changelog
2
+
3
+ # 0.4.0
4
+ - Initialize `Elevated::Runner` with a `CommandExecutor` instead of a `WinrmService` client
5
+ - Run commands from newer winrm executor
6
+ - Use latest winrm-fs 0.4.2
7
+ - Allow task to run as a service account
8
+ - Provide an artificially long timeout to the task to keep the task from dying after 60 seconds
9
+
10
+ # 0.3.0
11
+ - [Name Powershell Script and Log Files Uniquely](https://github.com/WinRb/winrm-elevated/pull/6)
12
+
13
+ # 0.2.0
14
+ - [Only upload the elevated runner script once per winrm session](https://github.com/WinRb/winrm-elevated/pull/3)
15
+ - Bump WinRM (1.5) and WinRM-fs (0.3.0) gem constraints
16
+
17
+ # 0.1.0
18
+ - Initial Release
@@ -0,0 +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