0
# Protocol Interface
1
2
Low-level SOAP protocol implementation providing full control over WinRM operations. The Protocol class offers fine-grained management of shell lifecycle, command streaming, input/output handling, and advanced WS-Management features for complex automation scenarios.
3
4
## Capabilities
5
6
### Protocol Initialization
7
8
Creates a Protocol instance with comprehensive configuration options for authentication, transport, timeouts, and security settings.
9
10
```python { .api }
11
class Protocol:
12
"""Low-level SOAP protocol implementation for WinRM operations."""
13
14
# Default configuration constants
15
DEFAULT_READ_TIMEOUT_SEC = 30
16
DEFAULT_OPERATION_TIMEOUT_SEC = 20
17
DEFAULT_MAX_ENV_SIZE = 153600
18
DEFAULT_LOCALE = "en-US"
19
20
def __init__(
21
self,
22
endpoint: str,
23
transport: Literal["auto", "basic", "certificate", "ntlm", "kerberos", "credssp", "plaintext", "ssl"] = "plaintext",
24
username: str | None = None,
25
password: str | None = None,
26
realm: None = None,
27
service: str = "HTTP",
28
keytab: None = None,
29
ca_trust_path: Literal["legacy_requests"] | str = "legacy_requests",
30
cert_pem: str | None = None,
31
cert_key_pem: str | None = None,
32
server_cert_validation: Literal["validate", "ignore"] | None = "validate",
33
kerberos_delegation: bool = False,
34
read_timeout_sec: str | int = DEFAULT_READ_TIMEOUT_SEC,
35
operation_timeout_sec: str | int = DEFAULT_OPERATION_TIMEOUT_SEC,
36
kerberos_hostname_override: str | None = None,
37
message_encryption: Literal["auto", "always", "never"] = "auto",
38
credssp_disable_tlsv1_2: bool = False,
39
send_cbt: bool = True,
40
proxy: Literal["legacy_requests"] | str | None = "legacy_requests"
41
):
42
"""
43
Initialize Protocol with comprehensive WinRM configuration.
44
45
Parameters:
46
- endpoint: WinRM webservice endpoint URL
47
- transport: authentication/transport method
48
- username: authentication username
49
- password: authentication password
50
- service: service name for Kerberos (default: "HTTP")
51
- ca_trust_path: CA trust path or "legacy_requests" for environment variables
52
- cert_pem: client certificate file path (PEM format)
53
- cert_key_pem: client certificate key file path (PEM format)
54
- server_cert_validation: certificate validation ("validate" or "ignore")
55
- kerberos_delegation: enable Kerberos ticket forwarding
56
- read_timeout_sec: HTTP connection/read timeout (must exceed operation_timeout_sec)
57
- operation_timeout_sec: WinRM operation timeout
58
- kerberos_hostname_override: override hostname for Kerberos SPN
59
- message_encryption: message-level encryption setting
60
- credssp_disable_tlsv1_2: disable TLS 1.2 for CredSSP
61
- send_cbt: send channel binding tokens
62
- proxy: proxy configuration
63
"""
64
```
65
66
### Shell Management
67
68
Create and manage remote shells with customizable environment, working directory, and shell options.
69
70
```python { .api }
71
def open_shell(
72
self,
73
i_stream: str = "stdin",
74
o_stream: str = "stdout stderr",
75
working_directory: str | None = None,
76
env_vars: dict[str, str] | None = None,
77
noprofile: bool = False,
78
codepage: int = 437,
79
lifetime: None = None,
80
idle_timeout: str | int | None = None
81
) -> str:
82
"""
83
Open a remote shell for command execution.
84
85
Parameters:
86
- i_stream: input stream specification (default: "stdin")
87
- o_stream: output stream specification (default: "stdout stderr")
88
- working_directory: initial working directory
89
- env_vars: environment variables dictionary
90
- noprofile: skip loading user profile
91
- codepage: shell code page (default: 437)
92
- lifetime: maximum shell lifetime (default: None for server default)
93
- idle_timeout: idle timeout before shell closure (default: None for server default)
94
95
Returns:
96
Shell ID string for subsequent operations
97
"""
98
99
def close_shell(self, shell_id: str, close_session: bool = True) -> None:
100
"""
101
Close remote shell and optionally the transport session.
102
103
Parameters:
104
- shell_id: shell identifier from open_shell()
105
- close_session: whether to close the underlying transport session
106
"""
107
```
108
109
**Usage Example:**
110
111
```python
112
from winrm import Protocol
113
114
protocol = Protocol(
115
'http://windows-host:5985/wsman',
116
username='administrator',
117
password='password',
118
transport='ntlm'
119
)
120
121
# Open shell with custom environment
122
env_vars = {
123
'PATH': 'C:\\Windows\\System32;C:\\Windows',
124
'TEMP': 'C:\\Temp'
125
}
126
127
shell_id = protocol.open_shell(
128
working_directory='C:\\Scripts',
129
env_vars=env_vars,
130
lifetime=1800
131
)
132
133
# Use shell for multiple commands...
134
135
protocol.close_shell(shell_id)
136
```
137
138
### Command Execution
139
140
Execute commands within shells with fine-grained control over execution mode and command arguments.
141
142
```python { .api }
143
def run_command(
144
self,
145
shell_id: str,
146
command: str,
147
arguments: collections.abc.Iterable[str | bytes] = (),
148
console_mode_stdin: bool = True,
149
skip_cmd_shell: bool = False
150
) -> str:
151
"""
152
Execute command in specified shell.
153
154
Parameters:
155
- shell_id: target shell identifier
156
- command: command to execute
157
- arguments: command arguments
158
- console_mode_stdin: enable console mode for stdin
159
- skip_cmd_shell: bypass cmd.exe shell wrapper
160
161
Returns:
162
Command ID for output retrieval and cleanup
163
"""
164
165
def cleanup_command(self, shell_id: str, command_id: str) -> None:
166
"""
167
Clean up command resources after execution.
168
169
Parameters:
170
- shell_id: shell containing the command
171
- command_id: command identifier from run_command()
172
"""
173
```
174
175
### Input/Output Operations
176
177
Handle command input and retrieve output with support for streaming and partial results.
178
179
```python { .api }
180
def send_command_input(
181
self,
182
shell_id: str,
183
command_id: str,
184
stdin_input: str | bytes,
185
end: bool = False
186
) -> None:
187
"""
188
Send input to running command.
189
190
Parameters:
191
- shell_id: shell identifier
192
- command_id: command identifier
193
- stdin_input: input data to send
194
- end: whether this is the final input (triggers EOF)
195
"""
196
197
def get_command_output(
198
self,
199
shell_id: str,
200
command_id: str
201
) -> tuple[bytes, bytes, int]:
202
"""
203
Retrieve command output, blocking until completion.
204
205
Parameters:
206
- shell_id: shell identifier
207
- command_id: command identifier
208
209
Returns:
210
Tuple of (stdout, stderr, status_code)
211
"""
212
213
def get_command_output_raw(
214
self,
215
shell_id: str,
216
command_id: str
217
) -> tuple[bytes, bytes, int, bool]:
218
"""
219
Retrieve command output with completion status.
220
221
Returns:
222
Tuple of (stdout, stderr, status_code, done)
223
where done indicates if command execution is complete
224
"""
225
226
# Legacy alias for backward compatibility
227
_raw_get_command_output = get_command_output_raw
228
```
229
230
**Advanced Command Execution Example:**
231
232
```python
233
# Execute long-running command with streaming
234
shell_id = protocol.open_shell()
235
command_id = protocol.run_command(shell_id, 'ping', ['google.com', '-t'])
236
237
# Stream output until completion
238
while True:
239
stdout, stderr, status_code, done = protocol.get_command_output_raw(shell_id, command_id)
240
241
if stdout:
242
print(f"Output: {stdout.decode('utf-8')}")
243
if stderr:
244
print(f"Error: {stderr.decode('utf-8')}")
245
246
if done:
247
print(f"Command completed with status: {status_code}")
248
break
249
250
time.sleep(1)
251
252
protocol.cleanup_command(shell_id, command_id)
253
protocol.close_shell(shell_id)
254
```
255
256
### Interactive Command Example
257
258
```python
259
# Interactive command with input
260
shell_id = protocol.open_shell()
261
command_id = protocol.run_command(shell_id, 'python', ['-i'])
262
263
# Send Python commands
264
protocol.send_command_input(shell_id, command_id, "print('Hello, World!')\n")
265
protocol.send_command_input(shell_id, command_id, "import os\n")
266
protocol.send_command_input(shell_id, command_id, "print(os.getcwd())\n")
267
protocol.send_command_input(shell_id, command_id, "exit()\n", end=True)
268
269
# Get final output
270
stdout, stderr, status_code = protocol.get_command_output(shell_id, command_id)
271
print(f"Python session output:\n{stdout.decode('utf-8')}")
272
273
protocol.cleanup_command(shell_id, command_id)
274
protocol.close_shell(shell_id)
275
```
276
277
### Message Operations
278
279
Low-level SOAP message construction and transmission for advanced WS-Management operations.
280
281
```python { .api }
282
def build_wsman_header(
283
self,
284
action: str,
285
resource_uri: str,
286
shell_id: str | None = None,
287
message_id: str | uuid.UUID | None = None
288
) -> dict[str, Any]:
289
"""
290
Build WS-Management SOAP header for custom operations.
291
292
Parameters:
293
- action: WS-Management action URI
294
- resource_uri: resource URI for the operation
295
- shell_id: shell identifier for shell-specific operations
296
- message_id: custom message ID (auto-generated if None)
297
298
Returns:
299
SOAP header dictionary structure
300
"""
301
302
# Legacy alias for Ansible compatibility
303
_get_soap_header = build_wsman_header
304
305
def send_message(self, message: str) -> bytes:
306
"""
307
Send raw SOAP message and return response.
308
309
Parameters:
310
- message: complete SOAP message XML
311
312
Returns:
313
Raw response bytes from WinRM service
314
"""
315
```
316
317
## Timeout and Error Handling
318
319
The Protocol class provides sophisticated timeout handling:
320
321
- **read_timeout_sec**: HTTP connection and read timeout (must be > operation_timeout_sec)
322
- **operation_timeout_sec**: WinRM operation timeout for individual requests
323
- Automatic retry logic for operation timeouts during output retrieval
324
- Proper cleanup of resources on timeout or error conditions
325
326
Timeouts are validated during initialization to ensure proper operation order and prevent deadlock conditions.