|
10 | 10 |
|
11 | 11 | import xmltodict
|
12 | 12 |
|
13 |
| -from winrm.exceptions import WinRMError, WinRMOperationTimeoutError, WinRMTransportError |
| 13 | +from winrm.exceptions import ( |
| 14 | + WinRMError, |
| 15 | + WinRMOperationTimeoutError, |
| 16 | + WinRMTransportError, |
| 17 | + WSManFaultError, |
| 18 | +) |
14 | 19 | from winrm.transport import Transport
|
15 | 20 |
|
16 | 21 | xmlns = {
|
17 | 22 | "soapenv": "http://www.w3.org/2003/05/soap-envelope",
|
18 | 23 | "soapaddr": "http://schemas.xmlsoap.org/ws/2004/08/addressing",
|
19 | 24 | "wsmanfault": "http://schemas.microsoft.com/wbem/wsman/1/wsmanfault",
|
| 25 | + "wmierror": "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/MSFT_WmiError", |
20 | 26 | }
|
21 | 27 |
|
22 | 28 |
|
@@ -247,33 +253,49 @@ def send_message(self, message: str) -> bytes:
|
247 | 253 | raise ex
|
248 | 254 |
|
249 | 255 | fault = root.find("soapenv:Body/soapenv:Fault", xmlns)
|
250 |
| - if fault is not None: |
251 |
| - fault_data = dict(transport_message=ex.message, http_status_code=ex.code) |
252 |
| - wsmanfault_code = fault.find("soapenv:Detail/wsmanfault:WSManFault[@Code]", xmlns) |
253 |
| - if wsmanfault_code is not None: |
254 |
| - fault_data["wsmanfault_code"] = wsmanfault_code.get("Code") |
255 |
| - # convert receive timeout code to WinRMOperationTimeoutError |
256 |
| - if fault_data["wsmanfault_code"] == "2150858793": |
257 |
| - # TODO: this fault code is specific to the Receive operation; convert all op timeouts? |
258 |
| - raise WinRMOperationTimeoutError() |
259 |
| - |
260 |
| - fault_code = fault.find("soapenv:Code/soapenv:Value", xmlns) |
261 |
| - if fault_code is not None: |
262 |
| - fault_data["fault_code"] = fault_code.text |
263 |
| - |
264 |
| - fault_subcode = fault.find("soapenv:Code/soapenv:Subcode/soapenv:Value", xmlns) |
265 |
| - if fault_subcode is not None: |
266 |
| - fault_data["fault_subcode"] = fault_subcode.text |
267 |
| - |
268 |
| - error_message_node = fault.find("soapenv:Reason/soapenv:Text", xmlns) |
269 |
| - if error_message_node is not None: |
270 |
| - error_message = error_message_node.text |
271 |
| - else: |
272 |
| - error_message = "(no error message in fault)" |
273 |
| - |
274 |
| - raise WinRMError("{0} (extended fault data: {1})".format(error_message, fault_data)) |
275 |
| - |
276 |
| - raise |
| 256 | + if fault is None: |
| 257 | + raise |
| 258 | + |
| 259 | + wsmanfault_code_raw = fault.find("soapenv:Detail/wsmanfault:WSManFault[@Code]", xmlns) |
| 260 | + wsmanfault_code: int | None = None |
| 261 | + if wsmanfault_code_raw is not None: |
| 262 | + wsmanfault_code = int(wsmanfault_code_raw.attrib["Code"]) |
| 263 | + |
| 264 | + # convert receive timeout code to WinRMOperationTimeoutError |
| 265 | + if wsmanfault_code == 2150858793: |
| 266 | + # TODO: this fault code is specific to the Receive operation; convert all op timeouts? |
| 267 | + raise WinRMOperationTimeoutError() |
| 268 | + |
| 269 | + fault_code_raw = fault.find("soapenv:Code/soapenv:Value", xmlns) |
| 270 | + fault_code: str | None = None |
| 271 | + if fault_code_raw is not None and fault_code_raw.text: |
| 272 | + fault_code = fault_code_raw.text |
| 273 | + |
| 274 | + fault_subcode_raw = fault.find("soapenv:Code/soapenv:Subcode/soapenv:Value", xmlns) |
| 275 | + fault_subcode: str | None = None |
| 276 | + if fault_subcode_raw is not None and fault_subcode_raw.text: |
| 277 | + fault_subcode = fault_subcode_raw.text |
| 278 | + |
| 279 | + error_message_node = fault.find("soapenv:Reason/soapenv:Text", xmlns) |
| 280 | + reason: str | None = None |
| 281 | + if error_message_node is not None: |
| 282 | + reason = error_message_node.text |
| 283 | + |
| 284 | + wmi_error_code_raw = fault.find("soapenv:Detail/wmierror:MSFT_WmiError/wmierror:error_Code", xmlns) |
| 285 | + wmi_error_code: int | None = None |
| 286 | + if wmi_error_code_raw is not None and wmi_error_code_raw.text: |
| 287 | + wmi_error_code = int(wmi_error_code_raw.text) |
| 288 | + |
| 289 | + raise WSManFaultError( |
| 290 | + code=ex.code, |
| 291 | + message=ex.message, |
| 292 | + response=ex.response_text, |
| 293 | + reason=reason or "(no error message in fault)", |
| 294 | + fault_code=fault_code, |
| 295 | + fault_subcode=fault_subcode, |
| 296 | + wsman_fault_code=wsmanfault_code, |
| 297 | + wmierror_code=wmi_error_code, |
| 298 | + ) |
277 | 299 |
|
278 | 300 | def close_shell(self, shell_id: str, close_session: bool = True) -> None:
|
279 | 301 | """
|
|
0 commit comments