From 78eebf98f06ce314476e9e4a6105be21cf6b1480 Mon Sep 17 00:00:00 2001 From: KirtiRamchandani Date: Mon, 25 May 2026 09:58:46 +0530 Subject: [PATCH] Avoid decorating ErrorRecord during CliXml serialization --- .../engine/serialization.cs | 20 +++++++++++++ .../clixml.tests.ps1 | 29 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/src/System.Management.Automation/engine/serialization.cs b/src/System.Management.Automation/engine/serialization.cs index add0eab25dc..414b87f9a1f 100644 --- a/src/System.Management.Automation/engine/serialization.cs +++ b/src/System.Management.Automation/engine/serialization.cs @@ -1482,6 +1482,24 @@ int depth _writer.WriteEndElement(); } + private static PSObject GetRemotingSerializationTarget(PSObject source) + { + PSObject target = source.Copy(); + + // Keep remoting-only notes local to the serialization wrapper, rather + // than writing them to the base object's resurrection table. + target.InstanceMembers = new PSMemberInfoInternalCollection(); + foreach (PSMemberInfo member in source.InstanceMembers) + { + if (!member.IsHidden) + { + target.Members.Add(member); + } + } + + return target; + } + private void HandleComplexTypePSObject ( object source, @@ -1514,6 +1532,7 @@ int depth ErrorRecord errorRecord = mshSource.ImmediateBaseObject as ErrorRecord; if (errorRecord != null) { + mshSource = GetRemotingSerializationTarget(mshSource); errorRecord.ToPSObjectForRemoting(mshSource); isErrorRecord = true; break; @@ -1522,6 +1541,7 @@ int depth InformationalRecord informationalRecord = mshSource.ImmediateBaseObject as InformationalRecord; if (informationalRecord != null) { + mshSource = GetRemotingSerializationTarget(mshSource); informationalRecord.ToPSObjectForRemoting(mshSource); isInformationalRecord = true; break; diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/clixml.tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/clixml.tests.ps1 index 58f6a4f3353..f05acbbfed8 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/clixml.tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/clixml.tests.ps1 @@ -35,6 +35,12 @@ Describe "CliXml test" -Tags "CI" { $this.testFile = $file } } + + function Get-ExtendedMemberName { + param([object] $InputObject) + + @($InputObject | Get-Member -View Extended | Select-Object -ExpandProperty Name) + } } AfterAll { @@ -184,6 +190,18 @@ Describe "CliXml test" -Tags "CI" { $cred.UserName | Should -BeExactly "Foo" $cred.Password | Should -BeOfType System.Security.SecureString } + + It "does not add remoting serialization members to ErrorRecord input" { + $filePath = Join-Path $subFilePath 'error.xml' + Write-Error foo 2>$null + $errorRecord = $Error[0] + $before = Get-ExtendedMemberName $errorRecord + + $errorRecord | Export-Clixml -Path $filePath + + $after = Get-ExtendedMemberName $errorRecord + @($after | Where-Object { $_ -notin $before }) | Should -BeNullOrEmpty + } } Context "ConvertTo-CliXml"{ @@ -232,6 +250,17 @@ Describe "CliXml test" -Tags "CI" { $isExisted | Should -BeTrue } + + It "does not add remoting serialization members to ErrorRecord input" { + Write-Error foo 2>$null + $errorRecord = $Error[0] + $before = Get-ExtendedMemberName $errorRecord + + $null = $errorRecord | ConvertTo-CliXml + + $after = Get-ExtendedMemberName $errorRecord + @($after | Where-Object { $_ -notin $before }) | Should -BeNullOrEmpty + } } Context "ConvertFrom-CliXml" {