Package: pypsrp
pypsrp - Python PowerShell Remoting Protocol Client librarypypsrp is a Python client for the PowerShell Remoting Protocol (PSRP) and
Windows Remote Management (WinRM) service. It allows your to execute commands
on a remote Windows host from any machine that can run Python.This library exposes 4 different types of APIs;A simple client API that can copy files to and from the remote Windows host as well as execute processes and PowerShell scriptsA WSMan interface to execute various WSMan calls likeSend,Create,Connect,Disconnect, etcA Windows Remote Shell (WinRS) layer that executes cmd commands and executables using the base WinRM protocolA PowerShell Remoting Protocol (PSRP) layer allows you to create remote Runspace Pools and PowerShell pipelinesAt a basic level, you can use this library to;Execute a cmd commandRun another executableExecute PowerShell scriptsCopy a file from the localhost to the remote Windows hostFetch a file from the remote Windows host to the localhostCreate a Runspace Pool that contains one or multiple PowerShell pipelines and execute them asynchronouslySupport for a reference host base implementation of PSRP for interactive scriptsCurrently this library only supports the WSMan transport method but is designed
to support SSH at some point in the future (PR's are welcome). By default it
supports the following authentication methods with WSMan;BasicCertificateNTLMIt also supportsNegotiate/Kerberos, andCredSSPbut require extra
libraries to be installed.RequirementsSeeHow to Installfor more detailsCPython 3.6+cryptographypyspnegorequestsOptional RequirementsThe following Python libraries can be installed to add extra features that do
not come with the base package:python-gssapifor Kerberos authentication on Linuxpykrb5for Kerberos authentication on Linuxrequests-credsspfor CredSSP authenticationHow to InstallTo install pypsrp with all the basic features, run:pipinstallpypsrpKerberos AuthenticationWhile pypsrp supports Kerberos authentication, it isn't included by default for
Linux hosts due to it's reliance on system packages to be present.To install these packages, depending on your distribution, run one of the following script blocks.For Debian/Ubuntu# For Python 2apt-getinstallgccpython-devlibkrb5-dev# For Python 3apt-getinstallgccpython3-devlibkrb5-dev# To add NTLM to the GSSAPI SPNEGO auth runapt-getinstallgss-ntlmsspFor RHEL/Centosyuminstallgccpython-develkrb5-devel# To add NTLM to the GSSAPI SPNEGO auth runyuminstallgssntlmsspFor Fedoradnfinstallgccpython-develkrb5-devel# To add NTLM to the GSSAPI SPNEGO auth rundnfinstallgssntlmsspFor Arch Linuxpacman-Sgcckrb5Once installed you can install the Python packages withpipinstallpypsrp[kerberos]Kerberos also needs to be configured to talk to the domain but that is outside
the scope of this page.CredSSP AuthenticationLike Kerberos auth, CredSSP is supported but isn't included by default. To add
support for CredSSP auth try to run the followingpipinstallpypsrp[credssp]If that fails you may need to update pip and setuptools to a newer versionpip install -U pip setuptools.How to UseThere are 3 main components that are in use within this library;Transport: Handles the raw transport of messages to and from the serverShell: Handles the WSMV or PSRP protocol details used to create the remote shell that processes are run on, usesConnectionto send the detailsProcess: Runs the process or script within a shellConnectionCurrently only the connection that is supported is the WSMan protocol over HTTP
throughpypsrp.wsman.WSManand offers mostly all the same features in the
WSMV spec including;Basic, Certificate, Negotiate, Kerberos, and CredSSP authenticationTLS encryptionMessage encryption with Negotiate, Kerberos, and CredSSP authenticationDefinable proxyThese are the options that can be used to setupWSMan;server: The hostname or IP address of the host to connect tomax_envelope_size: The maximum envelope size, in bytes, that can be sent to the server, default is153600operation_timeout: The operation timeout, in seconds, of each WSMan operation, default is20. This should always be lower thanread_timeout.port: The port to connect to, default is5986ifssl=Trueelse5985username: The username to connect with, required for all auths exceptcertificateand optionally required fornegotiate/kerberospassword: The password forusername. Due to a bug on MacOS/Heimdal GSSAPI implementations, this will persist in the user's ccache when using Negotiate or Kerberos authentication, runkdestroymanually to remove thisssl: Whether to connect overhttpsorhttps, default isTruepath: The WinRM path to connect to, default iswsmanauth: The authentication protocol to use, default isnegotiate, choices arebasic,certificate,negotiate,ntlm,kerberos,credsspcert_validation: Whether to validate the server's SSL certificate, default isTrue. Can beFalseto not validate or a path to a PEM file of trusted certificatesconnection_timeout: The timeout for creating a HTTP connection, default is30read_timeout: The timeout for receiving a response from the server after a request has been made, default is30encryption: Controls the encryption settings, default isauto, choices areauto,always,never. Set toalwaysto always run message encryption even over HTTPS,neverto never use message encryption even over HTTPproxy: The proxy URL used to connect to the remote hostno_proxy: Whether to ignore any environment proxy variable and connect directly to the host, default isFalselocale: Thewsmv:Localevalue to set on each WSMan request. This specifies the language in which the cleint wants response text to be translated, default isen-USdata_locale: Thewsmv:DataLocalevalue to set on each WSMan request. This specifies the format in which numerical data is presented in the response text, default is the value oflocalereconnection_retries: Number of retries on a connection problem, default is0reconnection_backoff: Number of seconds to backoff in between reconnection attempts (first sleeps X, then sleeps 2X, 4X, 8*X, ...), default is2.0certificate_key_pem: The path to the certificate key used incertificateauthenticationcertificate_pem: The path to the certificate used incertificateauthenticationcredssp_auth_mechanism: The sub-auth mechanism used in CredSSP, default isauto, choices areauto,ntlm, orkerberoscredssp_disable_tlsv1_2: Whether to used CredSSP auth over the insecure TLSv1.0, default isFalsecredssp_minimum_version: The minimum CredSSP server version that the client will connect to, default is2negotiate_delegate: Whether to negotiate the credential to the host, default isFalse. This is only valid ifnegotiateauth negotiated Kerberos orkerberoswas explicitly setnegotiate_hostname_override: The hostname used to calculate the host SPN when authenticating the host with Kerberos auth. This is only valid ifnegotiateauth negotiated Kerberos orkerberoswas explicitly setnegotiate_send_cbt: Whether to binding the channel binding token (HTTPS only) to the auth or ignore, default isTruenegotiate_service: Override the service part of the calculated SPN used when authenticating the server, default isWSMAN. This is only valid ifnegotiateauth negotiated Kerberos orkerberoswas explicitly setWhen running over HTTP, this library will enforce encryption by default but if
that is not supported (Basic auth) or isn't available on the host then either
use HTTPS or disable encryption withencryption="never".There are plans to add support for SSH as a connection but this still needs to
be implemented. SSH will work on hosts that are running PowerShell Core but
not the standard PowerShell.ShellThere are two shells that can be used in this library,pypsrp.shell.WinRSandpypsrp.powershell.RunspacePool.WinRSis a cmd shell that can be used to issue cmd commands, including but
not limited to other executables. Here are the options that can be used to
configure aWinRSshell;wsman: WinRS only works over WSMan, so this is thepypsrp.wsman.WSManobject to run the commands overresource_uri: The resource uri of the shell, defaults tohttp://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmdid: The ID if the shell, this should be kept asNoneas it is created dynamically by the serverinput_streams: The input stream(s) of the shell, default isstdinoutput_streams: The output stream(s) of the shell, default isstdout, stderrcodepage: The codepage of the shell, default is the default of the hostenvironment: A dictionary of environment key/values to set for the remote shellidle_time_out: THe idle timeout in seconds of the shelllifetime: The total lifetime of the shellname: The name (description only) of the shellno_profile: Whether to create the shell with the user profile loaded or notworking_directory: The default working directory of the created shellRunspacePoolis a shell used by the PSRP protocol, it is designed to be a
close implementation of the .NETSystem.Management.Automation.Runspaces.RunspacePoolclass. The methods and properties are similar and can mostly do the same thing.
Here are the options that can be used to configure aRunspacePoolshell;connection: The connection object used by the RunspacePool to send commands to the remote server, currently only supportsWSManapartment_state: The int value ofpypsrp.complex_objects.ApartmentStatefor the remote thread, default isUNKNOWNthread_options: The int value ofpypsrp.complex_objects.ThreadOptionsthat specifies the type of thread to create, default isDEFAULThost: The local host info implementation, default is no hostconfiguration_name: The configuration name to connect to, default isMicrosoft.PowerShelland can be used to specify the Just Enough Administration (JEA) to connect tomin_runspaces: The minimuum number of runspaces that a pool can hold, default is 1max_runspaces: The maximum number of runspaces that a pool can hold. Each PowerShell pipeline is run in a single Runspace, default is 1session_key_timeout_ms: The maximum time to wait for a session key transfer from the serverProcessThere are two process objects that can be used,pypsrp.shell.Processfor theWinRSshell andpypsrp.powershell.PowerShellfor theRunspacePoolshell.
These objects are ultimately used to execute commands, processes, or scripts on
the remote host.Processis used with theWinRSshell to execute a cmd command or another
executable. The following options are used to configure theProcessobject;shell: TheWinRSshell the process is run overexecutable: The executable or command to runarguments: A list of arguments to the executable or command, default is no argumentsid: The ID of the created command, if not specified then this is dynamically createdno_shell: Whether to create a command in the cmd shell or bypass it, default isFalse. IfTruethen the executable must be the full path to the exe. This only works on older OS' before 2012 R2 (not including)To execute the process, call.invoke(), thestdout,stderr, andrcproperties contain the output of the command once complete.PowerShellis used by the PSRP protocol, it is designed to be a close
implementation of theSystem.Management.Automation.PowerShellclass. The methods and properties are similar and can mostly do the same thing.
Here are the options that can be used to configure aPowerShellprocess;runspace_pool: TheRunspacePoolobject to run thePowerShellprocess onTo execute the process, call.invoke(), theoutput,had_erros, andstreamscontains the execution status and output information of the process.
Before invoke can be called, cmdlets or scripts must be added. These can be
done with the following methods;add_script: Add a raw PowerShell script to the pending commandsadd_cmdlet: Add a cmdlet to the pending commandsadd_parameters: Add a dictionary of key/value parameters to the last added commandadd_argument: Add a value argument to the last added commandadd_statement: Set the last command/script to be the end of that pipeline so the next command/script is like a newlineSee the examples below for more details.ExamplesHow to use the high level client APIfrompypsrp.clientimportClient# this takes in the same kwargs as the WSMan objectwithClient("server",username="user",password="password")asclient:# execute a cmd commandstdout,stderr,rc=client.execute_cmd("dir")stdout,stderr,rc=client.execute_cmd("powershell.exe gci $pwd")sanitised_stderr=client.sanitise_clixml(stderr)# execute a PowerShell scriptoutput,streams,had_errors=client.execute_ps('''$path = "%s"if (Test-Path -Path $path) {Remove-Item -Path $path -Force -Recurse}New-Item -Path $path -ItemType Directory'''%path)output,streams,had_errors=client.execute_ps("New-Item -Path C:\\temp\\folder -ItemType Directory")# copy a file from the local host to the remote hostclient.copy("~/file.txt","C:\\temp\\file.txt")# fetch a file from the remote host to the local hostclient.fetch("C:\\temp\\file.txt","~/file.txt")How to use WinRS/Process to execute a commandfrompypsrp.shellimportProcess,SignalCode,WinRSfrompypsrp.wsmanimportWSMan# creates a http connection with no encryption and basic authwsman=WSMan("server",ssl=False,auth="basic",encryption="never",username="vagrant",password="vagrant")withwsman,WinRS(wsman)asshell:process=Process(shell,"dir")process.invoke()process.signal(SignalCode.CTRL_C)# execute a process with arguments in the backgroundprocess=Process(shell,"powershell",["gci","$pwd"])process.begin_invoke()# start the invocation and return immediatelyprocess.poll_invoke()# update the output streamprocess.end_invoke()# finally wait until the process is finishedprocess.signal(SignalCode.CTRL_C)How to use RunspacePool/PowerShell to execute a PowerShell script/commandfrompypsrp.powershellimportPowerShell,RunspacePoolfrompypsrp.wsmanimportWSMan# creates a https connection with explicit kerberos auth and implicit credentialswsman=WSMan("server",auth="kerberos",cert_validation=False))withwsman,RunspacePool(wsman)aspool:# execute 'Get-Process | Select-Object Name'ps=PowerShell(pool)ps.add_cmdlet("Get-Process").add_cmdlet("Select-Object").add_argument("Name")output=ps.invoke()# execute 'Get-Process | Select-Object -Property Name'ps.add_cmdlet("Get-Process").add_cmdlet("Select-Object")ps.add_parameter("Property","Name")ps.begin_invoke()# execute process in the backgroundps.poll_invoke()# update the output streamsps.end_invoke()# wait until the process is finished# execute 'Get-Process | Select-Object -Property Name; Get-Service audiosrv'ps.add_cmdlet("Get-Process").add_cmdlet("Select-Object").add_parameter("Property","Name")ps.add_statement()ps.add_cmdlet("Get-Service").add_argument("audiosrc")ps.invoke()# execute a PowerShell script with input being sentscript='''begin {$DebugPreference = "Continue"Write-Debug -Message "begin"} process {Write-Output -InputObject $input} end {Write-Debug -Message "end"}'''ps.add_script(script)ps.invoke(["string",1])print(ps.output)print(ps.streams.debug)LoggingThis library takes advantage of the Python logging configuration and messages
are logged to thepypsrpnamed logger as well aspypsrp.*where*is each
Python script in thepypsrpdirectory.An easy way to turn on logging for the entire library is to create the
following JSON file and run your script withPYPSRP_LOG_CFG=log.json python script.py(this does not work with Python
2.6).{"version":1,"disable_existing_loggers":false,"formatters":{"simple":{"format":"%(asctime)s - %(name)s - %(levelname)s - %(message)s"}},"handlers":{"console":{"class":"logging.StreamHandler","level":"DEBUG","formatter":"simple","stream":"ext://sys.stdout"}},"loggers":{"pypsrp":{"level":"DEBUG","handlers":["console"],"propagate":"no"}}}You can adjust the log level by changing the level value inloggertoINFO.Note:DEBUGcontains a lot of information and will output all the messages
sent to and from the client. This can have the side effect of leaking sensitive
information and should only be used for debugging purposes.TestingAny changes are more than welcome in pull request form, you can run the current
test suite with tox like so;# make sure tox is installedpipinstalltox# run the tox suitetox# or run the test manually for the current Python environmentpy.test-v--pep8--covpypsrp--cov-reportterm-missingA lot of the tests either simulate a remote Windows host but you can also run a
lot of them against a real Windows host. To do this, set the following
environment variables before running the tests;PYPSRP_SERVER: The hostname or IP of the remote hostPYPSRP_USERNAME: The username to connect withPYPSRP_PASSWORD: The password to connect withPYPSRR_PORT: The port to connect with (default:5986)PYPSRP_AUTH: The authentication protocol to auth with (default:negotiate)There are further integration tests that require a specific host setup to run
correctly. You can useVagrantto set this host up. This is done by running
the following commands;# download the Vagrant box and start it up based on the Vagrantfilevagrantup# once the above script is complete run the followingvagrantssh# password is vagrantpowershell.exe
Register-PSSessionConfiguration-Path"C:\Users\vagrant\Documents\JEARoleSettings.pssc"-NameJEARole-Force$sec_pass=ConvertTo-SecureString-String"vagrant"-AsPlainText-Force$credential=New-Object-TypeNameSystem.Management.Automation.PSCredential-ArgumentList"vagrant",$sec_pass$thumbprint=(Get-ChildItem-PathCert:\LocalMachine\TrustedPeople)[0].Thumbprint

New-Item-PathWSMan:\localhost\ClientCertificate`-Subject"vagrant@localhost"`-URI*`-Issuer$thumbprint`-Credential$credential`-Force# exit the remote PowerShell sessionexit# exist the SSH sessionexitOnce complete, set the following environment variables to run the integration
tests;PYPSRP_RUN_INTEGRATION: To any valuePYPSRP_SERVER: Set to127.0.0.1PYPSRP_USERNAME: Set tovagrantPYPSRP_PASSWORD: Set tovagrantPYPSRP_HTTP_PORT: Set to55985PYPSRP_HTTPS_PORT: Set to55986PYPSRP_CERT_DIR: Set to the full path of the project directoryFrom here you can run the normal test suite and it will run all the integration
tests.BacklogLook at implementing the following transport optionsNamed pipesSSHUpdate CI to use named pipes for integration testsAdd Ansible playbook for better integration testsImproved serialization between Python and .NET objectsLive interactive console for PSRP