diff --git a/src/System.Management.Automation/engine/InitialSessionState.cs b/src/System.Management.Automation/engine/InitialSessionState.cs index 798b5ca4d8d..3f4e20fb3a2 100644 --- a/src/System.Management.Automation/engine/InitialSessionState.cs +++ b/src/System.Management.Automation/engine/InitialSessionState.cs @@ -1309,7 +1309,7 @@ public void Add(T item) } /// - /// + /// Add items to this collection. /// /// public void Add(IEnumerable items) @@ -1326,6 +1326,27 @@ public void Add(IEnumerable items) } } + /// + /// Special add for TypeTable type entries that removes redundant file entries. + /// + internal void AddTypeTableTypesInfo(IEnumerable items) + { + if (typeof(T) != typeof(SessionStateTypeEntry)) { throw new PSInvalidOperationException(); } + + lock (_syncObject) + { + foreach (var element in items) + { + var typeEntry = element as SessionStateTypeEntry; + if (typeEntry.TypeData != null) + { + // Skip type file entries. + _internalCollection.Add(element); + } + } + } + } + /// /// Get enumerator for this collection. /// @@ -3851,7 +3872,12 @@ internal void UpdateTypes(ExecutionContext context, bool updateOnly) context.TypeTable = typeTable; Types.Clear(); - Types.Add(typeTable.typesInfo); + + // A TypeTable contains types info along with type file references used to create the types info, + // which is redundant information. When resused in a runspace the ISS unpacks the file types again + // resulting in duplicate types and duplication errors when processed. + // So use this special Add method to filter all types files found in the TypeTable. + Types.AddTypeTableTypesInfo(typeTable.typesInfo); return; } diff --git a/test/powershell/Common/TestTypeFile.ps1xml b/test/powershell/Common/TestTypeFile.ps1xml new file mode 100644 index 00000000000..6e22c9cf3dc --- /dev/null +++ b/test/powershell/Common/TestTypeFile.ps1xml @@ -0,0 +1,13 @@ + + + + + System.Array + + + Counts + Length + + + + diff --git a/test/powershell/engine/InitialSessionState.Tests.ps1 b/test/powershell/engine/InitialSessionState.Tests.ps1 index 85b1bec4fd1..547bbddbcfb 100644 --- a/test/powershell/engine/InitialSessionState.Tests.ps1 +++ b/test/powershell/engine/InitialSessionState.Tests.ps1 @@ -54,4 +54,75 @@ Describe "InitialSessionState capacity" -Tags CI { $ps.AddScript('New-Alias -Name a5000 -Value f1; a5000').Invoke() | Should Be "fn f1" $ps.Streams.Error | Should Be $null } -} \ No newline at end of file +} + +## +## A reused InitialSessionState created from a TypeTable should not have duplicate types. +## +Describe "TypeTable duplicate types in reused runspace InitialSessionState TypeTable" -Tags 'Feature' { + + Context "No duplicate types test" { + + BeforeAll { + + $typeTable = [System.Management.Automation.Runspaces.TypeTable]::new([string[]](Join-Path $PSScriptRoot "../Common/TestTypeFile.ps1xml")) + [initialsessionstate] $iss = [initialsessionstate]::Create() + $iss.Types.Add($typeTable) + [runspace] $rs1 = [runspacefactory]::CreateRunspace($iss) + + # Process TypeTable types from ISS + $rs1.Open() + + # Get processed ISS from runspace. + $issReused = $rs1.InitialSessionState.Clone() + $issReused.ThrowOnRunspaceOpenError = $true + + # Create new runspace with reused ISS. + $rs2 = [runspacefactory]::CreateRunspace($issReused) + } + + AfterAll { + + if ($rs1 -ne $null) { $rs1.Dispose() } + if ($rs2 -ne $null) { $rs2.Dispose() } + } + + It "Verifies that a reused InitialSessionState object created from a TypeTable object does not have duplicate types" { + + { $rs2.Open() } | Should Not Throw + } + } + + Context "Cannot use shared TypeTable in ISS test" { + + BeforeAll { + + # Create default ISS and add shared TypeTable. + $typeTable = [System.Management.Automation.Runspaces.TypeTable]::new([string[]](Join-Path $PSScriptRoot "../Common/TestTypeFile.ps1xml")) + [initialsessionstate] $iss = [initialsessionstate]::CreateDefault2() + $iss.Types.Add($typeTable) + $iss.ThrowOnRunspaceOpenError = $true + [runspace] $rs = [runspacefactory]::CreateRunspace($iss) + } + + AfterAll { + + if ($rs -ne $null) { $rs.Dispose() } + } + + It "Verifies that shared TypeTable is not allowed in ISS" { + + # Process TypeTable types from ISS. + $errorId = "" + try + { + $rs.Open() + throw "No Exception!" + } + catch + { + $_.Exception.InnerException.ErrorRecord.FullyQualifiedErrorId | Should Be "ErrorsUpdatingTypes" + } + } + } +}