Modules/businessdev.ALbuild.Containers/Private/ConvertFrom-BcCliXml.ps1
|
function ConvertFrom-BcCliXml { <# .SYNOPSIS Converts PowerShell CLIXML error-stream output into readable plain text. .DESCRIPTION Internal helper. When a child 'powershell' has its stderr captured through a pipe (as with 'docker exec ... powershell'), it serialises its error/progress streams as CLIXML: a '#< CLIXML' marker followed by an <Objs> document in which the error text is XML-escaped (ANSI colour codes as '_x001B_[..m', line breaks as '_x000D__x000A_'). Dumped raw into an exception this is unreadable, so this reconstructs the message: it deserialises the document, keeps the error-stream strings (dropping progress records), and strips ANSI escape sequences. Anything that is not CLIXML is returned unchanged, so it is always safe to call. .PARAMETER Text The captured stream text, possibly containing a CLIXML document. .OUTPUTS System.String #> [CmdletBinding()] [OutputType([string])] param( [AllowNull()] [AllowEmptyString()] [string] $Text ) if ([string]::IsNullOrWhiteSpace($Text) -or ($Text -notmatch '#<\s*CLIXML')) { return $Text } # Isolate the <Objs>...</Objs> document, keeping any plain text that precedes the marker. $markerIndex = $Text.IndexOf('#<') $prefix = $Text.Substring(0, $markerIndex).Trim() $startIndex = $Text.IndexOf('<Objs', $markerIndex) $endTag = '</Objs>' $endIndex = if ($startIndex -ge 0) { $Text.IndexOf($endTag, $startIndex) } else { -1 } if ($startIndex -lt 0 -or $endIndex -lt 0) { return $Text } $xml = $Text.Substring($startIndex, $endIndex + $endTag.Length - $startIndex) try { $objects = [System.Management.Automation.PSSerializer]::Deserialize($xml) } catch { return $Text } # Error-stream fragments deserialise to strings (already containing their line breaks); progress # and other records come back as objects and are dropped. $message = (@($objects | Where-Object { $_ -is [string] }) -join '').Trim() $message = [regex]::Replace($message, "$([char]27)\[[0-9;]*[A-Za-z]", '') $combined = @($prefix, $message.Trim()) | Where-Object { $_ } return ($combined -join [Environment]::NewLine) } |