diff options
| author | CoprDistGit <infra@openeuler.org> | 2023-04-11 01:47:16 +0000 |
|---|---|---|
| committer | CoprDistGit <infra@openeuler.org> | 2023-04-11 01:47:16 +0000 |
| commit | 8563241043b4e47e72e48ac1aed826a80a467e85 (patch) | |
| tree | b994bd3f28430fca23edc57ccc64dd3b9c14b544 | |
| parent | 142bb0f918c89b042908c505bfaa59f57cf772f1 (diff) | |
automatic import of python-pypsrp
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | python-pypsrp.spec | 1574 | ||||
| -rw-r--r-- | sources | 1 |
3 files changed, 1576 insertions, 0 deletions
@@ -0,0 +1 @@ +/pypsrp-0.8.1.tar.gz diff --git a/python-pypsrp.spec b/python-pypsrp.spec new file mode 100644 index 0000000..00f0506 --- /dev/null +++ b/python-pypsrp.spec @@ -0,0 +1,1574 @@ +%global _empty_manifest_terminate_build 0 +Name: python-pypsrp +Version: 0.8.1 +Release: 1 +Summary: PowerShell Remoting Protocol and WinRM for Python +License: MIT +URL: https://github.com/jborean93/pypsrp +Source0: https://mirrors.nju.edu.cn/pypi/web/packages/57/da/3d9295972c20624c79843c1c14cf06fc6b0575ba786c1f72d6ca5bc5b9d5/pypsrp-0.8.1.tar.gz +BuildArch: noarch + +Requires: python3-cryptography +Requires: python3-pyspnego +Requires: python3-requests +Requires: python3-requests-credssp +Requires: python3-pyspnego[kerberos] + +%description +# pypsrp - Python PowerShell Remoting Protocol Client library + +[](https://github.com/jborean93/pypsrp/actions/workflows/ci.yml) +[](https://codecov.io/gh/jborean93/pypsrp) +[](https://badge.fury.io/py/pypsrp) + +pypsrp 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 scripts +* A WSMan interface to execute various WSMan calls like `Send`, `Create`, `Connect`, `Disconnect`, etc +* A Windows Remote Shell (WinRS) layer that executes cmd commands and executables using the base WinRM protocol +* A PowerShell Remoting Protocol (PSRP) layer allows you to create remote Runspace Pools and PowerShell pipelines + +At a basic level, you can use this library to; + +* Execute a cmd command +* Run another executable +* Execute PowerShell scripts +* Copy a file from the localhost to the remote Windows host +* Fetch a file from the remote Windows host to the localhost +* Create a Runspace Pool that contains one or multiple PowerShell pipelines and execute them asynchronously +* Support for a reference host base implementation of PSRP for interactive scripts + +Currently 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; + +* Basic +* Certificate +* NTLM + +It also supports `Negotiate/Kerberos`, and `CredSSP` but require extra +libraries to be installed. + + +## Requirements + +See `How to Install` for more details + +* CPython 3.6+ +* [cryptography](https://github.com/pyca/cryptography) +* [pyspnego](https://github.com/jborean93/pyspnego) +* [requests](https://github.com/requests/requests) + +### Optional Requirements + +The following Python libraries can be installed to add extra features that do +not come with the base package: + +* [python-gssapi](https://github.com/pythongssapi/python-gssapi) for Kerberos authentication on Linux +* [pykrb5](https://github.com/jborean93/pykrb5) for Kerberos authentication on Linux +* [requests-credssp](https://github.com/jborean93/requests-credssp) for CredSSP authentication + + +## How to Install + +To install pypsrp with all the basic features, run: + +```bash +pip install pypsrp +``` + +### Kerberos Authentication + +While 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 + +```bash +# For Python 2 +apt-get install gcc python-dev libkrb5-dev + +# For Python 3 +apt-get install gcc python3-dev libkrb5-dev + +# To add NTLM to the GSSAPI SPNEGO auth run +apt-get install gss-ntlmssp +``` + +For RHEL/Centos + +```bash +yum install gcc python-devel krb5-devel + +# To add NTLM to the GSSAPI SPNEGO auth run +yum install gssntlmssp +``` + +For Fedora + +```bash +dnf install gcc python-devel krb5-devel + +# To add NTLM to the GSSAPI SPNEGO auth run +dnf install gssntlmssp +``` + +For Arch Linux + +```bash +pacman -S gcc krb5 +``` + +Once installed you can install the Python packages with + +```bash +pip install pypsrp[kerberos] +``` + +Kerberos also needs to be configured to talk to the domain but that is outside +the scope of this page. + +### CredSSP Authentication + +Like Kerberos auth, CredSSP is supported but isn't included by default. To add +support for CredSSP auth try to run the following + +```bash +pip install pypsrp[credssp] +``` + +If that fails you may need to update pip and setuptools to a newer version +`pip install -U pip setuptools`. + + +## How to Use + +There are 3 main components that are in use within this library; + +* `Transport`: Handles the raw transport of messages to and from the server +* `Shell`: Handles the WSMV or PSRP protocol details used to create the remote shell that processes are run on, uses `Connection` to send the details +* `Process`: Runs the process or script within a shell + +### Connection + +Currently only the connection that is supported is the WSMan protocol over HTTP +through `pypsrp.wsman.WSMan` and offers mostly all the same features in the +WSMV spec including; + +* Basic, Certificate, Negotiate, Kerberos, and CredSSP authentication +* TLS encryption +* Message encryption with Negotiate, Kerberos, and CredSSP authentication +* Definable proxy + +These are the options that can be used to setup `WSMan`; + +* `server`: The hostname or IP address of the host to connect to +* `max_envelope_size`: The maximum envelope size, in bytes, that can be sent to the server, default is `153600` +* `operation_timeout`: The operation timeout, in seconds, of each WSMan operation, default is `20`. This should always be lower than `read_timeout`. +* `port`: The port to connect to, default is `5986` if `ssl=True` else `5985` +* `username`: The username to connect with, required for all auths except `certificate` and optionally required for `negotiate/kerberos` +* `password`: The password for `username`. Due to a bug on MacOS/Heimdal GSSAPI implementations, this will persist in the user's ccache when using Negotiate or Kerberos authentication, run `kdestroy` manually to remove this +* `ssl`: Whether to connect over `https` or `https`, default is `True` +* `path`: The WinRM path to connect to, default is `wsman` +* `auth`: The authentication protocol to use, default is `negotiate`, choices are `basic`, `certificate`, `negotiate`, `ntlm`, `kerberos`, `credssp` +* `cert_validation`: Whether to validate the server's SSL certificate, default is `True`. Can be `False` to not validate or a path to a PEM file of trusted certificates +* `connection_timeout`: The timeout for creating a HTTP connection, default is `30` +* `read_timeout`: The timeout for receiving a response from the server after a request has been made, default is `30` +* `encryption`: Controls the encryption settings, default is `auto`, choices are `auto`, `always`, `never`. Set to `always` to always run message encryption even over HTTPS, `never` to never use message encryption even over HTTP +* `proxy`: The proxy URL used to connect to the remote host +* `no_proxy`: Whether to ignore any environment proxy variable and connect directly to the host, default is `False` +* `locale`: The `wsmv:Locale` value to set on each WSMan request. This specifies the language in which the cleint wants response text to be translated, default is `en-US` +* `data_locale`: The `wsmv:DataLocale` value to set on each WSMan request. This specifies the format in which numerical data is presented in the response text, default is the value of `locale` +* `reconnection_retries`: Number of retries on a connection problem, default is `0` +* `reconnection_backoff`: Number of seconds to backoff in between reconnection attempts (first sleeps X, then sleeps 2*X, 4*X, 8*X, ...), default is `2.0` +* `certificate_key_pem`: The path to the certificate key used in `certificate` authentication +* `certificate_pem`: The path to the certificate used in `certificate` authentication +* `credssp_auth_mechanism`: The sub-auth mechanism used in CredSSP, default is `auto`, choices are `auto`, `ntlm`, or `kerberos` +* `credssp_disable_tlsv1_2`: Whether to used CredSSP auth over the insecure TLSv1.0, default is `False` +* `credssp_minimum_version`: The minimum CredSSP server version that the client will connect to, default is `2` +* `negotiate_delegate`: Whether to negotiate the credential to the host, default is `False`. This is only valid if `negotiate` auth negotiated Kerberos or `kerberos` was explicitly set +* `negotiate_hostname_override`: The hostname used to calculate the host SPN when authenticating the host with Kerberos auth. This is only valid if `negotiate` auth negotiated Kerberos or `kerberos` was explicitly set +* `negotiate_send_cbt`: Whether to binding the channel binding token (HTTPS only) to the auth or ignore, default is `True` +* `negotiate_service`: Override the service part of the calculated SPN used when authenticating the server, default is `WSMAN`. This is only valid if `negotiate` auth negotiated Kerberos or `kerberos` was explicitly set + +When 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 with `encryption="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. + +### Shell + +There are two shells that can be used in this library, `pypsrp.shell.WinRS` and +`pypsrp.powershell.RunspacePool`. + +`WinRS` is 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 a `WinRS` shell; + +* `wsman`: WinRS only works over WSMan, so this is the `pypsrp.wsman.WSMan` object to run the commands over +* `resource_uri`: The resource uri of the shell, defaults to `http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd` +* `id`: The ID if the shell, this should be kept as `None` as it is created dynamically by the server +* `input_streams`: The input stream(s) of the shell, default is `stdin` +* `output_streams`: The output stream(s) of the shell, default is `stdout, stderr` +* `codepage`: The codepage of the shell, default is the default of the host +* `environment`: A dictionary of environment key/values to set for the remote shell +* `idle_time_out`: THe idle timeout in seconds of the shell +* `lifetime`: The total lifetime of the shell +* `name`: The name (description only) of the shell +* `no_profile`: Whether to create the shell with the user profile loaded or not +* `working_directory`: The default working directory of the created shell + +`RunspacePool` is a shell used by the PSRP protocol, it is designed to be a +close implementation of the .NET +[System.Management.Automation.Runspaces.RunspacePool](https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.runspaces.runspacepool?view=powershellsdk-1.1.0) +class. The methods and properties are similar and can mostly do the same thing. +Here are the options that can be used to configure a `RunspacePool` shell; + +* `connection`: The connection object used by the RunspacePool to send commands to the remote server, currently only supports `WSMan` +* `apartment_state`: The int value of `pypsrp.complex_objects.ApartmentState` for the remote thread, default is `UNKNOWN` +* `thread_options`: The int value of `pypsrp.complex_objects.ThreadOptions` that specifies the type of thread to create, default is `DEFAULT` +* `host`: The local host info implementation, default is no host +* `configuration_name`: The configuration name to connect to, default is `Microsoft.PowerShell` and can be used to specify the Just Enough Administration (JEA) to connect to +* `min_runspaces`: The minimuum number of runspaces that a pool can hold, default is 1 +* `max_runspaces`: The maximum number of runspaces that a pool can hold. Each PowerShell pipeline is run in a single Runspace, default is 1 +* `session_key_timeout_ms`: The maximum time to wait for a session key transfer from the server + +### Process + +There are two process objects that can be used, `pypsrp.shell.Process` for the +`WinRS` shell and `pypsrp.powershell.PowerShell` for the `RunspacePool` shell. +These objects are ultimately used to execute commands, processes, or scripts on +the remote host. + +`Process` is used with the `WinRS` shell to execute a cmd command or another +executable. The following options are used to configure the `Process` object; + +* `shell`: The `WinRS` shell the process is run over +* `executable`: The executable or command to run +* `arguments`: A list of arguments to the executable or command, default is no arguments +* `id`: The ID of the created command, if not specified then this is dynamically created +* `no_shell`: Whether to create a command in the cmd shell or bypass it, default is `False`. If `True` then 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()`, the `stdout`, `stderr`, and `rc` +properties contain the output of the command once complete. + +`PowerShell` is used by the PSRP protocol, it is designed to be a close +implementation of the +[System.Management.Automation.PowerShell](https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.powershell?view=powershellsdk-1.1.0) +class. The methods and properties are similar and can mostly do the same thing. +Here are the options that can be used to configure a `PowerShell` process; + +* `runspace_pool`: The `RunspacePool` object to run the `PowerShell` process on + +To execute the process, call `.invoke()`, the `output`, `had_erros`, and +`streams` contains 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 commands +* `add_cmdlet`: Add a cmdlet to the pending commands +* `add_parameters`: Add a dictionary of key/value parameters to the last added command +* `add_argument`: Add a value argument to the last added command +* `add_statement`: Set the last command/script to be the end of that pipeline so the next command/script is like a newline + +See the examples below for more details. + +### Examples + +How to use the high level client API + +```python +from pypsrp.client import Client + +# this takes in the same kwargs as the WSMan object +with Client("server", username="user", password="password") as client: + + # execute a cmd command + stdout, 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 script + output, 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 host + client.copy("~/file.txt", "C:\\temp\\file.txt") + + # fetch a file from the remote host to the local host + client.fetch("C:\\temp\\file.txt", "~/file.txt") +``` + +How to use WinRS/Process to execute a command + + +```python +from pypsrp.shell import Process, SignalCode, WinRS +from pypsrp.wsman import WSMan + +# creates a http connection with no encryption and basic auth +wsman = WSMan("server", ssl=False, auth="basic", encryption="never", + username="vagrant", password="vagrant") + +with wsman, WinRS(wsman) as shell: + process = Process(shell, "dir") + process.invoke() + process.signal(SignalCode.CTRL_C) + + # execute a process with arguments in the background + process = Process(shell, "powershell", ["gci", "$pwd"]) + process.begin_invoke() # start the invocation and return immediately + process.poll_invoke() # update the output stream + process.end_invoke() # finally wait until the process is finished + process.signal(SignalCode.CTRL_C) +``` + +How to use RunspacePool/PowerShell to execute a PowerShell script/command + +```python +from pypsrp.powershell import PowerShell, RunspacePool +from pypsrp.wsman import WSMan + +# creates a https connection with explicit kerberos auth and implicit credentials +wsman = WSMan("server", auth="kerberos", cert_validation=False)) + +with wsman, RunspacePool(wsman) as pool: + # 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 background + ps.poll_invoke() # update the output streams + ps.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 sent + script = '''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) +``` + + +## Logging + +This library takes advantage of the Python logging configuration and messages +are logged to the `pypsrp` named logger as well as `pypsrp.*` where `*` is each +Python script in the `pypsrp` directory. + +An easy way to turn on logging for the entire library is to create the +following JSON file and run your script with +`PYPSRP_LOG_CFG=log.json python script.py` (this does not work with Python +2.6). + +```json +{ + "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 in `logger` to `INFO`. + +_Note: `DEBUG` contains 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._ + + +## Testing + +Any changes are more than welcome in pull request form, you can run the current +test suite with tox like so; + +```bash +# make sure tox is installed +pip install tox + +# run the tox suite +tox + +# or run the test manually for the current Python environment +py.test -v --pep8 --cov pypsrp --cov-report term-missing +``` + +A 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 host +* `PYPSRP_USERNAME`: The username to connect with +* `PYPSRP_PASSWORD`: The password to connect with +* `PYPSRR_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 use `Vagrant` to set this host up. This is done by running +the following commands; + +```bash +# download the Vagrant box and start it up based on the Vagrantfile +vagrant up + +# once the above script is complete run the following +vagrant ssh # password is vagrant + +powershell.exe +Register-PSSessionConfiguration -Path "C:\Users\vagrant\Documents\JEARoleSettings.pssc" -Name JEARole -Force + +$sec_pass = ConvertTo-SecureString -String "vagrant" -AsPlainText -Force +$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "vagrant", $sec_pass +$thumbprint = (Get-ChildItem -Path Cert:\LocalMachine\TrustedPeople)[0].Thumbprint + +New-Item -Path WSMan:\localhost\ClientCertificate ` + -Subject "vagrant@localhost" ` + -URI * ` + -Issuer $thumbprint ` + -Credential $credential ` + -Force + + +# exit the remote PowerShell session +exit + +# exist the SSH session +exit +``` + +Once complete, set the following environment variables to run the integration +tests; + +* `PYPSRP_RUN_INTEGRATION`: To any value +* `PYPSRP_SERVER`: Set to `127.0.0.1` +* `PYPSRP_USERNAME`: Set to `vagrant` +* `PYPSRP_PASSWORD`: Set to `vagrant` +* `PYPSRP_HTTP_PORT`: Set to `55985` +* `PYPSRP_HTTPS_PORT`: Set to `55986` +* `PYPSRP_CERT_DIR`: Set to the full path of the project directory + +From here you can run the normal test suite and it will run all the integration +tests. + + +## Backlog + +* Look at implementing the following transport options + * Named pipes + * SSH +* Update CI to use named pipes for integration tests +* Add Ansible playbook for better integration tests +* Improved serialization between Python and .NET objects +* Live interactive console for PSRP + + + + +%package -n python3-pypsrp +Summary: PowerShell Remoting Protocol and WinRM for Python +Provides: python-pypsrp +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-pip +%description -n python3-pypsrp +# pypsrp - Python PowerShell Remoting Protocol Client library + +[](https://github.com/jborean93/pypsrp/actions/workflows/ci.yml) +[](https://codecov.io/gh/jborean93/pypsrp) +[](https://badge.fury.io/py/pypsrp) + +pypsrp 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 scripts +* A WSMan interface to execute various WSMan calls like `Send`, `Create`, `Connect`, `Disconnect`, etc +* A Windows Remote Shell (WinRS) layer that executes cmd commands and executables using the base WinRM protocol +* A PowerShell Remoting Protocol (PSRP) layer allows you to create remote Runspace Pools and PowerShell pipelines + +At a basic level, you can use this library to; + +* Execute a cmd command +* Run another executable +* Execute PowerShell scripts +* Copy a file from the localhost to the remote Windows host +* Fetch a file from the remote Windows host to the localhost +* Create a Runspace Pool that contains one or multiple PowerShell pipelines and execute them asynchronously +* Support for a reference host base implementation of PSRP for interactive scripts + +Currently 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; + +* Basic +* Certificate +* NTLM + +It also supports `Negotiate/Kerberos`, and `CredSSP` but require extra +libraries to be installed. + + +## Requirements + +See `How to Install` for more details + +* CPython 3.6+ +* [cryptography](https://github.com/pyca/cryptography) +* [pyspnego](https://github.com/jborean93/pyspnego) +* [requests](https://github.com/requests/requests) + +### Optional Requirements + +The following Python libraries can be installed to add extra features that do +not come with the base package: + +* [python-gssapi](https://github.com/pythongssapi/python-gssapi) for Kerberos authentication on Linux +* [pykrb5](https://github.com/jborean93/pykrb5) for Kerberos authentication on Linux +* [requests-credssp](https://github.com/jborean93/requests-credssp) for CredSSP authentication + + +## How to Install + +To install pypsrp with all the basic features, run: + +```bash +pip install pypsrp +``` + +### Kerberos Authentication + +While 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 + +```bash +# For Python 2 +apt-get install gcc python-dev libkrb5-dev + +# For Python 3 +apt-get install gcc python3-dev libkrb5-dev + +# To add NTLM to the GSSAPI SPNEGO auth run +apt-get install gss-ntlmssp +``` + +For RHEL/Centos + +```bash +yum install gcc python-devel krb5-devel + +# To add NTLM to the GSSAPI SPNEGO auth run +yum install gssntlmssp +``` + +For Fedora + +```bash +dnf install gcc python-devel krb5-devel + +# To add NTLM to the GSSAPI SPNEGO auth run +dnf install gssntlmssp +``` + +For Arch Linux + +```bash +pacman -S gcc krb5 +``` + +Once installed you can install the Python packages with + +```bash +pip install pypsrp[kerberos] +``` + +Kerberos also needs to be configured to talk to the domain but that is outside +the scope of this page. + +### CredSSP Authentication + +Like Kerberos auth, CredSSP is supported but isn't included by default. To add +support for CredSSP auth try to run the following + +```bash +pip install pypsrp[credssp] +``` + +If that fails you may need to update pip and setuptools to a newer version +`pip install -U pip setuptools`. + + +## How to Use + +There are 3 main components that are in use within this library; + +* `Transport`: Handles the raw transport of messages to and from the server +* `Shell`: Handles the WSMV or PSRP protocol details used to create the remote shell that processes are run on, uses `Connection` to send the details +* `Process`: Runs the process or script within a shell + +### Connection + +Currently only the connection that is supported is the WSMan protocol over HTTP +through `pypsrp.wsman.WSMan` and offers mostly all the same features in the +WSMV spec including; + +* Basic, Certificate, Negotiate, Kerberos, and CredSSP authentication +* TLS encryption +* Message encryption with Negotiate, Kerberos, and CredSSP authentication +* Definable proxy + +These are the options that can be used to setup `WSMan`; + +* `server`: The hostname or IP address of the host to connect to +* `max_envelope_size`: The maximum envelope size, in bytes, that can be sent to the server, default is `153600` +* `operation_timeout`: The operation timeout, in seconds, of each WSMan operation, default is `20`. This should always be lower than `read_timeout`. +* `port`: The port to connect to, default is `5986` if `ssl=True` else `5985` +* `username`: The username to connect with, required for all auths except `certificate` and optionally required for `negotiate/kerberos` +* `password`: The password for `username`. Due to a bug on MacOS/Heimdal GSSAPI implementations, this will persist in the user's ccache when using Negotiate or Kerberos authentication, run `kdestroy` manually to remove this +* `ssl`: Whether to connect over `https` or `https`, default is `True` +* `path`: The WinRM path to connect to, default is `wsman` +* `auth`: The authentication protocol to use, default is `negotiate`, choices are `basic`, `certificate`, `negotiate`, `ntlm`, `kerberos`, `credssp` +* `cert_validation`: Whether to validate the server's SSL certificate, default is `True`. Can be `False` to not validate or a path to a PEM file of trusted certificates +* `connection_timeout`: The timeout for creating a HTTP connection, default is `30` +* `read_timeout`: The timeout for receiving a response from the server after a request has been made, default is `30` +* `encryption`: Controls the encryption settings, default is `auto`, choices are `auto`, `always`, `never`. Set to `always` to always run message encryption even over HTTPS, `never` to never use message encryption even over HTTP +* `proxy`: The proxy URL used to connect to the remote host +* `no_proxy`: Whether to ignore any environment proxy variable and connect directly to the host, default is `False` +* `locale`: The `wsmv:Locale` value to set on each WSMan request. This specifies the language in which the cleint wants response text to be translated, default is `en-US` +* `data_locale`: The `wsmv:DataLocale` value to set on each WSMan request. This specifies the format in which numerical data is presented in the response text, default is the value of `locale` +* `reconnection_retries`: Number of retries on a connection problem, default is `0` +* `reconnection_backoff`: Number of seconds to backoff in between reconnection attempts (first sleeps X, then sleeps 2*X, 4*X, 8*X, ...), default is `2.0` +* `certificate_key_pem`: The path to the certificate key used in `certificate` authentication +* `certificate_pem`: The path to the certificate used in `certificate` authentication +* `credssp_auth_mechanism`: The sub-auth mechanism used in CredSSP, default is `auto`, choices are `auto`, `ntlm`, or `kerberos` +* `credssp_disable_tlsv1_2`: Whether to used CredSSP auth over the insecure TLSv1.0, default is `False` +* `credssp_minimum_version`: The minimum CredSSP server version that the client will connect to, default is `2` +* `negotiate_delegate`: Whether to negotiate the credential to the host, default is `False`. This is only valid if `negotiate` auth negotiated Kerberos or `kerberos` was explicitly set +* `negotiate_hostname_override`: The hostname used to calculate the host SPN when authenticating the host with Kerberos auth. This is only valid if `negotiate` auth negotiated Kerberos or `kerberos` was explicitly set +* `negotiate_send_cbt`: Whether to binding the channel binding token (HTTPS only) to the auth or ignore, default is `True` +* `negotiate_service`: Override the service part of the calculated SPN used when authenticating the server, default is `WSMAN`. This is only valid if `negotiate` auth negotiated Kerberos or `kerberos` was explicitly set + +When 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 with `encryption="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. + +### Shell + +There are two shells that can be used in this library, `pypsrp.shell.WinRS` and +`pypsrp.powershell.RunspacePool`. + +`WinRS` is 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 a `WinRS` shell; + +* `wsman`: WinRS only works over WSMan, so this is the `pypsrp.wsman.WSMan` object to run the commands over +* `resource_uri`: The resource uri of the shell, defaults to `http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd` +* `id`: The ID if the shell, this should be kept as `None` as it is created dynamically by the server +* `input_streams`: The input stream(s) of the shell, default is `stdin` +* `output_streams`: The output stream(s) of the shell, default is `stdout, stderr` +* `codepage`: The codepage of the shell, default is the default of the host +* `environment`: A dictionary of environment key/values to set for the remote shell +* `idle_time_out`: THe idle timeout in seconds of the shell +* `lifetime`: The total lifetime of the shell +* `name`: The name (description only) of the shell +* `no_profile`: Whether to create the shell with the user profile loaded or not +* `working_directory`: The default working directory of the created shell + +`RunspacePool` is a shell used by the PSRP protocol, it is designed to be a +close implementation of the .NET +[System.Management.Automation.Runspaces.RunspacePool](https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.runspaces.runspacepool?view=powershellsdk-1.1.0) +class. The methods and properties are similar and can mostly do the same thing. +Here are the options that can be used to configure a `RunspacePool` shell; + +* `connection`: The connection object used by the RunspacePool to send commands to the remote server, currently only supports `WSMan` +* `apartment_state`: The int value of `pypsrp.complex_objects.ApartmentState` for the remote thread, default is `UNKNOWN` +* `thread_options`: The int value of `pypsrp.complex_objects.ThreadOptions` that specifies the type of thread to create, default is `DEFAULT` +* `host`: The local host info implementation, default is no host +* `configuration_name`: The configuration name to connect to, default is `Microsoft.PowerShell` and can be used to specify the Just Enough Administration (JEA) to connect to +* `min_runspaces`: The minimuum number of runspaces that a pool can hold, default is 1 +* `max_runspaces`: The maximum number of runspaces that a pool can hold. Each PowerShell pipeline is run in a single Runspace, default is 1 +* `session_key_timeout_ms`: The maximum time to wait for a session key transfer from the server + +### Process + +There are two process objects that can be used, `pypsrp.shell.Process` for the +`WinRS` shell and `pypsrp.powershell.PowerShell` for the `RunspacePool` shell. +These objects are ultimately used to execute commands, processes, or scripts on +the remote host. + +`Process` is used with the `WinRS` shell to execute a cmd command or another +executable. The following options are used to configure the `Process` object; + +* `shell`: The `WinRS` shell the process is run over +* `executable`: The executable or command to run +* `arguments`: A list of arguments to the executable or command, default is no arguments +* `id`: The ID of the created command, if not specified then this is dynamically created +* `no_shell`: Whether to create a command in the cmd shell or bypass it, default is `False`. If `True` then 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()`, the `stdout`, `stderr`, and `rc` +properties contain the output of the command once complete. + +`PowerShell` is used by the PSRP protocol, it is designed to be a close +implementation of the +[System.Management.Automation.PowerShell](https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.powershell?view=powershellsdk-1.1.0) +class. The methods and properties are similar and can mostly do the same thing. +Here are the options that can be used to configure a `PowerShell` process; + +* `runspace_pool`: The `RunspacePool` object to run the `PowerShell` process on + +To execute the process, call `.invoke()`, the `output`, `had_erros`, and +`streams` contains 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 commands +* `add_cmdlet`: Add a cmdlet to the pending commands +* `add_parameters`: Add a dictionary of key/value parameters to the last added command +* `add_argument`: Add a value argument to the last added command +* `add_statement`: Set the last command/script to be the end of that pipeline so the next command/script is like a newline + +See the examples below for more details. + +### Examples + +How to use the high level client API + +```python +from pypsrp.client import Client + +# this takes in the same kwargs as the WSMan object +with Client("server", username="user", password="password") as client: + + # execute a cmd command + stdout, 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 script + output, 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 host + client.copy("~/file.txt", "C:\\temp\\file.txt") + + # fetch a file from the remote host to the local host + client.fetch("C:\\temp\\file.txt", "~/file.txt") +``` + +How to use WinRS/Process to execute a command + + +```python +from pypsrp.shell import Process, SignalCode, WinRS +from pypsrp.wsman import WSMan + +# creates a http connection with no encryption and basic auth +wsman = WSMan("server", ssl=False, auth="basic", encryption="never", + username="vagrant", password="vagrant") + +with wsman, WinRS(wsman) as shell: + process = Process(shell, "dir") + process.invoke() + process.signal(SignalCode.CTRL_C) + + # execute a process with arguments in the background + process = Process(shell, "powershell", ["gci", "$pwd"]) + process.begin_invoke() # start the invocation and return immediately + process.poll_invoke() # update the output stream + process.end_invoke() # finally wait until the process is finished + process.signal(SignalCode.CTRL_C) +``` + +How to use RunspacePool/PowerShell to execute a PowerShell script/command + +```python +from pypsrp.powershell import PowerShell, RunspacePool +from pypsrp.wsman import WSMan + +# creates a https connection with explicit kerberos auth and implicit credentials +wsman = WSMan("server", auth="kerberos", cert_validation=False)) + +with wsman, RunspacePool(wsman) as pool: + # 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 background + ps.poll_invoke() # update the output streams + ps.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 sent + script = '''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) +``` + + +## Logging + +This library takes advantage of the Python logging configuration and messages +are logged to the `pypsrp` named logger as well as `pypsrp.*` where `*` is each +Python script in the `pypsrp` directory. + +An easy way to turn on logging for the entire library is to create the +following JSON file and run your script with +`PYPSRP_LOG_CFG=log.json python script.py` (this does not work with Python +2.6). + +```json +{ + "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 in `logger` to `INFO`. + +_Note: `DEBUG` contains 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._ + + +## Testing + +Any changes are more than welcome in pull request form, you can run the current +test suite with tox like so; + +```bash +# make sure tox is installed +pip install tox + +# run the tox suite +tox + +# or run the test manually for the current Python environment +py.test -v --pep8 --cov pypsrp --cov-report term-missing +``` + +A 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 host +* `PYPSRP_USERNAME`: The username to connect with +* `PYPSRP_PASSWORD`: The password to connect with +* `PYPSRR_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 use `Vagrant` to set this host up. This is done by running +the following commands; + +```bash +# download the Vagrant box and start it up based on the Vagrantfile +vagrant up + +# once the above script is complete run the following +vagrant ssh # password is vagrant + +powershell.exe +Register-PSSessionConfiguration -Path "C:\Users\vagrant\Documents\JEARoleSettings.pssc" -Name JEARole -Force + +$sec_pass = ConvertTo-SecureString -String "vagrant" -AsPlainText -Force +$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "vagrant", $sec_pass +$thumbprint = (Get-ChildItem -Path Cert:\LocalMachine\TrustedPeople)[0].Thumbprint + +New-Item -Path WSMan:\localhost\ClientCertificate ` + -Subject "vagrant@localhost" ` + -URI * ` + -Issuer $thumbprint ` + -Credential $credential ` + -Force + + +# exit the remote PowerShell session +exit + +# exist the SSH session +exit +``` + +Once complete, set the following environment variables to run the integration +tests; + +* `PYPSRP_RUN_INTEGRATION`: To any value +* `PYPSRP_SERVER`: Set to `127.0.0.1` +* `PYPSRP_USERNAME`: Set to `vagrant` +* `PYPSRP_PASSWORD`: Set to `vagrant` +* `PYPSRP_HTTP_PORT`: Set to `55985` +* `PYPSRP_HTTPS_PORT`: Set to `55986` +* `PYPSRP_CERT_DIR`: Set to the full path of the project directory + +From here you can run the normal test suite and it will run all the integration +tests. + + +## Backlog + +* Look at implementing the following transport options + * Named pipes + * SSH +* Update CI to use named pipes for integration tests +* Add Ansible playbook for better integration tests +* Improved serialization between Python and .NET objects +* Live interactive console for PSRP + + + + +%package help +Summary: Development documents and examples for pypsrp +Provides: python3-pypsrp-doc +%description help +# pypsrp - Python PowerShell Remoting Protocol Client library + +[](https://github.com/jborean93/pypsrp/actions/workflows/ci.yml) +[](https://codecov.io/gh/jborean93/pypsrp) +[](https://badge.fury.io/py/pypsrp) + +pypsrp 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 scripts +* A WSMan interface to execute various WSMan calls like `Send`, `Create`, `Connect`, `Disconnect`, etc +* A Windows Remote Shell (WinRS) layer that executes cmd commands and executables using the base WinRM protocol +* A PowerShell Remoting Protocol (PSRP) layer allows you to create remote Runspace Pools and PowerShell pipelines + +At a basic level, you can use this library to; + +* Execute a cmd command +* Run another executable +* Execute PowerShell scripts +* Copy a file from the localhost to the remote Windows host +* Fetch a file from the remote Windows host to the localhost +* Create a Runspace Pool that contains one or multiple PowerShell pipelines and execute them asynchronously +* Support for a reference host base implementation of PSRP for interactive scripts + +Currently 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; + +* Basic +* Certificate +* NTLM + +It also supports `Negotiate/Kerberos`, and `CredSSP` but require extra +libraries to be installed. + + +## Requirements + +See `How to Install` for more details + +* CPython 3.6+ +* [cryptography](https://github.com/pyca/cryptography) +* [pyspnego](https://github.com/jborean93/pyspnego) +* [requests](https://github.com/requests/requests) + +### Optional Requirements + +The following Python libraries can be installed to add extra features that do +not come with the base package: + +* [python-gssapi](https://github.com/pythongssapi/python-gssapi) for Kerberos authentication on Linux +* [pykrb5](https://github.com/jborean93/pykrb5) for Kerberos authentication on Linux +* [requests-credssp](https://github.com/jborean93/requests-credssp) for CredSSP authentication + + +## How to Install + +To install pypsrp with all the basic features, run: + +```bash +pip install pypsrp +``` + +### Kerberos Authentication + +While 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 + +```bash +# For Python 2 +apt-get install gcc python-dev libkrb5-dev + +# For Python 3 +apt-get install gcc python3-dev libkrb5-dev + +# To add NTLM to the GSSAPI SPNEGO auth run +apt-get install gss-ntlmssp +``` + +For RHEL/Centos + +```bash +yum install gcc python-devel krb5-devel + +# To add NTLM to the GSSAPI SPNEGO auth run +yum install gssntlmssp +``` + +For Fedora + +```bash +dnf install gcc python-devel krb5-devel + +# To add NTLM to the GSSAPI SPNEGO auth run +dnf install gssntlmssp +``` + +For Arch Linux + +```bash +pacman -S gcc krb5 +``` + +Once installed you can install the Python packages with + +```bash +pip install pypsrp[kerberos] +``` + +Kerberos also needs to be configured to talk to the domain but that is outside +the scope of this page. + +### CredSSP Authentication + +Like Kerberos auth, CredSSP is supported but isn't included by default. To add +support for CredSSP auth try to run the following + +```bash +pip install pypsrp[credssp] +``` + +If that fails you may need to update pip and setuptools to a newer version +`pip install -U pip setuptools`. + + +## How to Use + +There are 3 main components that are in use within this library; + +* `Transport`: Handles the raw transport of messages to and from the server +* `Shell`: Handles the WSMV or PSRP protocol details used to create the remote shell that processes are run on, uses `Connection` to send the details +* `Process`: Runs the process or script within a shell + +### Connection + +Currently only the connection that is supported is the WSMan protocol over HTTP +through `pypsrp.wsman.WSMan` and offers mostly all the same features in the +WSMV spec including; + +* Basic, Certificate, Negotiate, Kerberos, and CredSSP authentication +* TLS encryption +* Message encryption with Negotiate, Kerberos, and CredSSP authentication +* Definable proxy + +These are the options that can be used to setup `WSMan`; + +* `server`: The hostname or IP address of the host to connect to +* `max_envelope_size`: The maximum envelope size, in bytes, that can be sent to the server, default is `153600` +* `operation_timeout`: The operation timeout, in seconds, of each WSMan operation, default is `20`. This should always be lower than `read_timeout`. +* `port`: The port to connect to, default is `5986` if `ssl=True` else `5985` +* `username`: The username to connect with, required for all auths except `certificate` and optionally required for `negotiate/kerberos` +* `password`: The password for `username`. Due to a bug on MacOS/Heimdal GSSAPI implementations, this will persist in the user's ccache when using Negotiate or Kerberos authentication, run `kdestroy` manually to remove this +* `ssl`: Whether to connect over `https` or `https`, default is `True` +* `path`: The WinRM path to connect to, default is `wsman` +* `auth`: The authentication protocol to use, default is `negotiate`, choices are `basic`, `certificate`, `negotiate`, `ntlm`, `kerberos`, `credssp` +* `cert_validation`: Whether to validate the server's SSL certificate, default is `True`. Can be `False` to not validate or a path to a PEM file of trusted certificates +* `connection_timeout`: The timeout for creating a HTTP connection, default is `30` +* `read_timeout`: The timeout for receiving a response from the server after a request has been made, default is `30` +* `encryption`: Controls the encryption settings, default is `auto`, choices are `auto`, `always`, `never`. Set to `always` to always run message encryption even over HTTPS, `never` to never use message encryption even over HTTP +* `proxy`: The proxy URL used to connect to the remote host +* `no_proxy`: Whether to ignore any environment proxy variable and connect directly to the host, default is `False` +* `locale`: The `wsmv:Locale` value to set on each WSMan request. This specifies the language in which the cleint wants response text to be translated, default is `en-US` +* `data_locale`: The `wsmv:DataLocale` value to set on each WSMan request. This specifies the format in which numerical data is presented in the response text, default is the value of `locale` +* `reconnection_retries`: Number of retries on a connection problem, default is `0` +* `reconnection_backoff`: Number of seconds to backoff in between reconnection attempts (first sleeps X, then sleeps 2*X, 4*X, 8*X, ...), default is `2.0` +* `certificate_key_pem`: The path to the certificate key used in `certificate` authentication +* `certificate_pem`: The path to the certificate used in `certificate` authentication +* `credssp_auth_mechanism`: The sub-auth mechanism used in CredSSP, default is `auto`, choices are `auto`, `ntlm`, or `kerberos` +* `credssp_disable_tlsv1_2`: Whether to used CredSSP auth over the insecure TLSv1.0, default is `False` +* `credssp_minimum_version`: The minimum CredSSP server version that the client will connect to, default is `2` +* `negotiate_delegate`: Whether to negotiate the credential to the host, default is `False`. This is only valid if `negotiate` auth negotiated Kerberos or `kerberos` was explicitly set +* `negotiate_hostname_override`: The hostname used to calculate the host SPN when authenticating the host with Kerberos auth. This is only valid if `negotiate` auth negotiated Kerberos or `kerberos` was explicitly set +* `negotiate_send_cbt`: Whether to binding the channel binding token (HTTPS only) to the auth or ignore, default is `True` +* `negotiate_service`: Override the service part of the calculated SPN used when authenticating the server, default is `WSMAN`. This is only valid if `negotiate` auth negotiated Kerberos or `kerberos` was explicitly set + +When 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 with `encryption="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. + +### Shell + +There are two shells that can be used in this library, `pypsrp.shell.WinRS` and +`pypsrp.powershell.RunspacePool`. + +`WinRS` is 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 a `WinRS` shell; + +* `wsman`: WinRS only works over WSMan, so this is the `pypsrp.wsman.WSMan` object to run the commands over +* `resource_uri`: The resource uri of the shell, defaults to `http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd` +* `id`: The ID if the shell, this should be kept as `None` as it is created dynamically by the server +* `input_streams`: The input stream(s) of the shell, default is `stdin` +* `output_streams`: The output stream(s) of the shell, default is `stdout, stderr` +* `codepage`: The codepage of the shell, default is the default of the host +* `environment`: A dictionary of environment key/values to set for the remote shell +* `idle_time_out`: THe idle timeout in seconds of the shell +* `lifetime`: The total lifetime of the shell +* `name`: The name (description only) of the shell +* `no_profile`: Whether to create the shell with the user profile loaded or not +* `working_directory`: The default working directory of the created shell + +`RunspacePool` is a shell used by the PSRP protocol, it is designed to be a +close implementation of the .NET +[System.Management.Automation.Runspaces.RunspacePool](https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.runspaces.runspacepool?view=powershellsdk-1.1.0) +class. The methods and properties are similar and can mostly do the same thing. +Here are the options that can be used to configure a `RunspacePool` shell; + +* `connection`: The connection object used by the RunspacePool to send commands to the remote server, currently only supports `WSMan` +* `apartment_state`: The int value of `pypsrp.complex_objects.ApartmentState` for the remote thread, default is `UNKNOWN` +* `thread_options`: The int value of `pypsrp.complex_objects.ThreadOptions` that specifies the type of thread to create, default is `DEFAULT` +* `host`: The local host info implementation, default is no host +* `configuration_name`: The configuration name to connect to, default is `Microsoft.PowerShell` and can be used to specify the Just Enough Administration (JEA) to connect to +* `min_runspaces`: The minimuum number of runspaces that a pool can hold, default is 1 +* `max_runspaces`: The maximum number of runspaces that a pool can hold. Each PowerShell pipeline is run in a single Runspace, default is 1 +* `session_key_timeout_ms`: The maximum time to wait for a session key transfer from the server + +### Process + +There are two process objects that can be used, `pypsrp.shell.Process` for the +`WinRS` shell and `pypsrp.powershell.PowerShell` for the `RunspacePool` shell. +These objects are ultimately used to execute commands, processes, or scripts on +the remote host. + +`Process` is used with the `WinRS` shell to execute a cmd command or another +executable. The following options are used to configure the `Process` object; + +* `shell`: The `WinRS` shell the process is run over +* `executable`: The executable or command to run +* `arguments`: A list of arguments to the executable or command, default is no arguments +* `id`: The ID of the created command, if not specified then this is dynamically created +* `no_shell`: Whether to create a command in the cmd shell or bypass it, default is `False`. If `True` then 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()`, the `stdout`, `stderr`, and `rc` +properties contain the output of the command once complete. + +`PowerShell` is used by the PSRP protocol, it is designed to be a close +implementation of the +[System.Management.Automation.PowerShell](https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.powershell?view=powershellsdk-1.1.0) +class. The methods and properties are similar and can mostly do the same thing. +Here are the options that can be used to configure a `PowerShell` process; + +* `runspace_pool`: The `RunspacePool` object to run the `PowerShell` process on + +To execute the process, call `.invoke()`, the `output`, `had_erros`, and +`streams` contains 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 commands +* `add_cmdlet`: Add a cmdlet to the pending commands +* `add_parameters`: Add a dictionary of key/value parameters to the last added command +* `add_argument`: Add a value argument to the last added command +* `add_statement`: Set the last command/script to be the end of that pipeline so the next command/script is like a newline + +See the examples below for more details. + +### Examples + +How to use the high level client API + +```python +from pypsrp.client import Client + +# this takes in the same kwargs as the WSMan object +with Client("server", username="user", password="password") as client: + + # execute a cmd command + stdout, 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 script + output, 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 host + client.copy("~/file.txt", "C:\\temp\\file.txt") + + # fetch a file from the remote host to the local host + client.fetch("C:\\temp\\file.txt", "~/file.txt") +``` + +How to use WinRS/Process to execute a command + + +```python +from pypsrp.shell import Process, SignalCode, WinRS +from pypsrp.wsman import WSMan + +# creates a http connection with no encryption and basic auth +wsman = WSMan("server", ssl=False, auth="basic", encryption="never", + username="vagrant", password="vagrant") + +with wsman, WinRS(wsman) as shell: + process = Process(shell, "dir") + process.invoke() + process.signal(SignalCode.CTRL_C) + + # execute a process with arguments in the background + process = Process(shell, "powershell", ["gci", "$pwd"]) + process.begin_invoke() # start the invocation and return immediately + process.poll_invoke() # update the output stream + process.end_invoke() # finally wait until the process is finished + process.signal(SignalCode.CTRL_C) +``` + +How to use RunspacePool/PowerShell to execute a PowerShell script/command + +```python +from pypsrp.powershell import PowerShell, RunspacePool +from pypsrp.wsman import WSMan + +# creates a https connection with explicit kerberos auth and implicit credentials +wsman = WSMan("server", auth="kerberos", cert_validation=False)) + +with wsman, RunspacePool(wsman) as pool: + # 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 background + ps.poll_invoke() # update the output streams + ps.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 sent + script = '''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) +``` + + +## Logging + +This library takes advantage of the Python logging configuration and messages +are logged to the `pypsrp` named logger as well as `pypsrp.*` where `*` is each +Python script in the `pypsrp` directory. + +An easy way to turn on logging for the entire library is to create the +following JSON file and run your script with +`PYPSRP_LOG_CFG=log.json python script.py` (this does not work with Python +2.6). + +```json +{ + "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 in `logger` to `INFO`. + +_Note: `DEBUG` contains 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._ + + +## Testing + +Any changes are more than welcome in pull request form, you can run the current +test suite with tox like so; + +```bash +# make sure tox is installed +pip install tox + +# run the tox suite +tox + +# or run the test manually for the current Python environment +py.test -v --pep8 --cov pypsrp --cov-report term-missing +``` + +A 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 host +* `PYPSRP_USERNAME`: The username to connect with +* `PYPSRP_PASSWORD`: The password to connect with +* `PYPSRR_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 use `Vagrant` to set this host up. This is done by running +the following commands; + +```bash +# download the Vagrant box and start it up based on the Vagrantfile +vagrant up + +# once the above script is complete run the following +vagrant ssh # password is vagrant + +powershell.exe +Register-PSSessionConfiguration -Path "C:\Users\vagrant\Documents\JEARoleSettings.pssc" -Name JEARole -Force + +$sec_pass = ConvertTo-SecureString -String "vagrant" -AsPlainText -Force +$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "vagrant", $sec_pass +$thumbprint = (Get-ChildItem -Path Cert:\LocalMachine\TrustedPeople)[0].Thumbprint + +New-Item -Path WSMan:\localhost\ClientCertificate ` + -Subject "vagrant@localhost" ` + -URI * ` + -Issuer $thumbprint ` + -Credential $credential ` + -Force + + +# exit the remote PowerShell session +exit + +# exist the SSH session +exit +``` + +Once complete, set the following environment variables to run the integration +tests; + +* `PYPSRP_RUN_INTEGRATION`: To any value +* `PYPSRP_SERVER`: Set to `127.0.0.1` +* `PYPSRP_USERNAME`: Set to `vagrant` +* `PYPSRP_PASSWORD`: Set to `vagrant` +* `PYPSRP_HTTP_PORT`: Set to `55985` +* `PYPSRP_HTTPS_PORT`: Set to `55986` +* `PYPSRP_CERT_DIR`: Set to the full path of the project directory + +From here you can run the normal test suite and it will run all the integration +tests. + + +## Backlog + +* Look at implementing the following transport options + * Named pipes + * SSH +* Update CI to use named pipes for integration tests +* Add Ansible playbook for better integration tests +* Improved serialization between Python and .NET objects +* Live interactive console for PSRP + + + + +%prep +%autosetup -n pypsrp-0.8.1 + +%build +%py3_build + +%install +%py3_install +install -d -m755 %{buildroot}/%{_pkgdocdir} +if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi +if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi +if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi +if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi +pushd %{buildroot} +if [ -d usr/lib ]; then + find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/lib64 ]; then + find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/bin ]; then + find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/sbin ]; then + find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst +fi +touch doclist.lst +if [ -d usr/share/man ]; then + find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst +fi +popd +mv %{buildroot}/filelist.lst . +mv %{buildroot}/doclist.lst . + +%files -n python3-pypsrp -f filelist.lst +%dir %{python3_sitelib}/* + +%files help -f doclist.lst +%{_docdir}/* + +%changelog +* Tue Apr 11 2023 Python_Bot <Python_Bot@openeuler.org> - 0.8.1-1 +- Package Spec generated @@ -0,0 +1 @@ +55d346022eafdd9cc825e4ad111a98ae pypsrp-0.8.1.tar.gz |
