From b936539ae1d6b970a75a3b88e0dd7d11b36cb0e9 Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Sat, 29 Aug 2020 02:54:14 +1000 Subject: [PATCH] powershell - fix nested CLIXML parser (#71412) (#71451) (cherry picked from commit 8897d7e2ff8fa37c25cd4ba039984fd3a9e13b33) --- .../fragments/powershell-nested-clixml.yml | 2 ++ lib/ansible/plugins/shell/powershell.py | 22 ++++++++++++++----- test/units/plugins/shell/test_powershell.py | 19 ++++++++++++++++ 3 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 changelogs/fragments/powershell-nested-clixml.yml diff --git a/changelogs/fragments/powershell-nested-clixml.yml b/changelogs/fragments/powershell-nested-clixml.yml new file mode 100644 index 00000000000..27ce42727e8 --- /dev/null +++ b/changelogs/fragments/powershell-nested-clixml.yml @@ -0,0 +1,2 @@ +bugfixes: +- powershell - fix the CLIXML parser when it contains nested CLIXML objects - https://github.com/ansible/ansible/issues/69550 diff --git a/lib/ansible/plugins/shell/powershell.py b/lib/ansible/plugins/shell/powershell.py index f504b16dd95..d8c2e836d3c 100644 --- a/lib/ansible/plugins/shell/powershell.py +++ b/lib/ansible/plugins/shell/powershell.py @@ -43,12 +43,24 @@ def _parse_clixml(data, stream="Error"): message encoded in the XML data. CLIXML is used by PowerShell to encode multiple objects in stderr. """ - clixml = ET.fromstring(data.split(b"\r\n", 1)[-1]) - namespace_match = re.match(r'{(.*)}', clixml.tag) - namespace = "{%s}" % namespace_match.group(1) if namespace_match else "" + lines = [] + + # There are some scenarios where the stderr contains a nested CLIXML element like + # '<# CLIXML\r\n<# CLIXML\r\n......'. + # Parse each individual element and add the error strings to our stderr list. + # https://github.com/ansible/ansible/issues/69550 + while data: + end_idx = data.find(b"") + 7 + current_element = data[data.find(b"' \ + b'System.Management.Automation.PSCustomObjectSystem.Object' \ + b'1Preparing modules for first use.0' \ + b'-1-1Completed-1 ' \ + b'Error 1' \ + b'' \ + b'System.Management.Automation.PSCustomObjectSystem.Object' \ + b'1Preparing modules for first use.0' \ + b'-1-1Completed-1 ' \ + b'2' \ + b'Preparing modules for first use.0' \ + b'-1-1Completed-1 ' \ + b'Error 2' + expected = b"Error 1\r\nError 2" + actual = _parse_clixml(multiple_elements) + assert actual == expected + + def test_join_path_unc(): pwsh = ShellModule() unc_path_parts = ['\\\\host\\share\\dir1\\\\dir2\\', '\\dir3/dir4', 'dir5', 'dir6\\']