lib.winrm
This library collects some Microsoft WinRM related functions.
1#!/usr/bin/env python3 2# -*- coding: utf-8; py-indent-offset: 4 -*- 3# 4# Author: Linuxfabrik GmbH, Zurich, Switzerland 5# Contact: info (at) linuxfabrik (dot) ch 6# https://www.linuxfabrik.ch/ 7# License: The Unlicense, see LICENSE file. 8 9# https://github.com/Linuxfabrik/monitoring-plugins/blob/main/CONTRIBUTING.rst 10 11"""This library collects some Microsoft WinRM related functions. 12""" 13 14__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland' 15__version__ = '2025103002' 16 17try: 18 import winrm 19 HAVE_WINRM = True 20except ImportError: 21 HAVE_WINRM = False 22 23try: 24 from pypsrp.client import Client 25 HAVE_JEA = True 26except ImportError: 27 HAVE_JEA = False 28 29from . import txt 30 31 32def run_cmd(args, cmd, params=None): 33 """ 34 Run a native command on a remote Windows host via WinRM/PSRP and return a 35 normalized result dictionary. 36 37 Prefers **pypsrp (PSRP)** if available (for JEA/PowerShell Remoting 38 compatibility); otherwise falls back to **pywinrm**. Authentication, 39 transport and SSL/port selection are derived from the provided `args`. 40 41 ### Parameters 42 - **args**: An object (e.g., `argparse.Namespace`) that provides at least: 43 - `WINRM_HOSTNAME` (`str`): Target host or IP. 44 - `WINRM_USERNAME` (`str`): Username. 45 - `WINRM_PASSWORD` (`str`): Password. 46 - `WINRM_TRANSPORT` (`str`, optional): Transport (e.g., `'negotiate'`, `'kerberos'`, 47 `'ntlm'`, `'credssp'`, `'basic'`, `'ssl'`). Defaults to `'negotiate'` if unset. 48 - `WINRM_DOMAIN` (`str`, optional): If set, username is sent as `user@domain`. 49 (Additional fields may be honored by the underlying libraries if present.) 50 - **cmd** (`str`): The executable/command to run remotely (native command, not a PowerShell 51 script block). 52 - **params** (`list[str]`, optional): Positional arguments passed to the command. Defaults 53 to `[]`. 54 55 ### Returns 56 - **dict**: A normalized result with: 57 - `retc` (`int`): Process return code (`0` on success). 58 - `stdout` (`str`): Captured standard output (text). 59 - `stderr` (`str`): Captured standard error (text). 60 61 ### Behavior 62 - If **pypsrp** is available, maps `WINRM_TRANSPORT` to an appropriate PSRP auth 63 and chooses SSL/port (5986 for SSL, 5985 otherwise), then executes the command 64 via `Client.execute_cmd()`. 65 - If pypsrp is unavailable but **pywinrm** is installed, executes via 66 `Session.run_cmd()`. 67 - On any exception, returns `{'retc': 1, 'stdout': '', 'stderr': <exception text>}`. 68 - If neither backend is present, returns an error indicating that no compatible 69 remoting library is available. 70 71 ### Example 72 >>> # args provides WINRM_* settings (hostname, creds, transport, etc.) 73 >>> run_cmd(args, "ipconfig", ["/all"]) 74 {'retc': 0, 'stdout': 'Windows IP Configuration\\r\\n...','stderr': ''} 75 """ 76 auth = (args.WINRM_USERNAME, args.WINRM_PASSWORD) 77 if getattr(args, 'WINRM_DOMAIN', None): 78 auth = (f'{args.WINRM_USERNAME}@{args.WINRM_DOMAIN}', args.WINRM_PASSWORD) 79 80 if params is None: 81 params = [] 82 83 if HAVE_JEA: 84 try: 85 # translate pywinrm transport -> pypsrp auth/ssl/port 86 _transport = (args.WINRM_TRANSPORT or '').lower() 87 _auth_map = { 88 'kerberos': 'kerberos', 89 'negotiate': 'negotiate', 90 'ntlm': 'negotiate', # NTLM is negotiated under "negotiate" 91 'credssp': 'credssp', 92 'basic': 'basic', 93 'plaintext': 'basic', # basic over HTTP 94 'ssl': 'basic', # basic over HTTPS 95 } 96 _psrp_auth = _auth_map.get(_transport, 'negotiate') 97 _use_ssl = (_transport == 'ssl') 98 _port = 5986 if _use_ssl else 5985 99 100 # create PSRP client 101 session = Client( 102 server=args.WINRM_HOSTNAME, 103 username=auth[0], 104 password=auth[1], 105 auth=_psrp_auth, 106 ssl=_use_ssl, 107 port=_port, 108 cert_validation=True, 109 ) 110 111 # run native command (not PowerShell script) 112 stdout, stderr, rc = session.execute_cmd(cmd, params) 113 114 return { 115 'retc': rc, 116 'stdout': txt.to_text(stdout), 117 'stderr': txt.to_text(stderr), 118 } 119 except Exception as e: 120 return { 121 'retc': 1, 122 'stdout': '', 123 'stderr': txt.exception2text(e), 124 } 125 126 if HAVE_WINRM: 127 try: 128 session = winrm.Session( 129 args.WINRM_HOSTNAME, 130 auth=auth, 131 transport=args.WINRM_TRANSPORT, 132 ) 133 134 result = session.run_cmd(cmd, params) 135 return { 136 'retc': result.status_code, 137 'stdout': txt.to_text(result.std_out), 138 'stderr': txt.to_text(result.std_err), 139 } 140 except Exception as e: 141 return { 142 'retc': 1, 143 'stdout': '', 144 'stderr': txt.exception2text(e), 145 } 146 147 # Neither pypsrp nor pywinrm is available 148 return { 149 'retc': 1, 150 'stdout': '', 151 'stderr': 'No compatible remoting library available (pypsrp or pywinrm).', 152 } 153 154 155def run_ps(args, cmd): 156 """ 157 Run a PowerShell script/string on a remote Windows host via WinRM/PSRP and 158 return a normalized result dictionary. 159 160 Prefers **pypsrp (PSRP)** if available (best for JEA/PowerShell Remoting); 161 otherwise falls back to **pywinrm**. Authentication, transport, and SSL/port 162 are derived from the provided `args`. 163 164 ### Parameters 165 - **args**: An object (e.g., `argparse.Namespace`) that provides at least: 166 - `WINRM_HOSTNAME` (`str`): Target host or IP. 167 - `WINRM_USERNAME` (`str`): Username. 168 - `WINRM_PASSWORD` (`str`): Password. 169 - `WINRM_TRANSPORT` (`str`, optional): Transport (`'negotiate'`, `'kerberos'`, 170 `'ntlm'`, `'credssp'`, `'basic'`, `'ssl'`, etc.). Defaults to `'negotiate'` 171 if unset. 172 - `WINRM_DOMAIN` (`str`, optional): If set, username is sent as `user@domain`. 173 (Additional attributes may be honored by the underlying libraries if present.) 174 - **cmd** (`str`): PowerShell scriptblock/string to execute remotely. 175 176 ### Returns 177 - **dict**: A normalized result with: 178 - `retc` (`int`): Return code (`0` if no PowerShell errors were reported). 179 - `stdout` (`str`): Captured standard output/text from the script. 180 - `stderr` (`str`): Aggregated error/diagnostic output. 181 - For **PSRP**: collects entries from the PowerShell *Error* stream 182 (human-readable via `to_string()` when available). 183 - For **pywinrm**: uses `std_err`; if `retc == 0` and stderr begins with 184 `#< CLIXML`, it is suppressed as benign progress noise. 185 186 ### Behavior 187 - Maps `WINRM_TRANSPORT` to PSRP auth (`kerberos`, `negotiate`, `credssp`, `basic`) 188 and decides SSL/port (5986 for SSL, 5985 otherwise) when using **pypsrp**, 189 then executes via `Client.execute_ps()`. 190 - Falls back to **pywinrm** and executes via `Session.run_ps()` if pypsrp is not available. 191 - On any exception, returns `{'retc': 1, 'stdout': '', 'stderr': <exception text>}`. 192 - If neither backend is installed, returns an error indicating that no compatible 193 remoting library is available. 194 195 ### Example 196 >>> # args must provide WINRM_* settings (hostname, creds, transport, etc.) 197 >>> run_ps(args, "Get-Process | Select-Object -First 1 | Format-Table Name,Id -AutoSize") 198 {'retc': 0, 'stdout': 'Name Id\\r\\n---- --\\r\\n...\\r\\n', 'stderr': ''} 199 """ 200 auth = (args.WINRM_USERNAME, args.WINRM_PASSWORD) 201 if getattr(args, 'WINRM_DOMAIN', None): 202 auth = (f'{args.WINRM_USERNAME}@{args.WINRM_DOMAIN}', args.WINRM_PASSWORD) 203 204 if HAVE_JEA: 205 try: 206 # translate pywinrm transport -> pypsrp auth/ssl/port 207 _transport = (args.WINRM_TRANSPORT or '').lower() 208 _auth_map = { 209 'kerberos': 'kerberos', 210 'negotiate': 'negotiate', 211 'ntlm': 'negotiate', # NTLM is negotiated under "negotiate" 212 'credssp': 'credssp', 213 'basic': 'basic', 214 'plaintext': 'basic', # basic over HTTP 215 'ssl': 'basic', # basic over HTTPS 216 } 217 _psrp_auth = _auth_map.get(_transport, 'negotiate') 218 _use_ssl = (_transport == 'ssl') 219 _port = 5986 if _use_ssl else 5985 220 221 # create PSRP client (like in winrm.Session) 222 session = Client( 223 server=args.WINRM_HOSTNAME, 224 username=auth[0], 225 password=auth[1], 226 auth=_psrp_auth, 227 ssl=_use_ssl, 228 port=_port, 229 cert_validation=True, 230 ) 231 232 # run PowerShell 233 stdout, streams, had_errors = session.execute_ps(cmd) 234 235 # stdout is already a string; stderr from PSRP error stream(s) 236 stderr_lines = [] 237 for err in getattr(streams, 'error', []): 238 # err.to_string() gives a readable message with category/position if available 239 try: 240 stderr_lines.append(err.to_string()) 241 except Exception: 242 # fallback to message text 243 msg = getattr(err, 'message', None) or str(err) 244 stderr_lines.append(str(msg)) 245 stderr = '\n'.join(stderr_lines) 246 247 result = { 248 'retc': 0 if not had_errors else 1, 249 'stdout': txt.to_text(stdout), 250 'stderr': txt.to_text(stderr), 251 } 252 return result 253 except Exception as e: 254 return { 255 'retc': 1, 256 'stdout': '', 257 'stderr': txt.exception2text(e), 258 } 259 260 if HAVE_WINRM: 261 try: 262 session = winrm.Session( 263 args.WINRM_HOSTNAME, 264 auth=auth, 265 transport=args.WINRM_TRANSPORT, 266 ) 267 268 # run PowerShell 269 result = session.run_ps(cmd) 270 271 result = { 272 'retc': result.status_code, 273 'stdout': txt.to_text(result.std_out), 274 'stderr': txt.to_text(result.std_err), 275 } 276 # if `result.status_code == 0`, ignore stderr that starts with `#< CLIXML` 277 # (it's just progress noise) 278 if result['retc'] == 0 and result['stderr'].startswith('#< CLIXML'): 279 result['stderr'] = '' 280 return result 281 except Exception as e: 282 return { 283 'retc': 1, 284 'stdout': '', 285 'stderr': txt.exception2text(e), 286 } 287 288 # Neither pypsrp nor pywinrm is available 289 return { 290 'retc': 1, 291 'stdout': '', 292 'stderr': 'No compatible remoting library available (pypsrp or pywinrm).', 293 }
def
run_cmd(args, cmd, params=None):
33def run_cmd(args, cmd, params=None): 34 """ 35 Run a native command on a remote Windows host via WinRM/PSRP and return a 36 normalized result dictionary. 37 38 Prefers **pypsrp (PSRP)** if available (for JEA/PowerShell Remoting 39 compatibility); otherwise falls back to **pywinrm**. Authentication, 40 transport and SSL/port selection are derived from the provided `args`. 41 42 ### Parameters 43 - **args**: An object (e.g., `argparse.Namespace`) that provides at least: 44 - `WINRM_HOSTNAME` (`str`): Target host or IP. 45 - `WINRM_USERNAME` (`str`): Username. 46 - `WINRM_PASSWORD` (`str`): Password. 47 - `WINRM_TRANSPORT` (`str`, optional): Transport (e.g., `'negotiate'`, `'kerberos'`, 48 `'ntlm'`, `'credssp'`, `'basic'`, `'ssl'`). Defaults to `'negotiate'` if unset. 49 - `WINRM_DOMAIN` (`str`, optional): If set, username is sent as `user@domain`. 50 (Additional fields may be honored by the underlying libraries if present.) 51 - **cmd** (`str`): The executable/command to run remotely (native command, not a PowerShell 52 script block). 53 - **params** (`list[str]`, optional): Positional arguments passed to the command. Defaults 54 to `[]`. 55 56 ### Returns 57 - **dict**: A normalized result with: 58 - `retc` (`int`): Process return code (`0` on success). 59 - `stdout` (`str`): Captured standard output (text). 60 - `stderr` (`str`): Captured standard error (text). 61 62 ### Behavior 63 - If **pypsrp** is available, maps `WINRM_TRANSPORT` to an appropriate PSRP auth 64 and chooses SSL/port (5986 for SSL, 5985 otherwise), then executes the command 65 via `Client.execute_cmd()`. 66 - If pypsrp is unavailable but **pywinrm** is installed, executes via 67 `Session.run_cmd()`. 68 - On any exception, returns `{'retc': 1, 'stdout': '', 'stderr': <exception text>}`. 69 - If neither backend is present, returns an error indicating that no compatible 70 remoting library is available. 71 72 ### Example 73 >>> # args provides WINRM_* settings (hostname, creds, transport, etc.) 74 >>> run_cmd(args, "ipconfig", ["/all"]) 75 {'retc': 0, 'stdout': 'Windows IP Configuration\\r\\n...','stderr': ''} 76 """ 77 auth = (args.WINRM_USERNAME, args.WINRM_PASSWORD) 78 if getattr(args, 'WINRM_DOMAIN', None): 79 auth = (f'{args.WINRM_USERNAME}@{args.WINRM_DOMAIN}', args.WINRM_PASSWORD) 80 81 if params is None: 82 params = [] 83 84 if HAVE_JEA: 85 try: 86 # translate pywinrm transport -> pypsrp auth/ssl/port 87 _transport = (args.WINRM_TRANSPORT or '').lower() 88 _auth_map = { 89 'kerberos': 'kerberos', 90 'negotiate': 'negotiate', 91 'ntlm': 'negotiate', # NTLM is negotiated under "negotiate" 92 'credssp': 'credssp', 93 'basic': 'basic', 94 'plaintext': 'basic', # basic over HTTP 95 'ssl': 'basic', # basic over HTTPS 96 } 97 _psrp_auth = _auth_map.get(_transport, 'negotiate') 98 _use_ssl = (_transport == 'ssl') 99 _port = 5986 if _use_ssl else 5985 100 101 # create PSRP client 102 session = Client( 103 server=args.WINRM_HOSTNAME, 104 username=auth[0], 105 password=auth[1], 106 auth=_psrp_auth, 107 ssl=_use_ssl, 108 port=_port, 109 cert_validation=True, 110 ) 111 112 # run native command (not PowerShell script) 113 stdout, stderr, rc = session.execute_cmd(cmd, params) 114 115 return { 116 'retc': rc, 117 'stdout': txt.to_text(stdout), 118 'stderr': txt.to_text(stderr), 119 } 120 except Exception as e: 121 return { 122 'retc': 1, 123 'stdout': '', 124 'stderr': txt.exception2text(e), 125 } 126 127 if HAVE_WINRM: 128 try: 129 session = winrm.Session( 130 args.WINRM_HOSTNAME, 131 auth=auth, 132 transport=args.WINRM_TRANSPORT, 133 ) 134 135 result = session.run_cmd(cmd, params) 136 return { 137 'retc': result.status_code, 138 'stdout': txt.to_text(result.std_out), 139 'stderr': txt.to_text(result.std_err), 140 } 141 except Exception as e: 142 return { 143 'retc': 1, 144 'stdout': '', 145 'stderr': txt.exception2text(e), 146 } 147 148 # Neither pypsrp nor pywinrm is available 149 return { 150 'retc': 1, 151 'stdout': '', 152 'stderr': 'No compatible remoting library available (pypsrp or pywinrm).', 153 }
Run a native command on a remote Windows host via WinRM/PSRP and return a normalized result dictionary.
Prefers pypsrp (PSRP) if available (for JEA/PowerShell Remoting
compatibility); otherwise falls back to pywinrm. Authentication,
transport and SSL/port selection are derived from the provided args.
Parameters
- args: An object (e.g.,
argparse.Namespace) that provides at least:WINRM_HOSTNAME(str): Target host or IP.WINRM_USERNAME(str): Username.WINRM_PASSWORD(str): Password.WINRM_TRANSPORT(str, optional): Transport (e.g.,'negotiate','kerberos','ntlm','credssp','basic','ssl'). Defaults to'negotiate'if unset.WINRM_DOMAIN(str, optional): If set, username is sent asuser@domain. (Additional fields may be honored by the underlying libraries if present.)
- cmd (
str): The executable/command to run remotely (native command, not a PowerShell script block). - params (
list[str], optional): Positional arguments passed to the command. Defaults to[].
Returns
- dict: A normalized result with:
retc(int): Process return code (0on success).stdout(str): Captured standard output (text).stderr(str): Captured standard error (text).
Behavior
- If pypsrp is available, maps
WINRM_TRANSPORTto an appropriate PSRP auth and chooses SSL/port (5986 for SSL, 5985 otherwise), then executes the command viaClient.execute_cmd(). - If pypsrp is unavailable but pywinrm is installed, executes via
Session.run_cmd(). - On any exception, returns
{'retc': 1, 'stdout': '', 'stderr': <exception text>}. - If neither backend is present, returns an error indicating that no compatible remoting library is available.
Example
>>> # args provides WINRM_* settings (hostname, creds, transport, etc.)
>>> run_cmd(args, "ipconfig", ["/all"])
{'retc': 0, 'stdout': 'Windows IP Configuration\r\n...','stderr': ''}
def
run_ps(args, cmd):
156def run_ps(args, cmd): 157 """ 158 Run a PowerShell script/string on a remote Windows host via WinRM/PSRP and 159 return a normalized result dictionary. 160 161 Prefers **pypsrp (PSRP)** if available (best for JEA/PowerShell Remoting); 162 otherwise falls back to **pywinrm**. Authentication, transport, and SSL/port 163 are derived from the provided `args`. 164 165 ### Parameters 166 - **args**: An object (e.g., `argparse.Namespace`) that provides at least: 167 - `WINRM_HOSTNAME` (`str`): Target host or IP. 168 - `WINRM_USERNAME` (`str`): Username. 169 - `WINRM_PASSWORD` (`str`): Password. 170 - `WINRM_TRANSPORT` (`str`, optional): Transport (`'negotiate'`, `'kerberos'`, 171 `'ntlm'`, `'credssp'`, `'basic'`, `'ssl'`, etc.). Defaults to `'negotiate'` 172 if unset. 173 - `WINRM_DOMAIN` (`str`, optional): If set, username is sent as `user@domain`. 174 (Additional attributes may be honored by the underlying libraries if present.) 175 - **cmd** (`str`): PowerShell scriptblock/string to execute remotely. 176 177 ### Returns 178 - **dict**: A normalized result with: 179 - `retc` (`int`): Return code (`0` if no PowerShell errors were reported). 180 - `stdout` (`str`): Captured standard output/text from the script. 181 - `stderr` (`str`): Aggregated error/diagnostic output. 182 - For **PSRP**: collects entries from the PowerShell *Error* stream 183 (human-readable via `to_string()` when available). 184 - For **pywinrm**: uses `std_err`; if `retc == 0` and stderr begins with 185 `#< CLIXML`, it is suppressed as benign progress noise. 186 187 ### Behavior 188 - Maps `WINRM_TRANSPORT` to PSRP auth (`kerberos`, `negotiate`, `credssp`, `basic`) 189 and decides SSL/port (5986 for SSL, 5985 otherwise) when using **pypsrp**, 190 then executes via `Client.execute_ps()`. 191 - Falls back to **pywinrm** and executes via `Session.run_ps()` if pypsrp is not available. 192 - On any exception, returns `{'retc': 1, 'stdout': '', 'stderr': <exception text>}`. 193 - If neither backend is installed, returns an error indicating that no compatible 194 remoting library is available. 195 196 ### Example 197 >>> # args must provide WINRM_* settings (hostname, creds, transport, etc.) 198 >>> run_ps(args, "Get-Process | Select-Object -First 1 | Format-Table Name,Id -AutoSize") 199 {'retc': 0, 'stdout': 'Name Id\\r\\n---- --\\r\\n...\\r\\n', 'stderr': ''} 200 """ 201 auth = (args.WINRM_USERNAME, args.WINRM_PASSWORD) 202 if getattr(args, 'WINRM_DOMAIN', None): 203 auth = (f'{args.WINRM_USERNAME}@{args.WINRM_DOMAIN}', args.WINRM_PASSWORD) 204 205 if HAVE_JEA: 206 try: 207 # translate pywinrm transport -> pypsrp auth/ssl/port 208 _transport = (args.WINRM_TRANSPORT or '').lower() 209 _auth_map = { 210 'kerberos': 'kerberos', 211 'negotiate': 'negotiate', 212 'ntlm': 'negotiate', # NTLM is negotiated under "negotiate" 213 'credssp': 'credssp', 214 'basic': 'basic', 215 'plaintext': 'basic', # basic over HTTP 216 'ssl': 'basic', # basic over HTTPS 217 } 218 _psrp_auth = _auth_map.get(_transport, 'negotiate') 219 _use_ssl = (_transport == 'ssl') 220 _port = 5986 if _use_ssl else 5985 221 222 # create PSRP client (like in winrm.Session) 223 session = Client( 224 server=args.WINRM_HOSTNAME, 225 username=auth[0], 226 password=auth[1], 227 auth=_psrp_auth, 228 ssl=_use_ssl, 229 port=_port, 230 cert_validation=True, 231 ) 232 233 # run PowerShell 234 stdout, streams, had_errors = session.execute_ps(cmd) 235 236 # stdout is already a string; stderr from PSRP error stream(s) 237 stderr_lines = [] 238 for err in getattr(streams, 'error', []): 239 # err.to_string() gives a readable message with category/position if available 240 try: 241 stderr_lines.append(err.to_string()) 242 except Exception: 243 # fallback to message text 244 msg = getattr(err, 'message', None) or str(err) 245 stderr_lines.append(str(msg)) 246 stderr = '\n'.join(stderr_lines) 247 248 result = { 249 'retc': 0 if not had_errors else 1, 250 'stdout': txt.to_text(stdout), 251 'stderr': txt.to_text(stderr), 252 } 253 return result 254 except Exception as e: 255 return { 256 'retc': 1, 257 'stdout': '', 258 'stderr': txt.exception2text(e), 259 } 260 261 if HAVE_WINRM: 262 try: 263 session = winrm.Session( 264 args.WINRM_HOSTNAME, 265 auth=auth, 266 transport=args.WINRM_TRANSPORT, 267 ) 268 269 # run PowerShell 270 result = session.run_ps(cmd) 271 272 result = { 273 'retc': result.status_code, 274 'stdout': txt.to_text(result.std_out), 275 'stderr': txt.to_text(result.std_err), 276 } 277 # if `result.status_code == 0`, ignore stderr that starts with `#< CLIXML` 278 # (it's just progress noise) 279 if result['retc'] == 0 and result['stderr'].startswith('#< CLIXML'): 280 result['stderr'] = '' 281 return result 282 except Exception as e: 283 return { 284 'retc': 1, 285 'stdout': '', 286 'stderr': txt.exception2text(e), 287 } 288 289 # Neither pypsrp nor pywinrm is available 290 return { 291 'retc': 1, 292 'stdout': '', 293 'stderr': 'No compatible remoting library available (pypsrp or pywinrm).', 294 }
Run a PowerShell script/string on a remote Windows host via WinRM/PSRP and return a normalized result dictionary.
Prefers pypsrp (PSRP) if available (best for JEA/PowerShell Remoting);
otherwise falls back to pywinrm. Authentication, transport, and SSL/port
are derived from the provided args.
Parameters
- args: An object (e.g.,
argparse.Namespace) that provides at least:WINRM_HOSTNAME(str): Target host or IP.WINRM_USERNAME(str): Username.WINRM_PASSWORD(str): Password.WINRM_TRANSPORT(str, optional): Transport ('negotiate','kerberos','ntlm','credssp','basic','ssl', etc.). Defaults to'negotiate'if unset.WINRM_DOMAIN(str, optional): If set, username is sent asuser@domain. (Additional attributes may be honored by the underlying libraries if present.)
- cmd (
str): PowerShell scriptblock/string to execute remotely.
Returns
- dict: A normalized result with:
retc(int): Return code (0if no PowerShell errors were reported).stdout(str): Captured standard output/text from the script.stderr(str): Aggregated error/diagnostic output.- For PSRP: collects entries from the PowerShell Error stream
(human-readable via
to_string()when available). - For pywinrm: uses
std_err; ifretc == 0and stderr begins with#< CLIXML, it is suppressed as benign progress noise.
- For PSRP: collects entries from the PowerShell Error stream
(human-readable via
Behavior
- Maps
WINRM_TRANSPORTto PSRP auth (kerberos,negotiate,credssp,basic) and decides SSL/port (5986 for SSL, 5985 otherwise) when using pypsrp, then executes viaClient.execute_ps(). - Falls back to pywinrm and executes via
Session.run_ps()if pypsrp is not available. - On any exception, returns
{'retc': 1, 'stdout': '', 'stderr': <exception text>}. - If neither backend is installed, returns an error indicating that no compatible remoting library is available.
Example
>>> # args must provide WINRM_* settings (hostname, creds, transport, etc.)
>>> run_ps(args, "Get-Process | Select-Object -First 1 | Format-Table Name,Id -AutoSize")
{'retc': 0, 'stdout': 'Name Id\r\n---- --\r\n...\r\n', 'stderr': ''}