From eb47c22339475490c2cba332e2d1892294e5612e Mon Sep 17 00:00:00 2001 From: Ilya Date: Sat, 25 Jan 2020 14:10:39 +0500 Subject: [PATCH] Add custom 'Selected.*' type to PSCustomObject in Select-Object only once (#11548) Before the fix Select-Object without parameters added custom 'Selected.' type to PSCustomObject even if this type was already present in TypeNames that was a memory leak in the edge case. The cause of the problem was that Select-Object without parameters did not create a new object but forwarded the original. The fix is to add custom 'Selected.' type only if object is original and it has not already custom 'Selected.*' type. --- .../commands/utility/Select-Object.cs | 14 ++++++++---- .../Select-Object.Tests.ps1 | 22 +++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Select-Object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Select-Object.cs index 8d97952d61..47a6c2d51c 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Select-Object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Select-Object.cs @@ -607,7 +607,7 @@ namespace Microsoft.PowerShell.Commands { if (obj != AutomationNull.Value) { - SetPSCustomObject(obj); + SetPSCustomObject(obj, newPSObject: addedNoteProperties.Count > 0); WriteObject(obj); } @@ -648,16 +648,22 @@ namespace Microsoft.PowerShell.Commands if (isObjUnique) { - SetPSCustomObject(obj); + SetPSCustomObject(obj, newPSObject: addedNoteProperties.Count > 0); _uniques.Add(new UniquePSObjectHelper(obj, addedNoteProperties.Count)); } } } - private void SetPSCustomObject(PSObject psObj) + private void SetPSCustomObject(PSObject psObj, bool newPSObject) { if (psObj.ImmediateBaseObject is PSCustomObject) - psObj.TypeNames.Insert(0, "Selected." + InputObject.BaseObject.GetType().ToString()); + { + var typeName = "Selected." + InputObject.BaseObject.GetType().ToString(); + if (newPSObject || !psObj.TypeNames.Contains(typeName)) + { + psObj.TypeNames.Insert(0, typeName); + } + } } private void ProcessObjectAndHandleErrors(PSObject pso) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Select-Object.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Select-Object.Tests.ps1 index e1de2303a4..2071e0a53c 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Select-Object.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Select-Object.Tests.ps1 @@ -1,5 +1,6 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. + . (Join-Path -Path $PSScriptRoot -ChildPath Test-Mocks.ps1) Add-TestDynamicType @@ -349,4 +350,25 @@ Describe "Select-Object with Property = '*'" -Tags "CI" { $p = Get-Process -Id $PID | Select-Object -Property Process* -ExcludeProperty ProcessorAffinity -ExpandProperty Modules $p[0].psobject.Properties.Item("ProcessorAffinity") | Should -BeNullOrEmpty } + + It "Select-Object add 'Selected.*' type only once" { + $obj = [PSCustomObject]@{ Name = 1 } + + $obj.psobject.TypeNames.Count | Should -Be 2 + $obj.psobject.TypeNames | Should -Not -BeLike "Selected*" + + $obj = $obj | Select-Object + + $obj.psobject.TypeNames.Count | Should -Be 3 + $obj.psobject.TypeNames[0] | Should -BeLike "Selected*" + $obj.psobject.TypeNames[1] | Should -Not -BeLike "Selected*" + $obj.psobject.TypeNames[2] | Should -Not -BeLike "Selected*" + + $obj = $obj | Select-Object + + $obj.psobject.TypeNames.Count | Should -Be 3 + $obj.psobject.TypeNames[0] | Should -BeLike "Selected*" + $obj.psobject.TypeNames[1] | Should -Not -BeLike "Selected*" + $obj.psobject.TypeNames[2] | Should -Not -BeLike "Selected*" + } }