summaryrefslogtreecommitdiff
path: root/python-pypsexec.spec
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2023-04-10 17:33:22 +0000
committerCoprDistGit <infra@openeuler.org>2023-04-10 17:33:22 +0000
commitbb650456f267ac374d112bc2ef22199f55fedfaa (patch)
tree7b1c466a783d1fc67fe03e3b533dc95fa3bb7e86 /python-pypsexec.spec
parent593e237615fb4f7ba16f25c0b5a82a00f9f8b161 (diff)
automatic import of python-pypsexec
Diffstat (limited to 'python-pypsexec.spec')
-rw-r--r--python-pypsexec.spec1234
1 files changed, 1234 insertions, 0 deletions
diff --git a/python-pypsexec.spec b/python-pypsexec.spec
new file mode 100644
index 0000000..da09792
--- /dev/null
+++ b/python-pypsexec.spec
@@ -0,0 +1,1234 @@
+%global _empty_manifest_terminate_build 0
+Name: python-pypsexec
+Version: 0.3.0
+Release: 1
+Summary: Run commands on a remote Windows host using SMB/RPC
+License: MIT
+URL: https://github.com/jborean93/pypsexec
+Source0: https://mirrors.nju.edu.cn/pypi/web/packages/d4/cd/da60adc8d022ec3c38248f36d444568143f18de3f588c1b155a82ccd62c5/pypsexec-0.3.0.tar.gz
+BuildArch: noarch
+
+Requires: python3-smbprotocol
+
+%description
+# Python PsExec Library
+
+[![Test workflow](https://github.com/jborean93/pypsexec/actions/workflows/ci.yml/badge.svg)](https://github.com/jborean93/pypsexec/actions/workflows/ci.yml)
+[![codecov](https://codecov.io/gh/jborean93/pypsexec/branch/master/graph/badge.svg?token=Hi2Nk4RfMF)](https://codecov.io/gh/jborean93/pypsexec)
+[![PyPI version](https://badge.fury.io/py/pypsexec.svg)](https://badge.fury.io/py/pypsexec)
+[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jborean93/pypsexec/blob/master/LICENSE)
+
+This library can run commands on a remote Windows host through Python. This
+means that it can be run on any host with Python and does not require any
+binaries to be present or a specific OS. It uses SMB/RPC to executable commands
+in a similar fashion to the popular PsExec tool. More details on this tool
+can be read on
+[this blog post](https://www.bloggingforlogging.com/2018/03/12/introducing-psexec-for-python/).
+
+The executable wrapper that is sent to the service is based on the
+[PAExec](https://github.com/poweradminllc/PAExec) library. PAExec is an free,
+redistributable and open source equivalent to Microsoft's
+[PsExec](https://docs.microsoft.com/en-us/sysinternals/downloads/psexec)
+application. This program is stored as a binary in this package and is used
+to run the remote service and start the process execution.
+
+I would like to thank the developers of Power Admin for creating this library
+as it has made this library a lot less complex than what it would have been.
+
+
+## Features
+
+With pypsexec you can run commands of a remote Windows host like you would with
+PsExec. Current you can use pypsexec to do the following;
+
+* Run as a specific local or domain user or the user
+* Run as the local SYSTEM account
+* Run as an interactive process
+* Specify the session the interactive process should run on
+* Specify the run level of the user token, `highest` or `limited`
+* Set the priority of the process
+* Set a timeout for the remote process
+* Send input through the stdin pipe to the running process
+* Set the processors the process can run on
+
+
+## Further Info
+
+While this info is not necessary for you to use this library it can help people
+understand what is happening under the hood. This library runs the following
+steps when running a command;
+
+* Create an SMB connection to the host
+* Copies across the PAExec binary to the `ADMIN$` share of the remote host
+* Binds the Windows Service Manager to the opened `IPC$` tree using RPC
+* Creates and starts a Windows service as the `SYSTEM` account to run the binary copied
+* Connect to the PAExec named pipe the service creates
+* Sends the process details to the PAExec service through the pipe
+* Send a request to the PAExec service to start the process based on the settings sent
+* Connect to the newly spawned process's stdout, stderr, stdin pipe (if not interactive or async)
+* Read the stdout/stderr pipe until the process is complete
+* Get the return code of the new process
+* Stop and remove the PAExec service
+* Remove the PAExec binary from the `ADMIN$` share
+* Disconnects from the SMB connection
+
+In the case of a failed process, the PAExec service and binary may not be
+removed from the host and may need to be done manually. This is only the case
+for a critical error or the cleanup functions not being called.
+
+By default the data being sent to and from the server is encrypted to stop
+people listening in on the network from snooping your data. Unfortunately this
+uses SMB encryption which was added in the SMB 3.x dialects so hosts running
+Windows 7, Server 2008, or Server 2008 R2 will not work with encryption.
+
+This means that any data sent over the wire on these older versions of Windows
+is viewable by anyone reading those packets. Any input or output of the process
+comes through these packets so any secrets sent over the network won't be
+encrypted. PAExec tries to reduce this risk by doing a simple XOR scramble of
+the settings set in `run_executable` so it isn't plaintext but it can be
+decoded by someone who knows the protocol.
+
+
+## Requirements
+
+* Python 3.6+
+* [smbprotocol](https://github.com/jborean93/smbprotocol)
+
+To install pypsexec, simply run
+
+```bash
+pip install pypsexec
+```
+
+This will download the required packages that are required and get your
+Python environment ready to do.
+
+Out of the box, pypsexec supports authenticating to a Windows host with NTLM
+authentication but users in a domain environment can take advantage of Kerberos
+authentication as well for added security. The Kerberos libraries are an
+optional install which can be installed with;
+
+```bash
+# for Debian/Ubuntu/etc:
+sudo apt-get install gcc python-dev libkrb5-dev
+pip install smbprotocol[kerberos]
+
+# for RHEL/CentOS/etc:
+sudo yum install gcc python-devel krb5-devel krb5-workstation python-devel
+pip install smbprotocol[kerberos]
+```
+
+
+## Remote Host Requirements
+
+The goal of this package to be able to run executables on a vanilla remote
+Windows host with as little setup as possible. Unfortunately there is still
+some setup required to get working depending on the OS version and type
+that is being used. What pypsexec requires on the host is;
+
+* SMB to be up and running on the Windows port and readable from the Python host
+* The `ADMIN$` share to be enabled with read/write access of the user configured
+* The above usually means the configured user is an administrator of the Windows host
+* At least SMB 2 on the host (Server 2008 and newer)
+* The connection user has a full logon token that is not filtered by UAC
+* If connecting to localhost and `pywin32` is installed, the script must be run as a user with Administrator privileges
+
+### Firewall Setup
+
+By default, Windows blocks the SMB port 445 and it needs to be opened up before
+pypsexec can connect to the host. To do this run either one of the following
+commands;
+
+```powershell
+# PowerShell (Windows 8 and Server 2012 or Newer)
+Set-NetFirewallRule -Name FPS-SMB-In-TCP -Enabled True
+
+# CMD (All OS's)
+netsh advfirewall firewall set rule name="File and Printer Sharing (SMB-In)" dir=in new enable=Yes
+```
+
+This will open up inbound traffic to port `445` which is used by SMB.
+
+
+### User Account Control
+
+In some circumstances, UAC will filter any remote logon token and limit the
+rights that are available to it. This causes issues with pypsexec and it will
+fail with an `ACCESS_IS_DENIED` error message when trying to interact with the
+remote SCMR API. This restriction is enforced in various different scenarios
+and to get it working with pypsexec you can either;
+
+* In a domain environment, use any domain account that is a member of the local `Administrators` group
+* Use any local account that is a member of the local `Administrators` group if [LocalAccountTokenFilterPolicy](https://support.microsoft.com/en-us/help/951016/description-of-user-account-control-and-remote-restrictions-in-windows) is set to `1`
+ * This means any remote logon token will not be filtered and will have the full rights of that user
+ * By default this is not defined and needs to be created
+ * This only affects remote tokens, any local tokens/processes will still be limited as per usual
+* Use the builtin local Administrator account (SID `S-1-5-21-*-500`) that is created when Windows was installed
+ * The builtin Administrator account for English installs is typically called `Administrator` but it can be renamed
+ * This account is typically disabled by default on the desktop variants of Windows, e.g. Windows 7, 8.1, 10
+ * When [AdminApprovalMode](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/dd835564(v=ws.10)#BKMK_BuiltInAdmin) is `Enabled` this will not work. `AdminApprovalMode` is not `Enabled` by default
+* Use any local account that is a member of the local `Administrators` group if [EnableLUA](https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-lua-settings-enablelua) is `Disabled`
+ * Unlike the `LocalAccountTokenFilterPolicy` option, this affects local tokens and processes spawned locally
+ * This effectively disables UAC for any Administrator accounts and should be avoided
+
+To set `LocalAccountTokenFilterPolicy` to allow a full token on a remote logon,
+run the following PowerShell commands;
+
+```powershell
+$reg_path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
+$reg_prop_name = "LocalAccountTokenFilterPolicy"
+
+$reg_key = Get-Item -Path $reg_path
+$reg_prop = $reg_key.GetValue($reg_prop_name)
+if ($null -ne $reg_prop) {
+ Remove-ItemProperty -Path $reg_path -Name $reg_prop_name
+}
+
+New-ItemProperty -Path $reg_path -Name $reg_prop_name -Value 1 -PropertyType DWord
+```
+
+To get the name of the builtin Administrator (SID `S-1-5-21-*-500`), you can
+run the following PowerShell commands;
+
+```powershell
+Add-Type -AssemblyName System.DirectoryServices.AccountManagement
+$principal_context = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Machine)
+$user_principal = New-Object -TypeName System.DirectoryServices.AccountManagement.UserPrincipal($principal_context)
+$searcher = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalSearcher($user_principal)
+$users = $searcher.FindAll() | Where-Object { $_.Sid -like "*-500" }
+$users[0].Name
+```
+
+The last resort would be to disable UAC for any local Administrator account.
+Once again this should be avoided as there are other options available and this
+will reduce the security of your Windows host, but to do so you can run the
+following PowerShell commands;
+
+```powershell
+$reg_path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
+$reg_prop_name = "EnableLUA"
+
+$reg_key = Get-Item -Path $reg_path
+$reg_prop = $reg_key.GetValue($reg_prop_name)
+if ($null -ne $reg_prop) {
+ Remove-ItemProperty -Path $reg_path -Name $reg_prop_name
+}
+
+New-ItemProperty -Path $reg_path -Name $reg_prop_name -Value 0 -PropertyType DWord
+```
+
+After changing the `EnableLUA` setting, the Windows host needs to be rebooted
+before the policies are enacted.
+
+
+## Examples
+
+Here is an example of how to run a command with this library
+
+```python
+from pypsexec.client import Client
+
+# creates an encrypted connection to the host with the username and password
+c = Client("hostname", username="username", password="password")
+
+# set encrypt=False for Windows 7, Server 2008
+c = Client("hostname", username="username", password="password", encrypt=False)
+
+# if Kerberos is available, this will use the default credentials in the
+# credential cache
+c = Client("hostname")
+
+# you can also tell it to use a specific Kerberos principal in the cache
+# without a password
+c = Client("hostname", username="username@DOMAIN.LOCAL")
+
+c.connect()
+try:
+ c.create_service()
+
+ # After creating the service, you can run multiple exe's without
+ # reconnecting
+
+ # run a simple cmd.exe program with arguments
+ stdout, stderr, rc = c.run_executable("cmd.exe",
+ arguments="/c echo Hello World")
+
+ # run whoami.exe as the SYSTEM account
+ stdout, stderr, rc = c.run_executable("whoami.exe", use_system_account=True)
+
+ # run command asynchronously (in background), the rc is the PID of the spawned service
+ stdout, stderr, rc = c.run_executable("longrunning.exe",
+ arguments="/s other args",
+ asynchronous=True)
+
+ # run whoami.exe as a specific user
+ stdout, stderr, rc = c.run_executable("whoami",
+ arguments="/all",
+ username="local-user",
+ password="password",
+ run_elevated=True)
+finally:
+ c.remove_service()
+ c.disconnect()
+```
+
+In the case of a fatal failure, this project may leave behind some the PAExec
+payload in `C:\Windows` or the service still installed. As these are uniquely
+named they can build up over time. They can be manually removed but you can
+also use pypsexec to cleanup them all up at once. To do this run
+
+```python
+from pypsexec.client import Client
+
+c = Client("server", username="username", password="password")
+c.connect()
+c.cleanup() # this is where the magic happens
+c.disconnect()
+```
+
+The script will delete any files that match `C:\Windows\PAExec-*` and any
+services that match `PAExec-*`. For an individual run, the `remove_service()`
+function should still be used.
+
+### Client Options
+
+When creating the main pypsexec `Client` object there are some configuration
+options that can be set to control the process. These args are;
+
+* `server`: This needs to be set and is the host or IP address of the server to connect to
+* `username`: The username to connect with. Can be `None` if `python-gssapi` is installed and a ticket has been granted in the local credential cache
+* `password`: The password for `username`. Can be `None` if `python-gssapi` is installed and a ticket has been granted for the user specified
+* `port`: Override the default port of `445` when connecting to the server
+* `encrypt`: Whether to encrypt the messages or not, default is `True`. Server 2008, 2008 R2 and Windows 7 hosts do not support SMB Encryption and need this to be set to `False`
+
+
+### Run Executable Options
+
+When calling `run_executable`, there are multiple kwargs that can define
+how the remote process will work. These args are;
+
+* `executable`: (string) The path to the executable to be run
+* `arguments`: (string) Arguments for the executable
+* `processors`: (list<int>) A list of processor numbers that the process can run on
+* `asynchronous`: (bool) Doesn't wait until the process is complete before returning. The `rc` returned by the function is the `PID` of the async process, default is `False`
+* `load_profile`: (bool) Load the user's profile, default is `True`
+* `interactive_session`: (int) The session ID to display the interactive process when `interactive=True`, default is `0`
+* `interactive`: (bool) Runs the process as an interactive process. The stdout and stderr buffers will be `None` if `True`, default `False`
+* `run_elevated`: (bool) When `username` is defined, will elevated permissions, default `False`
+* `run_limited`: (bool) When `username` is defined, will run the process under limited permissions, default `False`
+* `username`: (string) Used to run the process under a different user than the one that authenticated the SMB session
+* `password`: (string) The password for `username`
+* `use_system_account`: (bool) Run the process as `NT AUTHORITY\SYSTEM`
+* `working_dir`: (string) The working directory of the process, default `C:\Windows\System32`
+* `show_ui_on_win_logon`: (bool) Displays the UI on the Winlogon secure desktop when `use_system_account=True`, default `False`
+* `priority`: (pypsexec.ProcessPriority) The priority level of the process, default `NORMAL_PRIORITY_CLASS`
+* `remote_log_path`: (string) A path on the remote host to log the PAExec service details
+* `timeout_seconds`: (int) The maximum time the process can run for, default is `0` (no timeout)
+* `stdout`: (pipe.OutputPipe) A class that implements pipe.OutputPipe that controls how the stdout output is processed and returned, will default to returning the byte string of the stdout. Is ignored when `interactive=True` and `asynchronous=True`
+* `stderr`: (pipe.OutputPipe) A class that implements pipe.OutputPipe that controls how the stderr output is processed and returned, will default to returning the byte string of the stderr. Is ignored when `interactive=True` and `asynchronous=True`
+* `stdin`: (bytes/generator) A byte string or generator that yields a byte string to send over the stdin pipe, does not work with `interactive=True` and `asynchronous=True`
+* `wow64`: (bool) Set to `True` to run the executable in 32-bit mode on 64-bit systems. This does nothing on 32-bit systems, default `False`
+
+
+## Logging
+
+This library uses the builtin Python logging library and can be used to find
+out what is happening in the pypsexec process. Log messages are logged to the
+`pypsexec` named logger as well as `pypsexec.*` where `*` is each python script
+in the `pypsexec` directory.
+
+A way to enable the logging in your scripts through code is to add the
+following to the top of the script being used;
+
+```python
+import logging
+
+logger = logging.getLogger("pypsexec")
+logger.setLevel(logging.DEBUG) # set to logging.INFO if you don't want DEBUG logs
+ch = logging.StreamHandler()
+ch.setLevel(logging.DEBUG)
+formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - '
+ '%(message)s')
+ch.setFormatter(formatter)
+logger.addHandler(ch)
+```
+
+These logs are generally useful when debugging issues as they give you a more
+step by step snapshot of what it is doing and what may be going wrong. The
+debug level will also print out a human readable string of each SMB packet that
+is sent out from the client but this level can get really verbose.
+
+
+## Testing
+
+To this module, you need to install some pre-requisites first. This can be done
+by running;
+
+```bash
+pip install -r requirements-test.txt
+
+# you can also run tox by installing tox
+pip install tox
+```
+
+From there to run the basic tests run;
+
+```bash
+py.test -v --cov pypsexec --cov-report term-missing
+
+# or with tox
+tox
+```
+
+There are extra tests that only run when certain environment variables are set.
+To run these tests set the following variables;
+
+* `PYPSEXEC_SERVER`: The hostname or IP to a Windows host
+* `PYPSEXEC_USERNAME`: The username to use authenticate with
+* `PYPSEXEC_PASSWORD`: The password for `PYPSEXEC_USERNAME`
+
+From there, you can just run `tox` or `py.test` with these environment
+variables to run the integration tests.
+
+
+## Future
+
+Some things I would be interested in looking at adding in the future would be
+
+* Add a Python script that can be called to run adhoc commands like `PsExec.exe`
+
+
+
+
+%package -n python3-pypsexec
+Summary: Run commands on a remote Windows host using SMB/RPC
+Provides: python-pypsexec
+BuildRequires: python3-devel
+BuildRequires: python3-setuptools
+BuildRequires: python3-pip
+%description -n python3-pypsexec
+# Python PsExec Library
+
+[![Test workflow](https://github.com/jborean93/pypsexec/actions/workflows/ci.yml/badge.svg)](https://github.com/jborean93/pypsexec/actions/workflows/ci.yml)
+[![codecov](https://codecov.io/gh/jborean93/pypsexec/branch/master/graph/badge.svg?token=Hi2Nk4RfMF)](https://codecov.io/gh/jborean93/pypsexec)
+[![PyPI version](https://badge.fury.io/py/pypsexec.svg)](https://badge.fury.io/py/pypsexec)
+[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jborean93/pypsexec/blob/master/LICENSE)
+
+This library can run commands on a remote Windows host through Python. This
+means that it can be run on any host with Python and does not require any
+binaries to be present or a specific OS. It uses SMB/RPC to executable commands
+in a similar fashion to the popular PsExec tool. More details on this tool
+can be read on
+[this blog post](https://www.bloggingforlogging.com/2018/03/12/introducing-psexec-for-python/).
+
+The executable wrapper that is sent to the service is based on the
+[PAExec](https://github.com/poweradminllc/PAExec) library. PAExec is an free,
+redistributable and open source equivalent to Microsoft's
+[PsExec](https://docs.microsoft.com/en-us/sysinternals/downloads/psexec)
+application. This program is stored as a binary in this package and is used
+to run the remote service and start the process execution.
+
+I would like to thank the developers of Power Admin for creating this library
+as it has made this library a lot less complex than what it would have been.
+
+
+## Features
+
+With pypsexec you can run commands of a remote Windows host like you would with
+PsExec. Current you can use pypsexec to do the following;
+
+* Run as a specific local or domain user or the user
+* Run as the local SYSTEM account
+* Run as an interactive process
+* Specify the session the interactive process should run on
+* Specify the run level of the user token, `highest` or `limited`
+* Set the priority of the process
+* Set a timeout for the remote process
+* Send input through the stdin pipe to the running process
+* Set the processors the process can run on
+
+
+## Further Info
+
+While this info is not necessary for you to use this library it can help people
+understand what is happening under the hood. This library runs the following
+steps when running a command;
+
+* Create an SMB connection to the host
+* Copies across the PAExec binary to the `ADMIN$` share of the remote host
+* Binds the Windows Service Manager to the opened `IPC$` tree using RPC
+* Creates and starts a Windows service as the `SYSTEM` account to run the binary copied
+* Connect to the PAExec named pipe the service creates
+* Sends the process details to the PAExec service through the pipe
+* Send a request to the PAExec service to start the process based on the settings sent
+* Connect to the newly spawned process's stdout, stderr, stdin pipe (if not interactive or async)
+* Read the stdout/stderr pipe until the process is complete
+* Get the return code of the new process
+* Stop and remove the PAExec service
+* Remove the PAExec binary from the `ADMIN$` share
+* Disconnects from the SMB connection
+
+In the case of a failed process, the PAExec service and binary may not be
+removed from the host and may need to be done manually. This is only the case
+for a critical error or the cleanup functions not being called.
+
+By default the data being sent to and from the server is encrypted to stop
+people listening in on the network from snooping your data. Unfortunately this
+uses SMB encryption which was added in the SMB 3.x dialects so hosts running
+Windows 7, Server 2008, or Server 2008 R2 will not work with encryption.
+
+This means that any data sent over the wire on these older versions of Windows
+is viewable by anyone reading those packets. Any input or output of the process
+comes through these packets so any secrets sent over the network won't be
+encrypted. PAExec tries to reduce this risk by doing a simple XOR scramble of
+the settings set in `run_executable` so it isn't plaintext but it can be
+decoded by someone who knows the protocol.
+
+
+## Requirements
+
+* Python 3.6+
+* [smbprotocol](https://github.com/jborean93/smbprotocol)
+
+To install pypsexec, simply run
+
+```bash
+pip install pypsexec
+```
+
+This will download the required packages that are required and get your
+Python environment ready to do.
+
+Out of the box, pypsexec supports authenticating to a Windows host with NTLM
+authentication but users in a domain environment can take advantage of Kerberos
+authentication as well for added security. The Kerberos libraries are an
+optional install which can be installed with;
+
+```bash
+# for Debian/Ubuntu/etc:
+sudo apt-get install gcc python-dev libkrb5-dev
+pip install smbprotocol[kerberos]
+
+# for RHEL/CentOS/etc:
+sudo yum install gcc python-devel krb5-devel krb5-workstation python-devel
+pip install smbprotocol[kerberos]
+```
+
+
+## Remote Host Requirements
+
+The goal of this package to be able to run executables on a vanilla remote
+Windows host with as little setup as possible. Unfortunately there is still
+some setup required to get working depending on the OS version and type
+that is being used. What pypsexec requires on the host is;
+
+* SMB to be up and running on the Windows port and readable from the Python host
+* The `ADMIN$` share to be enabled with read/write access of the user configured
+* The above usually means the configured user is an administrator of the Windows host
+* At least SMB 2 on the host (Server 2008 and newer)
+* The connection user has a full logon token that is not filtered by UAC
+* If connecting to localhost and `pywin32` is installed, the script must be run as a user with Administrator privileges
+
+### Firewall Setup
+
+By default, Windows blocks the SMB port 445 and it needs to be opened up before
+pypsexec can connect to the host. To do this run either one of the following
+commands;
+
+```powershell
+# PowerShell (Windows 8 and Server 2012 or Newer)
+Set-NetFirewallRule -Name FPS-SMB-In-TCP -Enabled True
+
+# CMD (All OS's)
+netsh advfirewall firewall set rule name="File and Printer Sharing (SMB-In)" dir=in new enable=Yes
+```
+
+This will open up inbound traffic to port `445` which is used by SMB.
+
+
+### User Account Control
+
+In some circumstances, UAC will filter any remote logon token and limit the
+rights that are available to it. This causes issues with pypsexec and it will
+fail with an `ACCESS_IS_DENIED` error message when trying to interact with the
+remote SCMR API. This restriction is enforced in various different scenarios
+and to get it working with pypsexec you can either;
+
+* In a domain environment, use any domain account that is a member of the local `Administrators` group
+* Use any local account that is a member of the local `Administrators` group if [LocalAccountTokenFilterPolicy](https://support.microsoft.com/en-us/help/951016/description-of-user-account-control-and-remote-restrictions-in-windows) is set to `1`
+ * This means any remote logon token will not be filtered and will have the full rights of that user
+ * By default this is not defined and needs to be created
+ * This only affects remote tokens, any local tokens/processes will still be limited as per usual
+* Use the builtin local Administrator account (SID `S-1-5-21-*-500`) that is created when Windows was installed
+ * The builtin Administrator account for English installs is typically called `Administrator` but it can be renamed
+ * This account is typically disabled by default on the desktop variants of Windows, e.g. Windows 7, 8.1, 10
+ * When [AdminApprovalMode](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/dd835564(v=ws.10)#BKMK_BuiltInAdmin) is `Enabled` this will not work. `AdminApprovalMode` is not `Enabled` by default
+* Use any local account that is a member of the local `Administrators` group if [EnableLUA](https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-lua-settings-enablelua) is `Disabled`
+ * Unlike the `LocalAccountTokenFilterPolicy` option, this affects local tokens and processes spawned locally
+ * This effectively disables UAC for any Administrator accounts and should be avoided
+
+To set `LocalAccountTokenFilterPolicy` to allow a full token on a remote logon,
+run the following PowerShell commands;
+
+```powershell
+$reg_path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
+$reg_prop_name = "LocalAccountTokenFilterPolicy"
+
+$reg_key = Get-Item -Path $reg_path
+$reg_prop = $reg_key.GetValue($reg_prop_name)
+if ($null -ne $reg_prop) {
+ Remove-ItemProperty -Path $reg_path -Name $reg_prop_name
+}
+
+New-ItemProperty -Path $reg_path -Name $reg_prop_name -Value 1 -PropertyType DWord
+```
+
+To get the name of the builtin Administrator (SID `S-1-5-21-*-500`), you can
+run the following PowerShell commands;
+
+```powershell
+Add-Type -AssemblyName System.DirectoryServices.AccountManagement
+$principal_context = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Machine)
+$user_principal = New-Object -TypeName System.DirectoryServices.AccountManagement.UserPrincipal($principal_context)
+$searcher = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalSearcher($user_principal)
+$users = $searcher.FindAll() | Where-Object { $_.Sid -like "*-500" }
+$users[0].Name
+```
+
+The last resort would be to disable UAC for any local Administrator account.
+Once again this should be avoided as there are other options available and this
+will reduce the security of your Windows host, but to do so you can run the
+following PowerShell commands;
+
+```powershell
+$reg_path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
+$reg_prop_name = "EnableLUA"
+
+$reg_key = Get-Item -Path $reg_path
+$reg_prop = $reg_key.GetValue($reg_prop_name)
+if ($null -ne $reg_prop) {
+ Remove-ItemProperty -Path $reg_path -Name $reg_prop_name
+}
+
+New-ItemProperty -Path $reg_path -Name $reg_prop_name -Value 0 -PropertyType DWord
+```
+
+After changing the `EnableLUA` setting, the Windows host needs to be rebooted
+before the policies are enacted.
+
+
+## Examples
+
+Here is an example of how to run a command with this library
+
+```python
+from pypsexec.client import Client
+
+# creates an encrypted connection to the host with the username and password
+c = Client("hostname", username="username", password="password")
+
+# set encrypt=False for Windows 7, Server 2008
+c = Client("hostname", username="username", password="password", encrypt=False)
+
+# if Kerberos is available, this will use the default credentials in the
+# credential cache
+c = Client("hostname")
+
+# you can also tell it to use a specific Kerberos principal in the cache
+# without a password
+c = Client("hostname", username="username@DOMAIN.LOCAL")
+
+c.connect()
+try:
+ c.create_service()
+
+ # After creating the service, you can run multiple exe's without
+ # reconnecting
+
+ # run a simple cmd.exe program with arguments
+ stdout, stderr, rc = c.run_executable("cmd.exe",
+ arguments="/c echo Hello World")
+
+ # run whoami.exe as the SYSTEM account
+ stdout, stderr, rc = c.run_executable("whoami.exe", use_system_account=True)
+
+ # run command asynchronously (in background), the rc is the PID of the spawned service
+ stdout, stderr, rc = c.run_executable("longrunning.exe",
+ arguments="/s other args",
+ asynchronous=True)
+
+ # run whoami.exe as a specific user
+ stdout, stderr, rc = c.run_executable("whoami",
+ arguments="/all",
+ username="local-user",
+ password="password",
+ run_elevated=True)
+finally:
+ c.remove_service()
+ c.disconnect()
+```
+
+In the case of a fatal failure, this project may leave behind some the PAExec
+payload in `C:\Windows` or the service still installed. As these are uniquely
+named they can build up over time. They can be manually removed but you can
+also use pypsexec to cleanup them all up at once. To do this run
+
+```python
+from pypsexec.client import Client
+
+c = Client("server", username="username", password="password")
+c.connect()
+c.cleanup() # this is where the magic happens
+c.disconnect()
+```
+
+The script will delete any files that match `C:\Windows\PAExec-*` and any
+services that match `PAExec-*`. For an individual run, the `remove_service()`
+function should still be used.
+
+### Client Options
+
+When creating the main pypsexec `Client` object there are some configuration
+options that can be set to control the process. These args are;
+
+* `server`: This needs to be set and is the host or IP address of the server to connect to
+* `username`: The username to connect with. Can be `None` if `python-gssapi` is installed and a ticket has been granted in the local credential cache
+* `password`: The password for `username`. Can be `None` if `python-gssapi` is installed and a ticket has been granted for the user specified
+* `port`: Override the default port of `445` when connecting to the server
+* `encrypt`: Whether to encrypt the messages or not, default is `True`. Server 2008, 2008 R2 and Windows 7 hosts do not support SMB Encryption and need this to be set to `False`
+
+
+### Run Executable Options
+
+When calling `run_executable`, there are multiple kwargs that can define
+how the remote process will work. These args are;
+
+* `executable`: (string) The path to the executable to be run
+* `arguments`: (string) Arguments for the executable
+* `processors`: (list<int>) A list of processor numbers that the process can run on
+* `asynchronous`: (bool) Doesn't wait until the process is complete before returning. The `rc` returned by the function is the `PID` of the async process, default is `False`
+* `load_profile`: (bool) Load the user's profile, default is `True`
+* `interactive_session`: (int) The session ID to display the interactive process when `interactive=True`, default is `0`
+* `interactive`: (bool) Runs the process as an interactive process. The stdout and stderr buffers will be `None` if `True`, default `False`
+* `run_elevated`: (bool) When `username` is defined, will elevated permissions, default `False`
+* `run_limited`: (bool) When `username` is defined, will run the process under limited permissions, default `False`
+* `username`: (string) Used to run the process under a different user than the one that authenticated the SMB session
+* `password`: (string) The password for `username`
+* `use_system_account`: (bool) Run the process as `NT AUTHORITY\SYSTEM`
+* `working_dir`: (string) The working directory of the process, default `C:\Windows\System32`
+* `show_ui_on_win_logon`: (bool) Displays the UI on the Winlogon secure desktop when `use_system_account=True`, default `False`
+* `priority`: (pypsexec.ProcessPriority) The priority level of the process, default `NORMAL_PRIORITY_CLASS`
+* `remote_log_path`: (string) A path on the remote host to log the PAExec service details
+* `timeout_seconds`: (int) The maximum time the process can run for, default is `0` (no timeout)
+* `stdout`: (pipe.OutputPipe) A class that implements pipe.OutputPipe that controls how the stdout output is processed and returned, will default to returning the byte string of the stdout. Is ignored when `interactive=True` and `asynchronous=True`
+* `stderr`: (pipe.OutputPipe) A class that implements pipe.OutputPipe that controls how the stderr output is processed and returned, will default to returning the byte string of the stderr. Is ignored when `interactive=True` and `asynchronous=True`
+* `stdin`: (bytes/generator) A byte string or generator that yields a byte string to send over the stdin pipe, does not work with `interactive=True` and `asynchronous=True`
+* `wow64`: (bool) Set to `True` to run the executable in 32-bit mode on 64-bit systems. This does nothing on 32-bit systems, default `False`
+
+
+## Logging
+
+This library uses the builtin Python logging library and can be used to find
+out what is happening in the pypsexec process. Log messages are logged to the
+`pypsexec` named logger as well as `pypsexec.*` where `*` is each python script
+in the `pypsexec` directory.
+
+A way to enable the logging in your scripts through code is to add the
+following to the top of the script being used;
+
+```python
+import logging
+
+logger = logging.getLogger("pypsexec")
+logger.setLevel(logging.DEBUG) # set to logging.INFO if you don't want DEBUG logs
+ch = logging.StreamHandler()
+ch.setLevel(logging.DEBUG)
+formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - '
+ '%(message)s')
+ch.setFormatter(formatter)
+logger.addHandler(ch)
+```
+
+These logs are generally useful when debugging issues as they give you a more
+step by step snapshot of what it is doing and what may be going wrong. The
+debug level will also print out a human readable string of each SMB packet that
+is sent out from the client but this level can get really verbose.
+
+
+## Testing
+
+To this module, you need to install some pre-requisites first. This can be done
+by running;
+
+```bash
+pip install -r requirements-test.txt
+
+# you can also run tox by installing tox
+pip install tox
+```
+
+From there to run the basic tests run;
+
+```bash
+py.test -v --cov pypsexec --cov-report term-missing
+
+# or with tox
+tox
+```
+
+There are extra tests that only run when certain environment variables are set.
+To run these tests set the following variables;
+
+* `PYPSEXEC_SERVER`: The hostname or IP to a Windows host
+* `PYPSEXEC_USERNAME`: The username to use authenticate with
+* `PYPSEXEC_PASSWORD`: The password for `PYPSEXEC_USERNAME`
+
+From there, you can just run `tox` or `py.test` with these environment
+variables to run the integration tests.
+
+
+## Future
+
+Some things I would be interested in looking at adding in the future would be
+
+* Add a Python script that can be called to run adhoc commands like `PsExec.exe`
+
+
+
+
+%package help
+Summary: Development documents and examples for pypsexec
+Provides: python3-pypsexec-doc
+%description help
+# Python PsExec Library
+
+[![Test workflow](https://github.com/jborean93/pypsexec/actions/workflows/ci.yml/badge.svg)](https://github.com/jborean93/pypsexec/actions/workflows/ci.yml)
+[![codecov](https://codecov.io/gh/jborean93/pypsexec/branch/master/graph/badge.svg?token=Hi2Nk4RfMF)](https://codecov.io/gh/jborean93/pypsexec)
+[![PyPI version](https://badge.fury.io/py/pypsexec.svg)](https://badge.fury.io/py/pypsexec)
+[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jborean93/pypsexec/blob/master/LICENSE)
+
+This library can run commands on a remote Windows host through Python. This
+means that it can be run on any host with Python and does not require any
+binaries to be present or a specific OS. It uses SMB/RPC to executable commands
+in a similar fashion to the popular PsExec tool. More details on this tool
+can be read on
+[this blog post](https://www.bloggingforlogging.com/2018/03/12/introducing-psexec-for-python/).
+
+The executable wrapper that is sent to the service is based on the
+[PAExec](https://github.com/poweradminllc/PAExec) library. PAExec is an free,
+redistributable and open source equivalent to Microsoft's
+[PsExec](https://docs.microsoft.com/en-us/sysinternals/downloads/psexec)
+application. This program is stored as a binary in this package and is used
+to run the remote service and start the process execution.
+
+I would like to thank the developers of Power Admin for creating this library
+as it has made this library a lot less complex than what it would have been.
+
+
+## Features
+
+With pypsexec you can run commands of a remote Windows host like you would with
+PsExec. Current you can use pypsexec to do the following;
+
+* Run as a specific local or domain user or the user
+* Run as the local SYSTEM account
+* Run as an interactive process
+* Specify the session the interactive process should run on
+* Specify the run level of the user token, `highest` or `limited`
+* Set the priority of the process
+* Set a timeout for the remote process
+* Send input through the stdin pipe to the running process
+* Set the processors the process can run on
+
+
+## Further Info
+
+While this info is not necessary for you to use this library it can help people
+understand what is happening under the hood. This library runs the following
+steps when running a command;
+
+* Create an SMB connection to the host
+* Copies across the PAExec binary to the `ADMIN$` share of the remote host
+* Binds the Windows Service Manager to the opened `IPC$` tree using RPC
+* Creates and starts a Windows service as the `SYSTEM` account to run the binary copied
+* Connect to the PAExec named pipe the service creates
+* Sends the process details to the PAExec service through the pipe
+* Send a request to the PAExec service to start the process based on the settings sent
+* Connect to the newly spawned process's stdout, stderr, stdin pipe (if not interactive or async)
+* Read the stdout/stderr pipe until the process is complete
+* Get the return code of the new process
+* Stop and remove the PAExec service
+* Remove the PAExec binary from the `ADMIN$` share
+* Disconnects from the SMB connection
+
+In the case of a failed process, the PAExec service and binary may not be
+removed from the host and may need to be done manually. This is only the case
+for a critical error or the cleanup functions not being called.
+
+By default the data being sent to and from the server is encrypted to stop
+people listening in on the network from snooping your data. Unfortunately this
+uses SMB encryption which was added in the SMB 3.x dialects so hosts running
+Windows 7, Server 2008, or Server 2008 R2 will not work with encryption.
+
+This means that any data sent over the wire on these older versions of Windows
+is viewable by anyone reading those packets. Any input or output of the process
+comes through these packets so any secrets sent over the network won't be
+encrypted. PAExec tries to reduce this risk by doing a simple XOR scramble of
+the settings set in `run_executable` so it isn't plaintext but it can be
+decoded by someone who knows the protocol.
+
+
+## Requirements
+
+* Python 3.6+
+* [smbprotocol](https://github.com/jborean93/smbprotocol)
+
+To install pypsexec, simply run
+
+```bash
+pip install pypsexec
+```
+
+This will download the required packages that are required and get your
+Python environment ready to do.
+
+Out of the box, pypsexec supports authenticating to a Windows host with NTLM
+authentication but users in a domain environment can take advantage of Kerberos
+authentication as well for added security. The Kerberos libraries are an
+optional install which can be installed with;
+
+```bash
+# for Debian/Ubuntu/etc:
+sudo apt-get install gcc python-dev libkrb5-dev
+pip install smbprotocol[kerberos]
+
+# for RHEL/CentOS/etc:
+sudo yum install gcc python-devel krb5-devel krb5-workstation python-devel
+pip install smbprotocol[kerberos]
+```
+
+
+## Remote Host Requirements
+
+The goal of this package to be able to run executables on a vanilla remote
+Windows host with as little setup as possible. Unfortunately there is still
+some setup required to get working depending on the OS version and type
+that is being used. What pypsexec requires on the host is;
+
+* SMB to be up and running on the Windows port and readable from the Python host
+* The `ADMIN$` share to be enabled with read/write access of the user configured
+* The above usually means the configured user is an administrator of the Windows host
+* At least SMB 2 on the host (Server 2008 and newer)
+* The connection user has a full logon token that is not filtered by UAC
+* If connecting to localhost and `pywin32` is installed, the script must be run as a user with Administrator privileges
+
+### Firewall Setup
+
+By default, Windows blocks the SMB port 445 and it needs to be opened up before
+pypsexec can connect to the host. To do this run either one of the following
+commands;
+
+```powershell
+# PowerShell (Windows 8 and Server 2012 or Newer)
+Set-NetFirewallRule -Name FPS-SMB-In-TCP -Enabled True
+
+# CMD (All OS's)
+netsh advfirewall firewall set rule name="File and Printer Sharing (SMB-In)" dir=in new enable=Yes
+```
+
+This will open up inbound traffic to port `445` which is used by SMB.
+
+
+### User Account Control
+
+In some circumstances, UAC will filter any remote logon token and limit the
+rights that are available to it. This causes issues with pypsexec and it will
+fail with an `ACCESS_IS_DENIED` error message when trying to interact with the
+remote SCMR API. This restriction is enforced in various different scenarios
+and to get it working with pypsexec you can either;
+
+* In a domain environment, use any domain account that is a member of the local `Administrators` group
+* Use any local account that is a member of the local `Administrators` group if [LocalAccountTokenFilterPolicy](https://support.microsoft.com/en-us/help/951016/description-of-user-account-control-and-remote-restrictions-in-windows) is set to `1`
+ * This means any remote logon token will not be filtered and will have the full rights of that user
+ * By default this is not defined and needs to be created
+ * This only affects remote tokens, any local tokens/processes will still be limited as per usual
+* Use the builtin local Administrator account (SID `S-1-5-21-*-500`) that is created when Windows was installed
+ * The builtin Administrator account for English installs is typically called `Administrator` but it can be renamed
+ * This account is typically disabled by default on the desktop variants of Windows, e.g. Windows 7, 8.1, 10
+ * When [AdminApprovalMode](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/dd835564(v=ws.10)#BKMK_BuiltInAdmin) is `Enabled` this will not work. `AdminApprovalMode` is not `Enabled` by default
+* Use any local account that is a member of the local `Administrators` group if [EnableLUA](https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-lua-settings-enablelua) is `Disabled`
+ * Unlike the `LocalAccountTokenFilterPolicy` option, this affects local tokens and processes spawned locally
+ * This effectively disables UAC for any Administrator accounts and should be avoided
+
+To set `LocalAccountTokenFilterPolicy` to allow a full token on a remote logon,
+run the following PowerShell commands;
+
+```powershell
+$reg_path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
+$reg_prop_name = "LocalAccountTokenFilterPolicy"
+
+$reg_key = Get-Item -Path $reg_path
+$reg_prop = $reg_key.GetValue($reg_prop_name)
+if ($null -ne $reg_prop) {
+ Remove-ItemProperty -Path $reg_path -Name $reg_prop_name
+}
+
+New-ItemProperty -Path $reg_path -Name $reg_prop_name -Value 1 -PropertyType DWord
+```
+
+To get the name of the builtin Administrator (SID `S-1-5-21-*-500`), you can
+run the following PowerShell commands;
+
+```powershell
+Add-Type -AssemblyName System.DirectoryServices.AccountManagement
+$principal_context = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Machine)
+$user_principal = New-Object -TypeName System.DirectoryServices.AccountManagement.UserPrincipal($principal_context)
+$searcher = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalSearcher($user_principal)
+$users = $searcher.FindAll() | Where-Object { $_.Sid -like "*-500" }
+$users[0].Name
+```
+
+The last resort would be to disable UAC for any local Administrator account.
+Once again this should be avoided as there are other options available and this
+will reduce the security of your Windows host, but to do so you can run the
+following PowerShell commands;
+
+```powershell
+$reg_path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
+$reg_prop_name = "EnableLUA"
+
+$reg_key = Get-Item -Path $reg_path
+$reg_prop = $reg_key.GetValue($reg_prop_name)
+if ($null -ne $reg_prop) {
+ Remove-ItemProperty -Path $reg_path -Name $reg_prop_name
+}
+
+New-ItemProperty -Path $reg_path -Name $reg_prop_name -Value 0 -PropertyType DWord
+```
+
+After changing the `EnableLUA` setting, the Windows host needs to be rebooted
+before the policies are enacted.
+
+
+## Examples
+
+Here is an example of how to run a command with this library
+
+```python
+from pypsexec.client import Client
+
+# creates an encrypted connection to the host with the username and password
+c = Client("hostname", username="username", password="password")
+
+# set encrypt=False for Windows 7, Server 2008
+c = Client("hostname", username="username", password="password", encrypt=False)
+
+# if Kerberos is available, this will use the default credentials in the
+# credential cache
+c = Client("hostname")
+
+# you can also tell it to use a specific Kerberos principal in the cache
+# without a password
+c = Client("hostname", username="username@DOMAIN.LOCAL")
+
+c.connect()
+try:
+ c.create_service()
+
+ # After creating the service, you can run multiple exe's without
+ # reconnecting
+
+ # run a simple cmd.exe program with arguments
+ stdout, stderr, rc = c.run_executable("cmd.exe",
+ arguments="/c echo Hello World")
+
+ # run whoami.exe as the SYSTEM account
+ stdout, stderr, rc = c.run_executable("whoami.exe", use_system_account=True)
+
+ # run command asynchronously (in background), the rc is the PID of the spawned service
+ stdout, stderr, rc = c.run_executable("longrunning.exe",
+ arguments="/s other args",
+ asynchronous=True)
+
+ # run whoami.exe as a specific user
+ stdout, stderr, rc = c.run_executable("whoami",
+ arguments="/all",
+ username="local-user",
+ password="password",
+ run_elevated=True)
+finally:
+ c.remove_service()
+ c.disconnect()
+```
+
+In the case of a fatal failure, this project may leave behind some the PAExec
+payload in `C:\Windows` or the service still installed. As these are uniquely
+named they can build up over time. They can be manually removed but you can
+also use pypsexec to cleanup them all up at once. To do this run
+
+```python
+from pypsexec.client import Client
+
+c = Client("server", username="username", password="password")
+c.connect()
+c.cleanup() # this is where the magic happens
+c.disconnect()
+```
+
+The script will delete any files that match `C:\Windows\PAExec-*` and any
+services that match `PAExec-*`. For an individual run, the `remove_service()`
+function should still be used.
+
+### Client Options
+
+When creating the main pypsexec `Client` object there are some configuration
+options that can be set to control the process. These args are;
+
+* `server`: This needs to be set and is the host or IP address of the server to connect to
+* `username`: The username to connect with. Can be `None` if `python-gssapi` is installed and a ticket has been granted in the local credential cache
+* `password`: The password for `username`. Can be `None` if `python-gssapi` is installed and a ticket has been granted for the user specified
+* `port`: Override the default port of `445` when connecting to the server
+* `encrypt`: Whether to encrypt the messages or not, default is `True`. Server 2008, 2008 R2 and Windows 7 hosts do not support SMB Encryption and need this to be set to `False`
+
+
+### Run Executable Options
+
+When calling `run_executable`, there are multiple kwargs that can define
+how the remote process will work. These args are;
+
+* `executable`: (string) The path to the executable to be run
+* `arguments`: (string) Arguments for the executable
+* `processors`: (list<int>) A list of processor numbers that the process can run on
+* `asynchronous`: (bool) Doesn't wait until the process is complete before returning. The `rc` returned by the function is the `PID` of the async process, default is `False`
+* `load_profile`: (bool) Load the user's profile, default is `True`
+* `interactive_session`: (int) The session ID to display the interactive process when `interactive=True`, default is `0`
+* `interactive`: (bool) Runs the process as an interactive process. The stdout and stderr buffers will be `None` if `True`, default `False`
+* `run_elevated`: (bool) When `username` is defined, will elevated permissions, default `False`
+* `run_limited`: (bool) When `username` is defined, will run the process under limited permissions, default `False`
+* `username`: (string) Used to run the process under a different user than the one that authenticated the SMB session
+* `password`: (string) The password for `username`
+* `use_system_account`: (bool) Run the process as `NT AUTHORITY\SYSTEM`
+* `working_dir`: (string) The working directory of the process, default `C:\Windows\System32`
+* `show_ui_on_win_logon`: (bool) Displays the UI on the Winlogon secure desktop when `use_system_account=True`, default `False`
+* `priority`: (pypsexec.ProcessPriority) The priority level of the process, default `NORMAL_PRIORITY_CLASS`
+* `remote_log_path`: (string) A path on the remote host to log the PAExec service details
+* `timeout_seconds`: (int) The maximum time the process can run for, default is `0` (no timeout)
+* `stdout`: (pipe.OutputPipe) A class that implements pipe.OutputPipe that controls how the stdout output is processed and returned, will default to returning the byte string of the stdout. Is ignored when `interactive=True` and `asynchronous=True`
+* `stderr`: (pipe.OutputPipe) A class that implements pipe.OutputPipe that controls how the stderr output is processed and returned, will default to returning the byte string of the stderr. Is ignored when `interactive=True` and `asynchronous=True`
+* `stdin`: (bytes/generator) A byte string or generator that yields a byte string to send over the stdin pipe, does not work with `interactive=True` and `asynchronous=True`
+* `wow64`: (bool) Set to `True` to run the executable in 32-bit mode on 64-bit systems. This does nothing on 32-bit systems, default `False`
+
+
+## Logging
+
+This library uses the builtin Python logging library and can be used to find
+out what is happening in the pypsexec process. Log messages are logged to the
+`pypsexec` named logger as well as `pypsexec.*` where `*` is each python script
+in the `pypsexec` directory.
+
+A way to enable the logging in your scripts through code is to add the
+following to the top of the script being used;
+
+```python
+import logging
+
+logger = logging.getLogger("pypsexec")
+logger.setLevel(logging.DEBUG) # set to logging.INFO if you don't want DEBUG logs
+ch = logging.StreamHandler()
+ch.setLevel(logging.DEBUG)
+formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - '
+ '%(message)s')
+ch.setFormatter(formatter)
+logger.addHandler(ch)
+```
+
+These logs are generally useful when debugging issues as they give you a more
+step by step snapshot of what it is doing and what may be going wrong. The
+debug level will also print out a human readable string of each SMB packet that
+is sent out from the client but this level can get really verbose.
+
+
+## Testing
+
+To this module, you need to install some pre-requisites first. This can be done
+by running;
+
+```bash
+pip install -r requirements-test.txt
+
+# you can also run tox by installing tox
+pip install tox
+```
+
+From there to run the basic tests run;
+
+```bash
+py.test -v --cov pypsexec --cov-report term-missing
+
+# or with tox
+tox
+```
+
+There are extra tests that only run when certain environment variables are set.
+To run these tests set the following variables;
+
+* `PYPSEXEC_SERVER`: The hostname or IP to a Windows host
+* `PYPSEXEC_USERNAME`: The username to use authenticate with
+* `PYPSEXEC_PASSWORD`: The password for `PYPSEXEC_USERNAME`
+
+From there, you can just run `tox` or `py.test` with these environment
+variables to run the integration tests.
+
+
+## Future
+
+Some things I would be interested in looking at adding in the future would be
+
+* Add a Python script that can be called to run adhoc commands like `PsExec.exe`
+
+
+
+
+%prep
+%autosetup -n pypsexec-0.3.0
+
+%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-pypsexec -f filelist.lst
+%dir %{python3_sitelib}/*
+
+%files help -f doclist.lst
+%{_docdir}/*
+
+%changelog
+* Mon Apr 10 2023 Python_Bot <Python_Bot@openeuler.org> - 0.3.0-1
+- Package Spec generated