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\\']