def _winrm_connect(self): ''' Establish a WinRM connection over HTTP/HTTPS. ''' display.vvv("ESTABLISH WINRM CONNECTION FOR USER: %s on PORT %s TO %s" % (self._winrm_user, self._winrm_port, self._winrm_host), host=self._winrm_host) netloc = '%s:%d' % (self._winrm_host, self._winrm_port) endpoint = urlunsplit((self._winrm_scheme, netloc, self._winrm_path, '', '')) errors = [] for transport in self._winrm_transport: if transport == 'kerberos' and not HAVE_KERBEROS: errors.append('kerberos: the python kerberos library is not installed') continue display.vvvvv('WINRM CONNECT: transport=%s endpoint=%s' % (transport, endpoint), host=self._winrm_host) try: protocol = Protocol(endpoint, transport=transport, **self._winrm_kwargs) protocol.send_message('') return protocol except Exception as e: err_msg = (str(e) or repr(e)).strip() if re.search(r'Operation\s+?timed\s+?out', err_msg, re.I): raise AnsibleError('the connection attempt timed out') m = re.search(r'Code\s+?(\d{3})', err_msg) if m: code = int(m.groups()[0]) if code == 401: err_msg = 'the username/password specified for this server was incorrect' elif code == 411: return protocol errors.append('%s: %s' % (transport, err_msg)) display.vvvvv('WINRM CONNECTION ERROR: %s\n%s' % (err_msg, traceback.format_exc()), host=self._winrm_host) if errors: raise AnsibleError(', '.join(errors)) else: raise AnsibleError('No transport found for WinRM connection')
def __init__(self, target, auth, transport='plaintext'): username, password = auth self.url = self._build_url(target, transport) self.protocol = Protocol(self.url, transport=transport, username=username, password=password)
def __init__(self, target, auth, **kwargs): username, password = auth self.url = self._build_url(target, kwargs.get('transport', 'plaintext')) self.protocol = Protocol(self.url, username=username, password=password, **kwargs)
class WINRM(object): """ WINRM Module to connect to windows host """ def __init__(self, host_ip, usr, pwd): """ - **parameters**, **types**, **return** and **return types**:: :param os_type : windows/linux :param host_ip: ip address of the Windows host :param usr: username of the Windows Host :param pwd: Password of the Windows Host :type os_type: string :type host_ip: string :type u_name: string :type pwd: string """ self.os_type = 'windows' self.host_ip = host_ip self.usr = usr self.pwd = pwd self.shell_id = None self.host_win_ip = None self.conn = None def connect(self): """ Method to connect to a Windows machine. """ try: self.host_win_ip = "http://" + self.host_ip + ":5985/wsman" self.conn = Protocol(endpoint=self.host_win_ip, transport="ntlm", username=self.usr, password=self.pwd, server_cert_validation="ignore") logger.warn("Connecting Windows ...") self.shell_id = self.conn.open_shell() logger.warn(self.shell_id) logger.warn('Connected to Windows.') except Exception as error: msg_exception_error = "Exception raised: %s " % error raise (msg_exception_error) def run_cmd(self, cmd): """ Generic Method for passing command and run it on windows machine and return output. - **parameters**, **types**, **return** and **return types**:: :param cmd: Command to be executed on windows machine. :return stdout,stderr,status_code : output,errormessage and statuscode of output. :rtype stdout,stderr,status_code: tuple """ if 'shell_id' in dir(self): #checking for the shell_id created in winrm object command_id = self.conn.run_command(self.shell_id, cmd) std_out, std_err, status_code = self.conn.get_command_output( self.shell_id, command_id) #runs the command and returns output,error,statuscode return std_out, std_err, status_code
def _winrm_connect(self): ''' Establish a WinRM connection over HTTP/HTTPS. ''' display.vvv("ESTABLISH WINRM CONNECTION FOR USER: %s on PORT %s TO %s" % (self._winrm_user, self._winrm_port, self._winrm_host), host=self._winrm_host) winrm_host = self._winrm_host if HAS_IPADDRESS: display.vvvv("checking if winrm_host %s is an IPv6 address" % winrm_host) try: ipaddress.IPv6Address(winrm_host) except ipaddress.AddressValueError: pass else: winrm_host = "[%s]" % winrm_host netloc = '%s:%d' % (winrm_host, self._winrm_port) endpoint = urlunsplit((self._winrm_scheme, netloc, self._winrm_path, '', '')) errors = [] for transport in self._winrm_transport: if transport == 'kerberos': if not HAVE_KERBEROS: errors.append('kerberos: the python kerberos library is not installed') continue if self._kerb_managed: self._kerb_auth(self._winrm_user, self._winrm_pass) display.vvvvv('WINRM CONNECT: transport=%s endpoint=%s' % (transport, endpoint), host=self._winrm_host) try: winrm_kwargs = self._winrm_kwargs.copy() if self._winrm_connection_timeout: winrm_kwargs['operation_timeout_sec'] = self._winrm_connection_timeout winrm_kwargs['read_timeout_sec'] = self._winrm_connection_timeout + 1 protocol = Protocol(endpoint, transport=transport, **winrm_kwargs) # open the shell from connect so we know we're able to talk to the server if not self.shell_id: self.shell_id = protocol.open_shell(codepage=65001) # UTF-8 display.vvvvv('WINRM OPEN SHELL: %s' % self.shell_id, host=self._winrm_host) return protocol except Exception as e: err_msg = to_text(e).strip() if re.search(to_text(r'Operation\s+?timed\s+?out'), err_msg, re.I): raise AnsibleError('the connection attempt timed out') m = re.search(to_text(r'Code\s+?(\d{3})'), err_msg) if m: code = int(m.groups()[0]) if code == 401: err_msg = 'the specified credentials were rejected by the server' elif code == 411: return protocol errors.append(u'%s: %s' % (transport, err_msg)) display.vvvvv(u'WINRM CONNECTION ERROR: %s\n%s' % (err_msg, to_text(traceback.format_exc())), host=self._winrm_host) if errors: raise AnsibleConnectionFailure(', '.join(map(to_native, errors))) else: raise AnsibleError('No transport found for WinRM connection')
def _winrm_connect(self): ''' Establish a WinRM connection over HTTP/HTTPS. ''' display.vvv("ESTABLISH WINRM CONNECTION FOR USER: %s on PORT %s TO %s" % (self._winrm_user, self._winrm_port, self._winrm_host), host=self._winrm_host) winrm_host = self._winrm_host if HAS_IPADDRESS: display.debug("checking if winrm_host %s is an IPv6 address" % winrm_host) try: ipaddress.IPv6Address(winrm_host) except ipaddress.AddressValueError: pass else: winrm_host = "[%s]" % winrm_host netloc = '%s:%d' % (winrm_host, self._winrm_port) endpoint = urlunsplit((self._winrm_scheme, netloc, self._winrm_path, '', '')) errors = [] for transport in self._winrm_transport: if transport == 'kerberos': if not HAVE_KERBEROS: errors.append('kerberos: the python kerberos library is not installed') continue if self._kerb_managed: self._kerb_auth(self._winrm_user, self._winrm_pass) display.vvvvv('WINRM CONNECT: transport=%s endpoint=%s' % (transport, endpoint), host=self._winrm_host) try: winrm_kwargs = self._winrm_kwargs.copy() if self._winrm_connection_timeout: winrm_kwargs['operation_timeout_sec'] = self._winrm_connection_timeout winrm_kwargs['read_timeout_sec'] = self._winrm_connection_timeout + 1 protocol = Protocol(endpoint, transport=transport, **winrm_kwargs) # open the shell from connect so we know we're able to talk to the server if not self.shell_id: self.shell_id = protocol.open_shell(codepage=65001) # UTF-8 display.vvvvv('WINRM OPEN SHELL: %s' % self.shell_id, host=self._winrm_host) return protocol except Exception as e: err_msg = to_text(e).strip() if re.search(to_text(r'Operation\s+?timed\s+?out'), err_msg, re.I): raise AnsibleError('the connection attempt timed out') m = re.search(to_text(r'Code\s+?(\d{3})'), err_msg) if m: code = int(m.groups()[0]) if code == 401: err_msg = 'the specified credentials were rejected by the server' elif code == 411: return protocol errors.append(u'%s: %s' % (transport, err_msg)) display.vvvvv(u'WINRM CONNECTION ERROR: %s\n%s' % (err_msg, to_text(traceback.format_exc())), host=self._winrm_host) if errors: raise AnsibleConnectionFailure(', '.join(map(to_native, errors))) else: raise AnsibleError('No transport found for WinRM connection')
def run(self, scripturl, scriptarguments): scriptpath = "c:\\samanamon" #scripturl="http://%s/%s" % (self.nagiosaddress, scriptname) scriptname = scripturl.split('/')[-1] if self.cleanup: script = ''' if (-Not (Test-Path %(scriptpath)s)) { mkdir %(scriptpath)s | Out-Null} "Environment prepared." | Out-Host Invoke-WebRequest -Uri %(scripturl)s -OutFile "%(scriptpath)s\\%(scriptname)s" if (-Not (Test-Path %(scriptpath)s\\%(scriptname)s)) { "File not downloaded" | Out-Host; Remove-Item -Recurse -Force %(scriptpath)s exit 1 } "Downloaded Script." | Out-Host %(scriptpath)s\\%(scriptname)s %(scriptarguments)s| Out-Host "Done executing script" | Out-Host del %(scriptpath)s\\%(scriptname)s Remove-Item -Recurse -Force %(scriptpath)s "Done cleanup" | Out-Host''' % { 'scripturl': scripturl, 'scriptpath': scriptpath, 'scriptname': scriptname, 'scriptarguments': scriptarguments, 'hostaddress': self.hostaddress } else: script = ''' %(scriptpath)s\\%(scriptname)s %(scriptarguments)s| Out-Host "Done executing script" | Out-Host''' % { 'scriptpath': scriptpath, 'scriptname': scriptname, 'scriptarguments': scriptarguments } shell_id = None command_id = None p = None error = 0 std_out = '' std_err = '' try: p = Protocol( endpoint='http://%s:5985/wsman' % self.hostaddress, transport='ntlm', username=self.username, password=self.password) shell_id = p.open_shell() encoded_ps = b64encode(script.encode('utf_16_le')).decode('ascii') command_id = p.run_command(shell_id, 'powershell', ['-encodedcommand {0}'.format(encoded_ps), ]) std_out, std_err, status_code = p.get_command_output(shell_id, command_id) self.check_error(std_err) p.cleanup_command(shell_id, command_id) p.close_shell(shell_id) except Exception as e: raise CheckWinRMExceptionUNKNOWN("Unable to get data from Server (%s) %s." % (type(e).__name__, str(e))) if status_code != 0: raise CheckWinRMExceptionUNKNOWN(std_err) return "%s\n%s" % (std_out, "")
def getLastTaskResult(self, taskname): script = """ $task = Get-ScheduledTaskInfo -TaskName %s $task.LastTaskResult """ % taskname shell_id = None command_id = None p = None error = False try: p = Protocol(endpoint='https://' + self.hostname + ':5986/wsman', transport='ntlm', username=self.username, password=self.password, server_cert_validation='ignore') shell_id = p.open_shell() encoded_ps = b64encode(script.encode('utf_16_le')).decode('ascii') command_id = p.run_command(shell_id, 'powershell', [ '-encodedcommand {0}'.format(encoded_ps), ]) std_out, std_err, status_code = p.get_command_output( shell_id, command_id) lasttaskresult = std_out.rstrip() except Exception as e: print("UNKNOWN - Unable to get data from server (%s) %s." % (str(e), type(e).__name__)) error = True finally: p.cleanup_command(shell_id, command_id) p.close_shell(shell_id) if error: exit(3) return lasttaskresult
def run(self): # use win remote management to run powershell script # set command text, tell windows which module to import and run in this case script = "Import-Module -Name 'C:\\Users\\trota\\Source\\PowerShell\\Modules\\yo.psm1'; &WriteYo(' with var')" # must use utf16 little endian on windows # see run_ps in pywinrm __init__.py https://github.com/diyan/pywinrm/blob/master/winrm/__init__.py encoded_ps = b64encode(script.encode('utf_16_le')).decode('ascii') encoded_ps_command = 'powershell -encodedcommand {0}'.format( encoded_ps) print("") print("encoded ps command: ", encoded_ps_command) print("") # connect p = Protocol( endpoint='https://CCWL-2909.chsamerica.com:5986/wsman', transport='ntlm', username=r'chs\trota', password='******', # secure connection validation - see http://www.hurryupandwait.io/blog/understanding-and-troubleshooting-winrm-connection-and-authentication-a-thrill-seekers-guide-to-adventure # TODO: configure SSL properly for production/public spaces server_cert_validation='ignore' #server_cert_validation='validate' ) shell_id = p.open_shell() command_id = p.run_command(shell_id, encoded_ps_command) std_out, std_err, status_code = p.get_command_output( shell_id, command_id) p.cleanup_command(shell_id, command_id) p.close_shell(shell_id)
def run(self, host, password, command, params, username='******', port=5732, secure=True): proto = 'https' if secure else 'http' p = Protocol( endpoint='%s://%s:%i/wsman' % (proto, host, port), # RFC 2732? transport='ntlm', username=username, password=password, server_cert_validation='ignore') shell_id = p.open_shell() # run the command command_id = p.run_command(shell_id, command, params) std_out, std_err, status_code = p.get_command_output( shell_id, command_id) p.cleanup_command(shell_id, command_id) p.close_shell(shell_id) return {'stdout': std_out, 'stderr': std_err}
def main(): args = parse_args() endpoint = '{}://{}:{}/{}'.format( 'http' if args.use_http else 'https', args.host, args.port, args.endpoint ) username = args.user if '\\' not in username or '@' not in username: username = '******'.format(args.host.split('.')[0], username) if args.shell: command = args.command[0] arguments = args.command[1:] else: command = 'powershell' encoded_command = ' '.join(args.command) encoded_command = base64.b64encode(encoded_command.encode('utf-16-le')) arguments = ['-EncodedCommand', encoded_command] proto = Protocol(endpoint, 'ntlm', username, args.password, server_cert_validation='ignore') shell_id = proto.open_shell() command_id = proto.run_command(shell_id, command, arguments) std_out, std_err, status_code = proto.get_command_output(shell_id, command_id) sys.stdout.write(std_out.decode('utf-8')) # sys.stderr.write(std_err.decode('utf-8')) proto.cleanup_command(shell_id, command_id) proto.close_shell(shell_id) return status_code
def run_command(command, target): p = Protocol(endpoint='https://' + target + ':5986/wsman', transport='kerberos') # We do not want printed info about kerberos ticket stdout_orig = sys.stdout f = open('/dev/null', 'w') sys.stdout = f try: shell_id = p.open_shell() command_id = p.run_command(shell_id, 'powershell', [command]) std_out, std_err, status_code = p.get_command_output( shell_id, command_id) p.cleanup_command(shell_id, command_id) p.close_shell(shell_id) sys.stdout = stdout_orig print std_out if std_err: sys.exit(std_err) except kerberos.GSSError as e: print >> sys.stderr, "kerberos GSSError:", e sys.exit(2) except: print >> sys.stderr, ( "Unexpected error during remote ps command execution :", sys.exc_info()[0], sys.exc_info()[1]) sys.exit(2)
def _winrm_connect(self): ''' Establish a WinRM connection over HTTP/HTTPS. ''' display.vvv( "ESTABLISH WINRM CONNECTION FOR USER: %s on PORT %s TO %s" % (self._winrm_user, self._winrm_port, self._winrm_host), host=self._winrm_host) netloc = '%s:%d' % (self._winrm_host, self._winrm_port) endpoint = urlunsplit( (self._winrm_scheme, netloc, self._winrm_path, '', '')) errors = [] for transport in self._winrm_transport: if transport == 'kerberos' and not HAVE_KERBEROS: errors.append( 'kerberos: the python kerberos library is not installed') continue display.vvvvv('WINRM CONNECT: transport=%s endpoint=%s' % (transport, endpoint), host=self._winrm_host) try: protocol = Protocol(endpoint, transport=transport, **self._winrm_kwargs) # send keepalive message to ensure we're awake # TODO: is this necessary? # protocol.send_message(xmltodict.unparse(rq)) if not self.shell_id: self.shell_id = protocol.open_shell( codepage=65001) # UTF-8 display.vvvvv('WINRM OPEN SHELL: %s' % self.shell_id, host=self._winrm_host) return protocol except Exception as e: err_msg = to_unicode(e).strip() if re.search(to_unicode(r'Operation\s+?timed\s+?out'), err_msg, re.I): raise AnsibleError('the connection attempt timed out') m = re.search(to_unicode(r'Code\s+?(\d{3})'), err_msg) if m: code = int(m.groups()[0]) if code == 401: err_msg = 'the username/password specified for this server was incorrect' elif code == 411: return protocol errors.append(u'%s: %s' % (transport, err_msg)) display.vvvvv(u'WINRM CONNECTION ERROR: %s\n%s' % (err_msg, to_unicode(traceback.format_exc())), host=self._winrm_host) if errors: raise AnsibleConnectionFailure(', '.join(map(to_str, errors))) else: raise AnsibleError('No transport found for WinRM connection')
def _winrm_connect(self): ''' Establish a WinRM connection over HTTP/HTTPS. ''' port = self._connection_info.port or 5986 self._display.vvv("ESTABLISH WINRM CONNECTION FOR USER: %s on PORT %s TO %s" % \ (self._connection_info.remote_user, port, self._connection_info.remote_addr), host=self._connection_info.remote_addr) netloc = '%s:%d' % (self._connection_info.remote_addr, port) exc = None for transport, scheme in self.transport_schemes['http' if port == 5985 else 'https']: if transport == 'kerberos' and ( not HAVE_KERBEROS or not '@' in self._connection_info.remote_user): continue if transport == 'kerberos': realm = self._connection_info.remote_user.split( '@', 1)[1].strip() or None else: realm = None endpoint = parse.urlunsplit((scheme, netloc, '/wsman', '', '')) self._display.vvvvv('WINRM CONNECT: transport=%s endpoint=%s' % (transport, endpoint), host=self._connection_info.remote_addr) protocol = Protocol(endpoint, transport=transport, username=self._connection_info.remote_user, password=self._connection_info.password, realm=realm) try: protocol.send_message('') return protocol except WinRMTransportError as exc: err_msg = str(exc) if re.search(r'Operation\s+?timed\s+?out', err_msg, re.I): raise AnsibleError("the connection attempt timed out") m = re.search(r'Code\s+?(\d{3})', err_msg) if m: code = int(m.groups()[0]) if code == 401: raise AnsibleError( "the username/password specified for this server was incorrect" ) elif code == 411: return protocol self._display.vvvvv('WINRM CONNECTION ERROR: %s' % err_msg, host=self._connection_info.remote_addr) continue if exc: raise AnsibleError(str(exc))
def connect(self): inventory = Inventory() if inventory.has_option(self.hostname, 'address'): address = inventory.get(self.hostname, 'address') else: address = self.hostname logger.debug('Using address ' + address) if inventory.has_option(self.hostname, 'scheme'): scheme = inventory.get(self.hostname, 'scheme') else: scheme = 'http' logger.debug('Using url scheme ' + scheme) if inventory.has_option(self.hostname, 'port'): port = inventory.get(self.hostname, 'port') else: if scheme == 'http': port = '5985' elif scheme == 'https': port = '5986' else: raise('Invalid WinRM scheme: ' + scheme) logger.debug('Using port ' + port) if not inventory.has_option(self.hostname, 'username'): raise RuntimeError('Host ' + self.hostname + ' has not specified option: username') username = inventory.get(self.hostname, 'username') if inventory.has_option(self.hostname, 'kerberos_realm'): username = username + '@' + inventory.get(self.hostname, 'kerberos_realm') logger.debug('Using username ' + username) if inventory.has_option(self.hostname, 'kerberos_delegation'): kerberos_delegation = inventory.get(self.hostname, 'kerberos_delegation') else: kerberos_delegation = False if inventory.has_option(self.hostname, 'kerberos_hostname_override'): kerberos_hostname_override = inventory.get(self.hostname, 'kerberos_hostname_override') else: kerberos_hostname_override = None self.protocol = Protocol( endpoint=scheme + '://' + address + ':' + port + '/wsman', transport='kerberos', username=username, kerberos_delegation=kerberos_delegation, kerberos_hostname_override=kerberos_hostname_override) try: self.shell_id = self.protocol.open_shell() except Exception as e: logger.warning(str(e))
def connect(self, output, server): self.output = output self.datastore = os.path.join(self.output, server['server']) os.makedirs(self.datastore) # session = winrm.Session(server['url'], # auth=(server['user'], server['password']), # transport='ntlm') self.protocol = Protocol(endpoint='http://{}:5985/wsman'.format( server['url']), transport='ntlm', username=server['user'], password=server['password'])
def init_winrm_connection(self, host, port, username, password): endpoint = 'https://%s:%s/wsman' % (host, port) try: self.winrm = Protocol(endpoint=endpoint, transport='ntlm', username=username, password=password, server_cert_validation='ignore') return True except Exception as ex: print "\t=> WinRM : Authentication failed on server: %s cause: %s" % ( host, str(ex)) return False
def _winrm_connect(self): ''' Establish a WinRM connection over HTTP/HTTPS. ''' # get winrm-specific connection vars host_vars = self.runner.inventory._hosts_cache[self.delegate].get_variables() port = self.port or 5986 vvv("ESTABLISH WINRM CONNECTION FOR USER: %s on PORT %s TO %s" % \ (self.user, port, self.host), host=self.host) netloc = '%s:%d' % (self.host, port) exc = None for transport, scheme in self.transport_schemes['http' if port == 5985 else 'https']: if transport == 'kerberos' and (not HAVE_KERBEROS or not '@' in self.user): continue if transport == 'kerberos': realm = self.user.split('@', 1)[1].strip() or None else: realm = None endpoint = urlparse.urlunsplit((scheme, netloc, '/wsman', '', '')) self._winrm_kwargs = dict(username=self.user, password=self.password, realm=realm) argspec = inspect.getargspec(Protocol.__init__) for arg in argspec.args: if arg in ('self', 'endpoint', 'transport', 'username', 'password', 'realm'): continue if 'ansible_winrm_%s' % arg in host_vars: self._winrm_kwargs[arg] = host_vars['ansible_winrm_%s' % arg] vvvv('WINRM CONNECT: transport=%s endpoint=%s' % (transport, endpoint), host=self.host) protocol = Protocol(endpoint, transport=transport, **self._winrm_kwargs) try: protocol.send_message('') return protocol except WinRMTransportError, exc: err_msg = str(exc) if re.search(r'Operation\s+?timed\s+?out', err_msg, re.I): raise errors.AnsibleError("the connection attempt timed out") m = re.search(r'Code\s+?(\d{3})', err_msg) if m: code = int(m.groups()[0]) if code == 401: raise errors.AnsibleError("the username/password specified for this server was incorrect") elif code == 411: return protocol vvvv('WINRM CONNECTION ERROR: %s' % err_msg, host=self.host) continue
def connect(self): inventory = Inventory() if inventory.has_option(self.hostname, 'address'): address = inventory.get(self.hostname, 'address') else: address = self.hostname logger.debug('Using address ' + address) if inventory.has_option(self.hostname, 'scheme'): scheme = inventory.get(self.hostname, 'scheme') else: scheme = 'http' logger.debug('Using url scheme ' + scheme) if inventory.has_option(self.hostname, 'port'): port = inventory.get(self.hostname, 'port') else: if scheme == 'http': port = '5985' elif scheme == 'https': port = '5986' else: raise ('Invalid WinRM scheme: ' + scheme) logger.debug('Using port ' + port) if not inventory.has_option(self.hostname, 'username'): raise RuntimeError('Host ' + self.hostname + ' has not specified option: username') username = inventory.get(self.hostname, 'username') if inventory.has_option(self.hostname, 'domain'): username = inventory.get(self.hostname, 'domain') + '\\' + username logger.debug('Using username ' + username) if not inventory.has_option(self.hostname, 'password'): raise RuntimeError('Host ' + self.hostname + ' has not specified option: password') password = inventory.get(self.hostname, 'password') self.protocol = Protocol(endpoint=scheme + '://' + address + ':' + port + '/wsman', transport='plaintext', username=username, password=password) try: self.shell_id = self.protocol.open_shell() except Exception as e: logger.warning(str(e))
def _winrm_connect(self): ''' Establish a WinRM connection over HTTP/HTTPS. ''' port = self.port or 5986 vvv("ESTABLISH WINRM CONNECTION FOR USER: %s on PORT %s TO %s" % \ (self.user, port, self.host), host=self.host) netloc = '%s:%d' % (self.host, port) cache_key = '%s:%s@%s:%d' % (self.user, hashlib.md5( self.password).hexdigest(), self.host, port) if cache_key in _winrm_cache: vvvv('WINRM REUSE EXISTING CONNECTION: %s' % cache_key, host=self.host) return _winrm_cache[cache_key] transport_schemes = [('plaintext', 'https'), ('plaintext', 'http')] # FIXME: ssl/kerberos if port == 5985: transport_schemes = reversed(transport_schemes) exc = None for transport, scheme in transport_schemes: endpoint = urlparse.urlunsplit((scheme, netloc, '/wsman', '', '')) vvvv('WINRM CONNECT: transport=%s endpoint=%s' % (transport, endpoint), host=self.host) protocol = Protocol(endpoint, transport=transport, username=self.user, password=self.password) try: protocol.send_message('') _winrm_cache[cache_key] = protocol return protocol except WinRMTransportError, exc: err_msg = str(exc.args[0]) if re.search(r'Operation\s+?timed\s+?out', err_msg, re.I): raise errors.AnsibleError( "the connection attempt timed out") m = re.search(r'Code\s+?(\d{3})', err_msg) if m: code = int(m.groups()[0]) if code == 401: raise errors.AnsibleError( "the username/password specified for this server was incorrect" ) elif code == 411: _winrm_cache[cache_key] = protocol return protocol vvvv('WINRM CONNECTION ERROR: %s' % err_msg, host=self.host) continue
def getRemoteConnection(self, timeout=4): ''' create a remote connection :return: remote connection ''' p = Protocol(endpoint='https://' + self.ip + ':5986/wsman', transport='basic', username=self.remoteAdminUser, password=self.passwd, server_cert_validation='ignore', read_timeout_sec=timeout + 5, operation_timeout_sec=timeout) shell_id = p.open_shell() return p, shell_id
def check_creds(host, username, password, domain): has_access = False try: username = '******' % (domain, username) url = 'http://%s:5985/wsman' % host wsman = Protocol(endpoint=url, transport='ntlm', username=username, password=password) shell_id = wsman.open_shell() wsman.close_shell(shell_id) has_access = True except: has_access = False return has_access
def run_command(server_name, command_line): """ Execute remote command and return the output. Remark: No handing of any kind of exeception. Kerberos ticket should be intiated. Args: server_name(string): Name of the host to connect. command_line(string): Command to execute. Returns: Standard output, Standard error, Status """ host_name = "http://" + server_name + ":5985/wsman" win_connect = Protocol(endpoint=host_name, transport='kerberos') shell_id = win_connect.open_shell() command_id = win_connect.run_command(shell_id, command_line) return win_connect.get_command_output(shell_id, command_id)
def run_powershell_with_codepage_936(target, username, password, script): """ run remote command with WinRM [Chinese characters are not displayed properly #288](https://github.com/diyan/pywinrm/issues/288) [Code Page Identifiers](https://docs.microsoft.com/en-us/windows/win32/intl/code-page-identifiers) codepage use 936, gb2312, ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) :param target: hostname or ip address :type target: str :param username: :type username: str :param password: :type password: str :param script: powershell commands or scripts :type script: str | unicode :return: status_code, std_out :rtype: tuple """ script = to_unicode_or_bust(script) encoded_ps = b64encode(script.encode('utf_16_le')).decode("ascii") p = Protocol( endpoint='http://{}:5985/wsman'.format(target), transport='ntlm', username=username, password=password, read_timeout_sec=10, operation_timeout_sec=5, ) try: shell_id = p.open_shell(codepage=936) except requests.exceptions.ConnectionError as e: return 1, "requests failed.", str(e) try: command_id = p.run_command(shell_id, 'powershell.exe', ['-EncodedCommand', encoded_ps]) try: std_out, std_err, status_code = p.get_command_output( shell_id, command_id) finally: p.cleanup_command(shell_id, command_id) finally: p.close_shell(shell_id) # print(std_out.decode('utf-8')) # print(std_err.decode('utf-8')) # print(status_code) return status_code, std_out, std_err
def connect(self, host, username, password): client = Protocol(endpoint="http://{0}:5985/wsman".format(host), transport="ntlm", username=username, password=password, read_timeout_sec=30) return client
def get_pywinrm_session(ip, port, username, password): '''Get an insecure pywinrm session. :params ip, username, password: Windows host's WinRM details. :param port: the port where the WinRM service is listening in host. ''' transport_protocols = { 'http': ('plaintext', 'http'), 'https': ('ssl', 'https') } transport, protocol = transport_protocols['http' if port == 5985 else 'https'] session = winrm.Session("%(protocol)s://%(ip)s:%(port)s/wsman" % { "ip": ip, "port": port, "protocol": protocol }, auth=(username, password), transport=transport) session.protocol = Protocol(session.url, transport=transport, username=username, password=password, server_cert_validation='ignore') return session
def __init__(self, target, auth, transport='plaintext', timeout=None): username, password = auth self.url = self._build_url(target, transport) self.protocol = Protocol(self.url, transport=transport, username=username, password=password, timeout=timeout)
def _winrm_connect(self): ''' Establish a WinRM connection over HTTP/HTTPS. ''' port = self._connection_info.port or 5986 self._display.vvv("ESTABLISH WINRM CONNECTION FOR USER: %s on PORT %s TO %s" % \ (self._connection_info.remote_user, port, self._connection_info.remote_addr), host=self._connection_info.remote_addr) netloc = '%s:%d' % (self._connection_info.remote_addr, port) exc = None for transport, scheme in self.transport_schemes['http' if port == 5985 else 'https']: if transport == 'kerberos' and (not HAVE_KERBEROS or not '@' in self._connection_info.remote_user): continue if transport == 'kerberos': realm = self._connection_info.remote_user.split('@', 1)[1].strip() or None else: realm = None endpoint = parse.urlunsplit((scheme, netloc, '/wsman', '', '')) self._display.vvvvv('WINRM CONNECT: transport=%s endpoint=%s' % (transport, endpoint), host=self._connection_info.remote_addr) protocol = Protocol( endpoint, transport=transport, username=self._connection_info.remote_user, password=self._connection_info.password, realm=realm ) try: protocol.send_message('') return protocol except WinRMTransportError as exc: err_msg = str(exc) if re.search(r'Operation\s+?timed\s+?out', err_msg, re.I): raise AnsibleError("the connection attempt timed out") m = re.search(r'Code\s+?(\d{3})', err_msg) if m: code = int(m.groups()[0]) if code == 401: raise AnsibleError("the username/password specified for this server was incorrect") elif code == 411: return protocol self._display.vvvvv('WINRM CONNECTION ERROR: %s' % err_msg, host=self._connection_info.remote_addr) continue if exc: raise AnsibleError(str(exc))
def main(computer, username, password, command): p = Protocol(endpoint='https://{}:5986/wsman'.format(computer), transport='ntlm', username=username, password=password, server_cert_validation='ignore') shell_id = p.open_shell() #command_id = p.run_command(shell_id, 'query', ['user']) command_id = p.run_command(shell_id, command, []) std_out, std_err, status_code = p.get_command_output(shell_id, command_id) p.cleanup_command(shell_id, command_id) p.close_shell(shell_id)
def auto_ss(): from winrm.protocol import Protocol p = Protocol(endpoint='http://172.30.200.149:5985/wsman', transport='basic', username=r'chry', password='******', server_cert_validation='ignore') shell_id = p.open_shell() command_id = p.run_command(shell_id, 'ipconfig', ['/all']) std_out, std_err, status_code = p.get_command_output(shell_id, command_id) p.cleanup_command(shell_id, command_id) p.close_shell(shell_id)
def build_connection(host, username='', password='', transport='ntlm', useSSL=False): if (useSSL): p = Protocol(endpoint='https://' + host + ':5986/wsman', username=username, password=password, transport=transport, server_cert_validation='ignore') else: p = Protocol(endpoint='http://' + host + ':5985/wsman', username=username, password=password, transport=transport) return p
def connect(self,host,username,password): client = Protocol(endpoint="http://{0}:5985/wsman".format(host),transport="ntlm",username=username,password=password,read_timeout_sec=30) try: smbclient.register_session(self.host, username=self.username, password=self.password, connection_timeout=30) except Exception as e: self.error = str(e) return None return client
def test_set_timeout_as_sec(): protocol = Protocol('endpoint', username='******', password='******', read_timeout_sec='30', operation_timeout_sec='29') assert protocol.read_timeout_sec == 30 assert protocol.operation_timeout_sec == 29
class Session(object): #TODO implement context manager methods def __init__(self, target, auth, transport='plaintext'): username, password = auth self.url = self._build_url(target, transport) self.protocol = Protocol(self.url, transport=transport, username=username, password=password) def run_cmd(self, command, args=()): #TODO optimize perf. Do not call open/close shell every time shell_id = self.protocol.open_shell() command_id = self.protocol.run_command(shell_id, command, args) rs = Response(self.protocol.get_command_output(shell_id, command_id)) self.protocol.cleanup_command(shell_id, command_id) self.protocol.close_shell(shell_id) return rs @staticmethod def _build_url(target, transport): match = re.match( '(?i)^((?P<scheme>http[s]?)://)?(?P<host>[0-9a-z-_]+)(:(?P<port>\d+))?(?P<path>(/)?(wsman)?)?', target) scheme = match.group('scheme') if not scheme: scheme = 'https' if transport == 'ssl' else 'http' # TODO do we have anything other than HTTP/HTTPS host = match.group('host') port = match.group('port') if not port: port = 5986 if transport == 'ssl' else 5985 path = match.group('path') if not path: path = 'wsman' return '{0}://{1}:{2}/{3}'.format(scheme, host, port, path.lstrip('/'))
def winrm_cmd(cmd): p = Protocol(endpoint='https://192.168.183.186:5986/wsman', transport='basic', username=r'Administrator', password='******', server_cert_validation='ignore') shell_id = p.open_shell() command_id = p.run_command(shell_id, cmd) std_out, std_err, status_code = p.get_command_output(shell_id, command_id) p.cleanup_command(shell_id, command_id) p.close_shell(shell_id) return std_out
def _winrm_connect(self): ''' Establish a WinRM connection over HTTP/HTTPS. ''' if _winrm_hacks: port = _winrm_hacks.get_port(self) else: port = self.port or 5986 vvv("ESTABLISH WINRM CONNECTION FOR USER: %s on PORT %s TO %s" % \ (self.user, port, self.host), host=self.host) netloc = '%s:%d' % (self.host, port) cache_key = '%s:%s@%s:%d' % (self.user, hashlib.md5(self.password).hexdigest(), self.host, port) if cache_key in _winrm_cache: vvvv('WINRM REUSE EXISTING CONNECTION: %s' % cache_key, host=self.host) return _winrm_cache[cache_key] transport_schemes = [('plaintext', 'https'), ('plaintext', 'http')] # FIXME: ssl/kerberos if port == 5985: transport_schemes = reversed(transport_schemes) exc = None for transport, scheme in transport_schemes: endpoint = urlparse.urlunsplit((scheme, netloc, '/wsman', '', '')) vvvv('WINRM CONNECT: transport=%s endpoint=%s' % (transport, endpoint), host=self.host) protocol = Protocol(endpoint, transport=transport, username=self.user, password=self.password) try: protocol.send_message('') _winrm_cache[cache_key] = protocol return protocol except WinRMTransportError, exc: err_msg = str(exc.args[0]) if re.search(r'Operation\s+?timed\s+?out', err_msg, re.I): raise m = re.search(r'Code\s+?(\d{3})', err_msg) if m: code = int(m.groups()[0]) if code == 411: _winrm_cache[cache_key] = protocol return protocol vvvv('WINRM CONNECTION ERROR: %s' % err_msg, host=self.host) continue
def _winrm_connect(self): ''' Establish a WinRM connection over HTTP/HTTPS. ''' display.vvv("ESTABLISH WINRM CONNECTION FOR USER: %s on PORT %s TO %s" % (self._winrm_user, self._winrm_port, self._winrm_host), host=self._winrm_host) netloc = '%s:%d' % (self._winrm_host, self._winrm_port) endpoint = urlunsplit((self._winrm_scheme, netloc, self._winrm_path, '', '')) errors = [] for transport in self._winrm_transport: if transport == 'kerberos' and not HAVE_KERBEROS: errors.append('kerberos: the python kerberos library is not installed') continue display.vvvvv('WINRM CONNECT: transport=%s endpoint=%s' % (transport, endpoint), host=self._winrm_host) try: protocol = Protocol(endpoint, transport=transport, **self._winrm_kwargs) # send keepalive message to ensure we're awake # TODO: is this necessary? # protocol.send_message(xmltodict.unparse(rq)) if not self.shell_id: self.shell_id = protocol.open_shell(codepage=65001) # UTF-8 display.vvvvv('WINRM OPEN SHELL: %s' % self.shell_id, host=self._winrm_host) return protocol except Exception as e: err_msg = to_unicode(e).strip() if re.search(to_unicode(r'Operation\s+?timed\s+?out'), err_msg, re.I): raise AnsibleError('the connection attempt timed out') m = re.search(to_unicode(r'Code\s+?(\d{3})'), err_msg) if m: code = int(m.groups()[0]) if code == 401: err_msg = 'the username/password specified for this server was incorrect' elif code == 411: return protocol errors.append(u'%s: %s' % (transport, err_msg)) display.vvvvv(u'WINRM CONNECTION ERROR: %s\n%s' % (err_msg, to_unicode(traceback.format_exc())), host=self._winrm_host) if errors: raise AnsibleConnectionFailure(', '.join(map(to_str, errors))) else: raise AnsibleError('No transport found for WinRM connection')
def protocol_fake(request): uuid4_patcher = patch('uuid.uuid4') uuid4_mock = uuid4_patcher.start() uuid4_mock.return_value = uuid.UUID( '11111111-1111-1111-1111-111111111111') from winrm.protocol import Protocol protocol_fake = Protocol( endpoint='http://windows-host:5985/wsman', transport='plaintext', username='******', password='******') protocol_fake.transport = TransportStub() def uuid4_patch_stop(): uuid4_patcher.stop() request.addfinalizer(uuid4_patch_stop) return protocol_fake
def _try_winrm(self, node): ip = node.private_ips[0] p = Protocol( endpoint='http://%s:5985/wsman' % ip, # RFC 2732 transport='ntlm', username=self.username, password=self.secret, server_cert_validation='ignore') shell_id = p.open_shell() command_id = p.run_command(shell_id, 'ipconfig', ['/all']) std_out, std_err, status_code = p.get_command_output(shell_id, command_id) p.cleanup_command(shell_id, command_id) p.close_shell(shell_id) return std_out
def run(self, host, password, username='******', port=5732, secure=True): proto = 'https' if secure else 'http' p = Protocol( endpoint='%s://%s:%i/wsman' % (proto, host, port), # RFC 2732? transport='ntlm', username=username, password=password, server_cert_validation='ignore') shell_id = p.open_shell() command_id = p.run_command(shell_id, 'ipconfig', ['/all']) std_out, std_err, status_code = p.get_command_output(shell_id, command_id) p.cleanup_command(shell_id, command_id) p.close_shell(shell_id) return {'stdout': std_out, 'stderr': std_err}
class Session(object): #TODO implement context manager methods def __init__(self, url, auth, transport = "plaintext"): #TODO convert short urls into well-formed endpoint self.protocol = Protocol(url, auth, transport) def run_cmd(self, command, args=()): #TODO optimize perf. Do not call open/close shell every time shell_id = self.protocol.open_shell() command_id = self.protocol.run_command(shell_id, command, args) rs = Response(self.protocol.get_command_output(shell_id, command_id)) self.protocol.cleanup_command(shell_id, command_id) self.protocol.close_shell(shell_id) return rs
def connect(self, username=None, password=None): """ Attempts to connect to a remote server via WinRM. @param username: Username to be used for the WinRM connection @type username: string @param password: Password to be used for the WinRM connection @type password: string """ endpoint = "http://{host}:5985/wsman".format(host=self.host) try: self.connection = Protocol(endpoint=endpoint, username=username, password=password) # Doing a wide catch as the exception handling in WinRM is not # very thorough or specific except Exception as exception: self._log(exception.message) else: self.shell_id = self.connection.open_shell()
def _winrm_commands(self, node, commands): ip = node.private_ips[0] p = Protocol( endpoint='http://%s:5985/wsman' % ip, # RFC 2732 transport='ntlm', username=self.username, password=self.secret, server_cert_validation='ignore') shell_id = p.open_shell() std_out_logs = [] std_err_logs = [] # run the commands in sequence. for command, params in commands: command_id = p.run_command(shell_id, command, params) std_out, std_err, status_code = p.get_command_output(shell_id, command_id) std_out_logs.append(std_out) std_err_logs.append(std_err) p.cleanup_command(shell_id, command_id) p.close_shell(shell_id) return std_out_logs, std_err_logs
class BaseWinRMClient(BaseClient): def __init__(self, host=None): """ Initialization @param host: IP address or host name to connect to @type host: string """ self.host = host self.connection = None self.shell_id = None def connect(self, username=None, password=None): """ Attempts to connect to a remote server via WinRM. @param username: Username to be used for the WinRM connection @type username: string @param password: Password to be used for the WinRM connection @type password: string """ endpoint = "http://{host}:5985/wsman".format(host=self.host) try: self.connection = Protocol(endpoint=endpoint, username=username, password=password) # Doing a wide catch as the exception handling in WinRM is not # very thorough or specific except Exception as exception: self._log(exception.message) else: self.shell_id = self.connection.open_shell() def is_connected(self): """ Checks to see if a WinRM connection exists. @rtype: bool """ return self.connection is not None and self.shell_id is not None def _format_response(self, std_out=None, std_err=None, status_code=None): """ Converts the executed command responses into an object. @param std_out: The stdout result @type std_out: string @param std_err: The stderr result @type std_err: string @param status_code: The status code of the executed command @type status_code: int @rtype: WinRMResponse """ response = WinRMResponse(std_out=std_out, std_err=std_err, status_code=status_code) return response def execute_command(self, command=None, args=None): """ Executes a command via remote shell. @param command: The command to execute @type command: string @param args: A list of arguments to pass to the command @type args: list of strings @return: Result of command execution @rtype: WinRMResponse """ if not self.is_connected(): message = "Not currently connected to {host}.".format(host=self.host) self._log.error(message) raise Exception(message) if args is None: args = [] self._log.debug("Executing command: {command} {args}".format(command=command, args=" ".join(args))) command_id = self.connection.run_command(self.shell_id, command, args) std_out, std_err, status_code = self.connection.get_command_output(self.shell_id, command_id) response = self._format_response(std_out=std_out, std_err=std_err, status_code=status_code) self._log.debug("Stdout: {std_out}".format(std_out=response.std_out)) self._log.debug("Stderr: {std_err}".format(std_err=response.std_err)) self._log.debug("Status code: {status_code}".format(status_code=response.status_code)) return response
class Session(object): # TODO implement context manager methods def __init__(self, target, auth, transport='plaintext'): username, password = auth self.url = self._build_url(target, transport) self.protocol = Protocol(self.url, transport=transport, username=username, password=password) def run_cmd(self, command, args=()): # TODO optimize perf. Do not call open/close shell every time shell_id = self.protocol.open_shell() command_id = self.protocol.run_command(shell_id, command, args) rs = Response(self.protocol.get_command_output(shell_id, command_id)) self.protocol.cleanup_command(shell_id, command_id) self.protocol.close_shell(shell_id) return rs def run_ps_long(self, script): """base64 encodes a Powershell script and executes the powershell encoded script command """ shell_id = self.protocol.open_shell() def run_command(command): command_id = self.protocol.run_command(shell_id, command) rs = Response(self.protocol.get_command_output(shell_id, command_id)) self.protocol.cleanup_command(shell_id, command_id) # Powershell errors are returned in XML, clean them up if len(rs.std_err): rs.std_err = self.clean_error_msg(rs.std_err) return rs def make_ps_command(ps_script): return ("powershell -encodedcommand %s" % base64.b64encode(ps_script.encode("utf_16_le"))) def run_and_check_ps(command, stage_message): rs = run_command(command) if len(rs.std_err) or rs.status_code != 0: self.protocol.close_shell(shell_id) raise Exception("%s\n%s" % (stage_message, rs.std_err)) return rs.std_out # Get the name of a temp file cmd = ("$script_file = [IO.Path]::GetTempFileName() | " " Rename-Item -NewName { $_ -replace 'tmp$', 'tmp.ps1' } -PassThru\n" '"$script_file"') script_file = run_and_check_ps(make_ps_command(cmd), "Creating temp script file") script_file = script_file.strip() # Append the data to the file base64_script = base64.b64encode(script) chunk_size = 2000 for chunk_index in range(0, len(base64_script), chunk_size): chunk = base64_script[chunk_index:chunk_index + chunk_size] cmd ='ECHO %s %s "%s" ' % (chunk, ('>>' if chunk_index else '>'), script_file) run_and_check_ps(cmd, "writing chunk %s to temp script file" % chunk_index) # Execute the powershell script cmd = ''' # Convert it from b64 encoded $b64 = get-content "%(script_file)s" [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($b64)) | out-file -Encoding Default "%(script_file)s" ''' % {'script_file':script_file} run_and_check_ps(make_ps_command(cmd), "Converting temp script file back from b64 encoding") cmd = ("""PowerShell.exe -ExecutionPolicy Bypass -Command "& '%s' " """ % script_file) rs = run_command(cmd) # Finally, cleanup the temp file cmd = "remove-item '%s' " % script_file run_and_check_ps(make_ps_command(cmd), "Deleting temp script file") self.protocol.close_shell(shell_id) return rs def run_ps(self, script): # Get a temp powershell file name # TODO optimize perf. Do not call open/close shell every time shell_id = self.protocol.open_shell() base64_script = base64.b64encode(script.encode("utf_16_le")) # There is an issue with powershell scripts over 2k or 8k (platform dependent) # You can not have a command line + argument longer than this if len(base64_script) > 2000: return self.run_ps_long(script) # must use utf16 little endian on windows rs = self.run_cmd("powershell -encodedcommand %s" % (base64_script)) if len(rs.std_err): # Clean it it up and make it human readable rs.std_err = self.clean_error_msg(rs.std_err) return rs def clean_error_msg(self, msg): """converts a Powershell CLIXML message to a more human readable string """ # if the msg does not start with this, return it as is if msg.startswith("#< CLIXML\r\n"): # for proper xml, we need to remove the CLIXML part # (the first line) msg_xml = msg[11:] try: # remove the namespaces from the xml for easier processing msg_xml = self.strip_namespace(msg_xml) root = ET.fromstring(msg_xml) # the S node is the error message, find all S nodes nodes = root.findall("./S") new_msg = "" for s in nodes: # append error msg string to result, also # the hex chars represent CRLF so we replace with newline new_msg += s.text.replace("_x000D__x000A_", "\n") except Exception as e: # if any of the above fails, the msg was not true xml # print a warning and return the orignal string print("Warning: there was a problem converting the Powershell" " error message: %s" % (e)) else: # if new_msg was populated, that's our error message # otherwise the original error message will be used if len(new_msg): # remove leading and trailing whitespace while we are here msg = new_msg.strip() return msg def strip_namespace(self, xml): """strips any namespaces from an xml string""" try: p = re.compile("xmlns=*[\"\"][^\"\"]*[\"\"]") allmatches = p.finditer(xml) for match in allmatches: xml = xml.replace(match.group(), "") return xml except Exception as e: raise Exception(e) @staticmethod def _build_url(target, transport): match = re.match( '(?i)^((?P<scheme>http[s]?)://)?(?P<host>[0-9a-z-_.]+)(:(?P<port>\d+))?(?P<path>(/)?(wsman)?)?', target) # NOQA scheme = match.group('scheme') if not scheme: # TODO do we have anything other than HTTP/HTTPS scheme = 'https' if transport == 'ssl' else 'http' host = match.group('host') port = match.group('port') if not port: port = 5986 if transport == 'ssl' else 5985 path = match.group('path') if not path: path = 'wsman' return '{0}://{1}:{2}/{3}'.format(scheme, host, port, path.lstrip('/'))
def __init__(self, url, auth): #TODO convert short urls into well-formed endpoint username, password = auth self.protocol = Protocol(url, username=username, password=password)
# Run a process on a remote host s = winrm.Session('windows-host.example.com', auth=('john.smith', 'secret')) r = s.run_cmd('ipconfig', ['/all']) print r.status_code, r.std_out, # Run Powershell script on remote host ps_script = """$strComputer = $Host Clear $RAM = WmiObject Win32_ComputerSystem $MB = 1048576 "Installed Memory: " + [int]($RAM.TotalPhysicalMemory /$MB) + " MB" """ r = s.run_ps(ps_script) print r.status_code, r.std_out, # Run process with low-level API with domain user, disabling HTTPS cert validation from winrm.protocol import Protocol p = Protocol( endpoint='https://windows-host:5986/wsman', transport='ntlm', username=r'somedomain\someuser', password='******', server_cert_validation='ignore') shell_id = p.open_shell() command_id = p.run_command(shell_id, 'ipconfig', ['/all']) std_out, std_err, status_code = p.get_command_output(shell_id, command_id) p.cleanup_command(shell_id, command_id) p.close_shell(shell_id)
class Session(object): # TODO implement context manager methods def __init__(self, target, auth, transport='plaintext', timeout=None): username, password = auth self.url = self._build_url(target, transport) self.protocol = Protocol(self.url, transport=transport, username=username, password=password, timeout=timeout) def run_cmd(self, command, args=()): # TODO optimize perf. Do not call open/close shell every time shell_id = self.protocol.open_shell() command_id = self.protocol.run_command(shell_id, command, args) rs = Response(self.protocol.get_command_output(shell_id, command_id)) self.protocol.cleanup_command(shell_id, command_id) self.protocol.close_shell(shell_id) return rs def run_ps(self, script): """base64 encodes a Powershell script and executes the powershell encoded script command """ # must use utf16 little endian on windows encoded_ps = b64encode(script.encode('utf_16_le')).decode('ascii') rs = self.run_cmd('powershell -encodedcommand {0}'.format(encoded_ps)) if len(rs.std_err): # if there was an error message, clean it it up and make it human # readable rs.std_err = self._clean_error_msg(rs.std_err) return rs def _clean_error_msg(self, msg): """converts a Powershell CLIXML message to a more human readable string """ # TODO prepare unit test, beautify code # if the msg does not start with this, return it as is if msg.startswith("#< CLIXML\r\n"): # for proper xml, we need to remove the CLIXML part # (the first line) msg_xml = msg[11:] try: # remove the namespaces from the xml for easier processing msg_xml = self._strip_namespace(msg_xml) root = ET.fromstring(msg_xml) # the S node is the error message, find all S nodes nodes = root.findall("./S") new_msg = "" for s in nodes: # append error msg string to result, also # the hex chars represent CRLF so we replace with newline new_msg += s.text.replace("_x000D__x000A_", "\n") except Exception as e: # if any of the above fails, the msg was not true xml # print a warning and return the orignal string # TODO do not print, raise user defined error instead print("Warning: there was a problem converting the Powershell" " error message: %s" % (e)) else: # if new_msg was populated, that's our error message # otherwise the original error message will be used if len(new_msg): # remove leading and trailing whitespace while we are here msg = new_msg.strip() return msg def _strip_namespace(self, xml): """strips any namespaces from an xml string""" try: p = re.compile("xmlns=*[\"\"][^\"\"]*[\"\"]") allmatches = p.finditer(xml) for match in allmatches: xml = xml.replace(match.group(), "") return xml except Exception as e: raise Exception(e) @staticmethod def _build_url(target, transport): match = re.match( '(?i)^((?P<scheme>http[s]?)://)?(?P<host>[0-9a-z-_.]+)(:(?P<port>\d+))?(?P<path>(/)?(wsman)?)?', target) # NOQA scheme = match.group('scheme') if not scheme: # TODO do we have anything other than HTTP/HTTPS scheme = 'https' if transport == 'ssl' else 'http' host = match.group('host') port = match.group('port') if not port: port = 5986 if transport == 'ssl' else 5985 path = match.group('path') if not path: path = 'wsman' return '{0}://{1}:{2}/{3}'.format(scheme, host, port, path.lstrip('/'))
def __init__(self, url, auth, transport = "plaintext"): #TODO convert short urls into well-formed endpoint self.protocol = Protocol(url, auth, transport)
class WinRMHook(BaseHook): """ Hook for winrm remote execution using pywinrm. :seealso: https://github.com/diyan/pywinrm/blob/master/winrm/protocol.py :param ssh_conn_id: connection id from airflow Connections from where all the required parameters can be fetched like username and password. Thought the priority is given to the param passed during init :type ssh_conn_id: str :param endpoint: When not set, endpoint will be constructed like this: 'http://{remote_host}:{remote_port}/wsman' :type endpoint: str :param remote_host: Remote host to connect to. Ignored if `endpoint` is set. :type remote_host: str :param remote_port: Remote port to connect to. Ignored if `endpoint` is set. :type remote_port: int :param transport: transport type, one of 'plaintext' (default), 'kerberos', 'ssl', 'ntlm', 'credssp' :type transport: str :param username: username to connect to the remote_host :type username: str :param password: password of the username to connect to the remote_host :type password: str :param service: the service name, default is HTTP :type service: str :param keytab: the path to a keytab file if you are using one :type keytab: str :param ca_trust_path: Certification Authority trust path :type ca_trust_path: str :param cert_pem: client authentication certificate file path in PEM format :type cert_pem: str :param cert_key_pem: client authentication certificate key file path in PEM format :type cert_key_pem: str :param server_cert_validation: whether server certificate should be validated on Python versions that support it; one of 'validate' (default), 'ignore' :type server_cert_validation: str :param kerberos_delegation: if True, TGT is sent to target server to allow multiple hops :type kerberos_delegation: bool :param read_timeout_sec: maximum seconds to wait before an HTTP connect/read times out (default 30). This value should be slightly higher than operation_timeout_sec, as the server can block *at least* that long. :type read_timeout_sec: int :param operation_timeout_sec: maximum allowed time in seconds for any single wsman HTTP operation (default 20). Note that operation timeouts while receiving output (the only wsman operation that should take any significant time, and where these timeouts are expected) will be silently retried indefinitely. :type operation_timeout_sec: int :param kerberos_hostname_override: the hostname to use for the kerberos exchange (defaults to the hostname in the endpoint URL) :type kerberos_hostname_override: str :param message_encryption: Will encrypt the WinRM messages if set and the transport auth supports message encryption. (Default 'auto') :type message_encryption: str :param credssp_disable_tlsv1_2: Whether to disable TLSv1.2 support and work with older protocols like TLSv1.0, default is False :type credssp_disable_tlsv1_2: bool :param send_cbt: Will send the channel bindings over a HTTPS channel (Default: True) :type send_cbt: bool """ def __init__(self, ssh_conn_id=None, endpoint=None, remote_host=None, remote_port=5985, transport='plaintext', username=None, password=None, service='HTTP', keytab=None, ca_trust_path=None, cert_pem=None, cert_key_pem=None, server_cert_validation='validate', kerberos_delegation=False, read_timeout_sec=30, operation_timeout_sec=20, kerberos_hostname_override=None, message_encryption='auto', credssp_disable_tlsv1_2=False, send_cbt=True): super(WinRMHook, self).__init__(ssh_conn_id) self.ssh_conn_id = ssh_conn_id self.endpoint = endpoint self.remote_host = remote_host self.remote_port = remote_port self.transport = transport self.username = username self.password = password self.service = service self.keytab = keytab self.ca_trust_path = ca_trust_path self.cert_pem = cert_pem self.cert_key_pem = cert_key_pem self.server_cert_validation = server_cert_validation self.kerberos_delegation = kerberos_delegation self.read_timeout_sec = read_timeout_sec self.operation_timeout_sec = operation_timeout_sec self.kerberos_hostname_override = kerberos_hostname_override self.message_encryption = message_encryption self.credssp_disable_tlsv1_2 = credssp_disable_tlsv1_2 self.send_cbt = send_cbt self.client = None self.winrm_protocol = None def get_conn(self): if self.client: return self.client self.log.debug('Creating WinRM client for conn_id: %s', self.ssh_conn_id) if self.ssh_conn_id is not None: conn = self.get_connection(self.ssh_conn_id) if self.username is None: self.username = conn.login if self.password is None: self.password = conn.password if self.remote_host is None: self.remote_host = conn.host if conn.extra is not None: extra_options = conn.extra_dejson if "endpoint" in extra_options: self.endpoint = str(extra_options["endpoint"]) if "remote_port" in extra_options: self.remote_port = int(extra_options["remote_port"]) if "transport" in extra_options: self.transport = str(extra_options["transport"]) if "service" in extra_options: self.service = str(extra_options["service"]) if "keytab" in extra_options: self.keytab = str(extra_options["keytab"]) if "ca_trust_path" in extra_options: self.ca_trust_path = str(extra_options["ca_trust_path"]) if "cert_pem" in extra_options: self.cert_pem = str(extra_options["cert_pem"]) if "cert_key_pem" in extra_options: self.cert_key_pem = str(extra_options["cert_key_pem"]) if "server_cert_validation" in extra_options: self.server_cert_validation = str(extra_options["server_cert_validation"]) if "kerberos_delegation" in extra_options: self.kerberos_delegation = str(extra_options["kerberos_delegation"]).lower() == 'true' if "read_timeout_sec" in extra_options: self.read_timeout_sec = int(extra_options["read_timeout_sec"]) if "operation_timeout_sec" in extra_options: self.operation_timeout_sec = int(extra_options["operation_timeout_sec"]) if "kerberos_hostname_override" in extra_options: self.kerberos_hostname_override = str(extra_options["kerberos_hostname_override"]) if "message_encryption" in extra_options: self.message_encryption = str(extra_options["message_encryption"]) if "credssp_disable_tlsv1_2" in extra_options: self.credssp_disable_tlsv1_2 = \ str(extra_options["credssp_disable_tlsv1_2"]).lower() == 'true' if "send_cbt" in extra_options: self.send_cbt = str(extra_options["send_cbt"]).lower() == 'true' if not self.remote_host: raise AirflowException("Missing required param: remote_host") # Auto detecting username values from system if not self.username: self.log.debug( "username to WinRM to host: %s is not specified for connection id" " %s. Using system's default provided by getpass.getuser()", self.remote_host, self.ssh_conn_id ) self.username = getpass.getuser() # If endpoint is not set, then build a standard wsman endpoint from host and port. if not self.endpoint: self.endpoint = 'http://{0}:{1}/wsman'.format(self.remote_host, self.remote_port) try: if self.password and self.password.strip(): self.winrm_protocol = Protocol( endpoint=self.endpoint, transport=self.transport, username=self.username, password=self.password, service=self.service, keytab=self.keytab, ca_trust_path=self.ca_trust_path, cert_pem=self.cert_pem, cert_key_pem=self.cert_key_pem, server_cert_validation=self.server_cert_validation, kerberos_delegation=self.kerberos_delegation, read_timeout_sec=self.read_timeout_sec, operation_timeout_sec=self.operation_timeout_sec, kerberos_hostname_override=self.kerberos_hostname_override, message_encryption=self.message_encryption, credssp_disable_tlsv1_2=self.credssp_disable_tlsv1_2, send_cbt=self.send_cbt ) self.log.info("Establishing WinRM connection to host: %s", self.remote_host) self.client = self.winrm_protocol.open_shell() except Exception as error: error_msg = "Error connecting to host: {0}, error: {1}".format(self.remote_host, error) self.log.error(error_msg) raise AirflowException(error_msg) return self.client
class WinRMHook(BaseHook, LoggingMixin): """ Hook for winrm remote execution using pywinrm. :param ssh_conn_id: connection id from airflow Connections from where all the required parameters can be fetched like username, password or key_file. Thought the priority is given to the param passed during init :type ssh_conn_id: str :param remote_host: remote host to connect :type remote_host: str :param username: username to connect to the remote_host :type username: str :param password: password of the username to connect to the remote_host :type password: str :param key_file: key file to use to connect to the remote_host. :type key_file: str :param timeout: timeout for the attempt to connect to the remote_host. :type timeout: int :param keepalive_interval: send a keepalive packet to remote host every keepalive_interval seconds :type keepalive_interval: int """ def __init__(self, ssh_conn_id=None, remote_host=None, username=None, password=None, key_file=None, timeout=10, keepalive_interval=30 ): super(WinRMHook, self).__init__(ssh_conn_id) # TODO make new win rm connection class self.ssh_conn_id = ssh_conn_id self.remote_host = remote_host self.username = username self.password = password self.key_file = key_file self.timeout = timeout self.keepalive_interval = keepalive_interval # Default values, overridable from Connection self.compress = True self.no_host_key_check = True self.client = None self.winrm_protocol = None def get_conn(self): if not self.client: self.log.debug('Creating WinRM client for conn_id: %s', self.ssh_conn_id) if self.ssh_conn_id is not None: conn = self.get_connection(self.ssh_conn_id) if self.username is None: self.username = conn.login if self.password is None: self.password = conn.password if self.remote_host is None: self.remote_host = conn.host if conn.extra is not None: extra_options = conn.extra_dejson self.key_file = extra_options.get("key_file") if "timeout" in extra_options: self.timeout = int(extra_options["timeout"], 10) if "compress" in extra_options \ and extra_options["compress"].lower() == 'false': self.compress = False if "no_host_key_check" in extra_options \ and extra_options["no_host_key_check"].lower() == 'false': self.no_host_key_check = False if not self.remote_host: raise AirflowException("Missing required param: remote_host") # Auto detecting username values from system if not self.username: self.log.debug( "username to ssh to host: %s is not specified for connection id" " %s. Using system's default provided by getpass.getuser()", self.remote_host, self.ssh_conn_id ) self.username = getpass.getuser() try: if self.password and self.password.strip(): self.winrm_protocol = Protocol( # TODO pass in port from ssh conn endpoint='http://' + self.remote_host + ':5985/wsman', # TODO get cert transport working # transport='certificate', transport='plaintext', # cert_pem=r'publickey.pem', # cert_key_pem=r'dev.pem', read_timeout_sec=70, operation_timeout_sec=60, username=self.username, password=self.password, server_cert_validation='ignore') self.log.info("Opening WinRM shell") self.client = self.winrm_protocol.open_shell() except Exception as error: self.log.error( "Error connecting to host: %s, error: %s", self.remote_host, error ) return self.client
def get_conn(self): if not self.client: self.log.debug('Creating WinRM client for conn_id: %s', self.ssh_conn_id) if self.ssh_conn_id is not None: conn = self.get_connection(self.ssh_conn_id) if self.username is None: self.username = conn.login if self.password is None: self.password = conn.password if self.remote_host is None: self.remote_host = conn.host if conn.extra is not None: extra_options = conn.extra_dejson self.key_file = extra_options.get("key_file") if "timeout" in extra_options: self.timeout = int(extra_options["timeout"], 10) if "compress" in extra_options \ and extra_options["compress"].lower() == 'false': self.compress = False if "no_host_key_check" in extra_options \ and extra_options["no_host_key_check"].lower() == 'false': self.no_host_key_check = False if not self.remote_host: raise AirflowException("Missing required param: remote_host") # Auto detecting username values from system if not self.username: self.log.debug( "username to ssh to host: %s is not specified for connection id" " %s. Using system's default provided by getpass.getuser()", self.remote_host, self.ssh_conn_id ) self.username = getpass.getuser() try: if self.password and self.password.strip(): self.winrm_protocol = Protocol( # TODO pass in port from ssh conn endpoint='http://' + self.remote_host + ':5985/wsman', # TODO get cert transport working # transport='certificate', transport='plaintext', # cert_pem=r'publickey.pem', # cert_key_pem=r'dev.pem', read_timeout_sec=70, operation_timeout_sec=60, username=self.username, password=self.password, server_cert_validation='ignore') self.log.info("Opening WinRM shell") self.client = self.winrm_protocol.open_shell() except Exception as error: self.log.error( "Error connecting to host: %s, error: %s", self.remote_host, error ) return self.client
def get_conn(self): if self.client: return self.client self.log.debug('Creating WinRM client for conn_id: %s', self.ssh_conn_id) if self.ssh_conn_id is not None: conn = self.get_connection(self.ssh_conn_id) if self.username is None: self.username = conn.login if self.password is None: self.password = conn.password if self.remote_host is None: self.remote_host = conn.host if conn.extra is not None: extra_options = conn.extra_dejson if "endpoint" in extra_options: self.endpoint = str(extra_options["endpoint"]) if "remote_port" in extra_options: self.remote_port = int(extra_options["remote_port"]) if "transport" in extra_options: self.transport = str(extra_options["transport"]) if "service" in extra_options: self.service = str(extra_options["service"]) if "keytab" in extra_options: self.keytab = str(extra_options["keytab"]) if "ca_trust_path" in extra_options: self.ca_trust_path = str(extra_options["ca_trust_path"]) if "cert_pem" in extra_options: self.cert_pem = str(extra_options["cert_pem"]) if "cert_key_pem" in extra_options: self.cert_key_pem = str(extra_options["cert_key_pem"]) if "server_cert_validation" in extra_options: self.server_cert_validation = str(extra_options["server_cert_validation"]) if "kerberos_delegation" in extra_options: self.kerberos_delegation = str(extra_options["kerberos_delegation"]).lower() == 'true' if "read_timeout_sec" in extra_options: self.read_timeout_sec = int(extra_options["read_timeout_sec"]) if "operation_timeout_sec" in extra_options: self.operation_timeout_sec = int(extra_options["operation_timeout_sec"]) if "kerberos_hostname_override" in extra_options: self.kerberos_hostname_override = str(extra_options["kerberos_hostname_override"]) if "message_encryption" in extra_options: self.message_encryption = str(extra_options["message_encryption"]) if "credssp_disable_tlsv1_2" in extra_options: self.credssp_disable_tlsv1_2 = \ str(extra_options["credssp_disable_tlsv1_2"]).lower() == 'true' if "send_cbt" in extra_options: self.send_cbt = str(extra_options["send_cbt"]).lower() == 'true' if not self.remote_host: raise AirflowException("Missing required param: remote_host") # Auto detecting username values from system if not self.username: self.log.debug( "username to WinRM to host: %s is not specified for connection id" " %s. Using system's default provided by getpass.getuser()", self.remote_host, self.ssh_conn_id ) self.username = getpass.getuser() # If endpoint is not set, then build a standard wsman endpoint from host and port. if not self.endpoint: self.endpoint = 'http://{0}:{1}/wsman'.format(self.remote_host, self.remote_port) try: if self.password and self.password.strip(): self.winrm_protocol = Protocol( endpoint=self.endpoint, transport=self.transport, username=self.username, password=self.password, service=self.service, keytab=self.keytab, ca_trust_path=self.ca_trust_path, cert_pem=self.cert_pem, cert_key_pem=self.cert_key_pem, server_cert_validation=self.server_cert_validation, kerberos_delegation=self.kerberos_delegation, read_timeout_sec=self.read_timeout_sec, operation_timeout_sec=self.operation_timeout_sec, kerberos_hostname_override=self.kerberos_hostname_override, message_encryption=self.message_encryption, credssp_disable_tlsv1_2=self.credssp_disable_tlsv1_2, send_cbt=self.send_cbt ) self.log.info("Establishing WinRM connection to host: %s", self.remote_host) self.client = self.winrm_protocol.open_shell() except Exception as error: error_msg = "Error connecting to host: {0}, error: {1}".format(self.remote_host, error) self.log.error(error_msg) raise AirflowException(error_msg) return self.client
if key == "params": paramlist = value.split("--") for param in paramlist: itemlist = param.split() if 1 < len(itemlist): script = script.replace("$$"+itemlist[0], itemlist[1]) else: script = script.replace("$$"+key, value) script = script.replace("\n", ";") if "\\" in data["serverusername"]: #script = base64.b64encode(script.encode("utf-16")) cmd = "powershell -ExecutionPolicy Bypass -command %s" % (script) p = Protocol( endpoint='https://'+data["servername"]+':5986/wsman', transport='credssp', username=data["serverusername"], password=data["password"], server_cert_validation='ignore') shell_id = p.open_shell() command_id = p.run_command(shell_id, cmd) std_out, std_err, status_code = p.get_command_output(shell_id, command_id) p.cleanup_command(shell_id, command_id) p.close_shell(shell_id) else: script = "\n"+script s = winrm.Session(data["servername"], auth=(data["serverusername"], data["password"])) try: r = s.run_ps(script) # except winrm.exceptions.UnauthorizedError: # print "Could not authenticate on the remote server:", sys.exc_info()[1] # sys.exit(100)