class WinRM::Shells::Elevated

Runs PowerShell commands elevated via a scheduled task

Attributes

execution_timeout[RW]

@return [Integer] Timeout for the task to be executed

interactive_logon[RW]

@return [Bool] Using an interactive logon

password[RW]

@return [String] The admin user password

username[RW]

@return [String] The admin user name to execute the scheduled task as

Public Class Methods

new(connection_opts, transport, logger) click to toggle source

Create a new elevated shell @param connection_opts [ConnectionOpts] The WinRM connection options @param transport [HttpTransport] The WinRM SOAP transport @param logger [Logger] The logger to log diagnostic messages to

# File lib/winrm/shells/elevated.rb, line 30
def initialize(connection_opts, transport, logger)
  @logger = logger
  @username = connection_opts[:user]
  @password = connection_opts[:password]
  @interactive_logon = false
  @shell = Powershell.new(connection_opts, transport, logger)
  @winrm_file_transporter = WinRM::FS::Core::FileTransporter.new(@shell)
  @execution_timeout = 86_400
end

Public Instance Methods

close() click to toggle source

Closes the shell if one is open

# File lib/winrm/shells/elevated.rb, line 68
def close
  @shell.close
end
run(command, &block) click to toggle source

Run a command or PowerShell script elevated without any of the restrictions that WinRM puts in place.

@param [String] The command or PS script to wrap in a scheduled task

@return [WinRM::Output] :stdout and :stderr

# File lib/winrm/shells/elevated.rb, line 58
def run(command, &block)
  # if an IO object is passed read it, otherwise assume the contents of the file were passed
  script_text = command.respond_to?(:read) ? command.read : command

  script_path = upload_elevated_shell_script(script_text)
  wrapped_script = wrap_in_scheduled_task(script_path, username, password)
  @shell.run(wrapped_script, &block)
end

Private Instance Methods

elevated_shell_script_content() click to toggle source
# File lib/winrm/shells/elevated.rb, line 83
def elevated_shell_script_content
  IO.read(File.expand_path('../../winrm-elevated/scripts/elevated_shell.ps1', __dir__))
end
upload_elevated_shell_script(script_text) click to toggle source
# File lib/winrm/shells/elevated.rb, line 74
def upload_elevated_shell_script(script_text)
  elevated_shell_path = 'c:/windows/temp/winrm-elevated-shell-' + SecureRandom.uuid + '.ps1'
  # Prepend the content of the file with an UTF-8 BOM for Windows to read it as such instead of the default
  # Windows-XXXX encoding, and convert script_text accordingly if needed.
  script_text_with_exit = "\uFEFF#{script_text.encode(Encoding::UTF_8)}\r\n$Host.SetShouldExit($LASTEXITCODE)"
  @winrm_file_transporter.upload(StringIO.new(script_text_with_exit), elevated_shell_path)
  elevated_shell_path
end
wrap_in_scheduled_task(script_path, username, password) click to toggle source
# File lib/winrm/shells/elevated.rb, line 87
def wrap_in_scheduled_task(script_path, username, password)
  context = {
    username: username,
    password: password,
    script_path: script_path,
    interactive_logon: interactive_logon,
    execution_timeout: execution_timeout
  }

  b = binding
  locals = context.collect { |k, _| "#{k} = context[#{k.inspect}]; " }
  b.eval(locals.join)
  b.eval(Erubi::Engine.new(elevated_shell_script_content).src)
end