class WinRM::Transport::CommandExecutor
Object which can execute multiple commands and Powershell scripts in one shared remote shell session. The maximum number of commands per shell is determined by interrogating the remote host when the session is opened and the remote shell is automatically recycled before the threshold is reached.
@author Matt Wrock <matt@mattwrock.com> @author Fletcher Nichol <fnichol@nichol.ca>
Constants
- LEGACY_LIMIT
@return [Integer] the default maximum number of commands which can be
executed in one remote shell session on "older" versions of Windows
@api private
- MODERN_LIMIT
@return [Integer] the default maximum number of commands which can be
executed in one remote shell session on "modern" versions of Windows
@api private
- PS1_OS_VERSION
@return [String] the PowerShell command used to determine the version
of Windows
@api private
Attributes
@return [Integer] the number of executed commands on the remote
shell session
@api private
@return [#debug,#info] the logger @api private
@return [Integer,nil] the safe maximum number of commands that can
be executed in one remote shell session, or `nil` if the threshold has not yet been determined
@return [WinRM::WinRMWebService] a WinRM
web service object @api private
@return [String,nil] the identifier for the current open remote
shell session, or `nil` if the session is not open
Public Class Methods
Creates a CommandExecutor
given a `WinRM::WinRMWebService` object.
@param service [WinRM::WinRMWebService] a winrm web service object @param logger [#debug,#info] an optional logger/ui object that
responds to `#debug` and `#info` (default: `nil`)
@param closer [ShellCloser] an optional object to automatically
close the active open remote shell when CommandExecutor garbarge collects
# File lib/winrm/transport/command_executor.rb, line 53 def initialize(service, logger = nil, closer = nil) @service = service @logger = logger @closer = closer @command_count = 0 end
Public Instance Methods
Closes the open remote shell session. This method can be called multiple times, even if there is no open session.
# File lib/winrm/transport/command_executor.rb, line 62 def close return if shell.nil? service.close_shell(shell) remove_finalizer @shell = nil end
Opens a remote shell session for reuse. The maxiumum command-per-shell threshold is also determined the first time this method is invoked and cached for later invocations.
@return [String] the remote shell session indentifier
# File lib/winrm/transport/command_executor.rb, line 75 def open close @shell = service.open_shell add_finalizer(shell) @command_count = 0 determine_max_commands unless max_commands shell end
Runs a CMD command.
@param command [String] the command to run on the remote system @param arguments [Array<String>] arguments to the command @yield [stdout, stderr] yields more live access the standard
output and standard error streams as they are returns, if streaming behavior is desired
@return [WinRM::Output] output object with stdout, stderr, and
exit code
# File lib/winrm/transport/command_executor.rb, line 93 def run_cmd(command, arguments = [], &block) reset if command_count_exceeded? ensure_open_shell! @command_count += 1 result = nil service.run_command(shell, command, arguments) do |command_id| result = service.get_command_output(shell, command_id, &block) end result end
Run a Powershell script that resides on the local box.
@param script_file [IO,String] an IO reference for reading the
Powershell script or the actual file contents
@yield [stdout, stderr] yields more live access the standard
output and standard error streams as they are returns, if streaming behavior is desired
@return [WinRM::Output] output object with stdout, stderr, and
exit code
# File lib/winrm/transport/command_executor.rb, line 114 def run_powershell_script(script_file, &block) # this code looks overly compact in an attempt to limit local # variable assignments that may contain large strings and # consequently bloat the Ruby VM run_cmd( "powershell", [ "-encodedCommand", ::WinRM::PowershellScript.new( script_file.is_a?(IO) ? script_file.read : script_file ).encoded ], &block ) end
Private Instance Methods
Creates a finalizer for this connection which will close the open remote shell session when the object is garabage collected or on Ruby VM shutdown.
@param shell_id [String] the remote shell identifier @api private
# File lib/winrm/transport/command_executor.rb, line 166 def add_finalizer(shell_id) ObjectSpace.define_finalizer(self, @closer.for(shell_id)) if @closer end
@return [true,false] whether or not the number of exeecuted commands
have exceeded the maxiumum threshold
@api private
# File lib/winrm/transport/command_executor.rb, line 173 def command_count_exceeded? command_count > max_commands.to_i end
Determines the safe maximum number of commands that can be executed on a remote shell session by interrogating the remote host.
@api private
# File lib/winrm/transport/command_executor.rb, line 192 def determine_max_commands os_version = run_powershell_script(PS1_OS_VERSION).stdout.chomp @max_commands = os_version < "6.2" ? LEGACY_LIMIT : MODERN_LIMIT @max_commands -= 2 # to be safe end
Ensures that there is an open remote shell session.
@raise [WinRM::WinRMError] if there is no open shell @api private
# File lib/winrm/transport/command_executor.rb, line 181 def ensure_open_shell! if shell.nil? raise ::WinRM::WinRMError, "#{self.class}#open must be called " \ "before any run methods are invoked" end end
Removes any finalizers for this connection.
@api private
# File lib/winrm/transport/command_executor.rb, line 201 def remove_finalizer ObjectSpace.undefine_finalizer(self) if @closer end
Closes the remote shell session and opens a new one.
@api private
# File lib/winrm/transport/command_executor.rb, line 208 def reset debug { "Resetting WinRM shell (Max command limit is #{max_commands})" } open end