powershell - fix nested CLIXML parser (#71412)
This commit is contained in:
parent
3c8744f0c1
commit
8897d7e2ff
3 changed files with 38 additions and 5 deletions
2
changelogs/fragments/powershell-nested-clixml.yml
Normal file
2
changelogs/fragments/powershell-nested-clixml.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
bugfixes:
|
||||
- powershell - fix the CLIXML parser when it contains nested CLIXML objects - https://github.com/ansible/ansible/issues/69550
|
|
@ -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<Objs>...</Objs><Objs>...</Objs>'.
|
||||
# Parse each individual <Objs> element and add the error strings to our stderr list.
|
||||
# https://github.com/ansible/ansible/issues/69550
|
||||
while data:
|
||||
end_idx = data.find(b"</Objs>") + 7
|
||||
current_element = data[data.find(b"<Objs "):end_idx]
|
||||
data = data[end_idx:]
|
||||
|
||||
clixml = ET.fromstring(current_element)
|
||||
namespace_match = re.match(r'{(.*)}', clixml.tag)
|
||||
namespace = "{%s}" % namespace_match.group(1) if namespace_match else ""
|
||||
|
||||
strings = clixml.findall("./%sS" % namespace)
|
||||
lines.extend([e.text.replace('_x000D__x000A_', '') for e in strings if e.attrib.get('S') == stream])
|
||||
|
||||
strings = clixml.findall("./%sS" % namespace)
|
||||
lines = [e.text.replace('_x000D__x000A_', '') for e in strings if e.attrib.get('S') == stream]
|
||||
return to_bytes('\r\n'.join(lines))
|
||||
|
||||
|
||||
|
|
|
@ -56,6 +56,25 @@ def test_parse_clixml_multiple_streams():
|
|||
assert actual == expected
|
||||
|
||||
|
||||
def test_parse_clixml_multiple_elements():
|
||||
multiple_elements = b'#< CLIXML\r\n#< CLIXML\r\n<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">' \
|
||||
b'<Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS>' \
|
||||
b'<I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil />' \
|
||||
b'<PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj>' \
|
||||
b'<S S="Error">Error 1</S></Objs>' \
|
||||
b'<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0">' \
|
||||
b'<TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS>' \
|
||||
b'<I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil />' \
|
||||
b'<PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj>' \
|
||||
b'<Obj S="progress" RefId="1"><TNRef RefId="0" /><MS><I64 N="SourceId">2</I64>' \
|
||||
b'<PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil />' \
|
||||
b'<PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj>' \
|
||||
b'<S S="Error">Error 2</S></Objs>'
|
||||
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\\']
|
||||
|
|
Loading…
Reference in a new issue