From b820dcc59bb2cb68691f893a9e58604898d73d5d Mon Sep 17 00:00:00 2001 From: Ilya Date: Sat, 8 Feb 2020 21:35:38 +0500 Subject: [PATCH 1/7] Set correct PSProvider full name --- .../engine/DataStoreAdapterProvider.cs | 4 +- .../engine/Modules/ImportProvider.Tests.ps1 | 68 +++++++++++++++++++ .../engine/Modules/ModuleCmdletBase.cs | 9 ++- 3 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 src/System.Management.Automation/engine/Modules/ImportProvider.Tests.ps1 diff --git a/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs b/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs index 84d8a80fbcb..48ed371bd87 100644 --- a/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs +++ b/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs @@ -44,9 +44,9 @@ public class ProviderInfo public string Name { get; } /// - /// Gets the full name of the provider including the pssnapin name if available. + /// Gets the full name of the provider including the module name if available. /// - internal string FullName + public string FullName { get { diff --git a/src/System.Management.Automation/engine/Modules/ImportProvider.Tests.ps1 b/src/System.Management.Automation/engine/Modules/ImportProvider.Tests.ps1 new file mode 100644 index 00000000000..e700e9214d1 --- /dev/null +++ b/src/System.Management.Automation/engine/Modules/ImportProvider.Tests.ps1 @@ -0,0 +1,68 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +Describe "Import PowerShell provider" -Tags "CI" { + BeforeAll { + $testModulePath = Join-Path $TestDrive "ReproModule" + New-Item -Path $testModulePath -ItemType Directory > $null + + New-ModuleManifest -Path "$testModulePath/ReproModule.psd1" -RootModule 'testmodule.dll' + + $testBinaryModulePath = Join-Path $testModulePath "testmodule.dll" + $binaryModule = @' +using System; +using System.Collections.ObjectModel; +using System.Management.Automation; +using System.Management.Automation.Provider; + +namespace module { + [CmdletProvider( + "SamplePrv", + ProviderCapabilities.ShouldProcess)] + public class SampleProvider : ContainerCmdletProvider { + protected override bool IsValidPath(string path) { + return true; + } + + protected override bool ItemExists(string path) { + return path == "test.txt"; + } + + protected override void GetItem(string path) { + Item resultItem; + if (path == "test.txt") { + resultItem = new Item { Name = "test.txt" }; + } else { + throw new Exception("Item not found."); + } + + WriteItemObject(resultItem, path, false); + } + + protected override Collection InitializeDefaultDrives() { + var drive = new PSDriveInfo( + "defaultSampleDrive", + ProviderInfo, + "/", + "Sample default drive", + null); + var result = new Collection {drive}; + return result; + } + + private class Item { + public string Name { get; set; } + } + } +} +'@ + Add-Type -OutputAssembly $testBinaryModulePath -TypeDefinition $binaryModule + + $pwsh = "$PSHOME\pwsh" + } + + It "Import a PowerShell provider with correct name" { + $result = & $pwsh -NoProfile -Command "Import-Module -Name $testModulePath; (Get-PSProvider ReproModule\SamplePrv).FullName" + $result | Should -BeExactly "ReproModule\SamplePrv" + } +} diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index 7da27ca0378..39663c960ed 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -3088,8 +3088,15 @@ internal PSModuleInfo LoadModuleManifest( // In that case, the nested module will first be loaded with a different session state, and then when trying to load the RootModule via 'LoadModuleNamedInManifest', // the same loaded nested module will be reused for the RootModule by 'LoadModuleNamedInManifest'. - // Change the module name to match the manifest name, not the original name + // Initially the original module name comes from RootModule manifest property but real name comes from the module (manifest) path. + // Change the module name to match the manifest name, not the original name. + // Then do the same for all providers loaded in the module since a provider caches full name based on the module name. newManifestInfo.SetName(manifestInfo.Name); + IEnumerable pis = ss.Provider.GetAll().Where((pi) => { return object.ReferenceEquals(pi.Module, newManifestInfo); }); + foreach (ProviderInfo pi in pis) + { + pi.SetModule(manifestInfo); + } // Copy in any nested modules... foreach (PSModuleInfo nm in manifestInfo.NestedModules) From ca60661a3995f14bfca1596402be3e4837571d81 Mon Sep 17 00:00:00 2001 From: Ilya Date: Sun, 9 Feb 2020 09:26:48 +0500 Subject: [PATCH 2/7] Fix NRE --- .../engine/Modules/ModuleCmdletBase.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index 39663c960ed..951e514c923 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -3092,10 +3092,15 @@ internal PSModuleInfo LoadModuleManifest( // Change the module name to match the manifest name, not the original name. // Then do the same for all providers loaded in the module since a provider caches full name based on the module name. newManifestInfo.SetName(manifestInfo.Name); - IEnumerable pis = ss.Provider.GetAll().Where((pi) => { return object.ReferenceEquals(pi.Module, newManifestInfo); }); - foreach (ProviderInfo pi in pis) + if (ss != null) { - pi.SetModule(manifestInfo); + foreach (ProviderInfo pi in ss.Provider.GetAll()) + { + if (object.ReferenceEquals(pi.Module, newManifestInfo)) + { + pi.SetModule(manifestInfo); + } + } } // Copy in any nested modules... From 03296daeb3e28841255a9ddd36c5581ff9b88786 Mon Sep 17 00:00:00 2001 From: Ilya Date: Mon, 10 Feb 2020 08:02:35 +0500 Subject: [PATCH 3/7] Update src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs Co-Authored-By: Robert Holt --- .../engine/Modules/ModuleCmdletBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index 951e514c923..0c12aabfb10 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -3098,7 +3098,7 @@ internal PSModuleInfo LoadModuleManifest( { if (object.ReferenceEquals(pi.Module, newManifestInfo)) { - pi.SetModule(manifestInfo); + pi.SetModule(manifestInfo); } } } From f0c146dfd32a2e06fa23ea8b392dc76d60255609 Mon Sep 17 00:00:00 2001 From: Ilya Date: Tue, 11 Feb 2020 08:48:25 +0500 Subject: [PATCH 4/7] Revert FullName --- .../engine/DataStoreAdapterProvider.cs | 2 +- .../engine/Modules/ImportProvider.Tests.ps1 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs b/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs index 48ed371bd87..cb340681b0f 100644 --- a/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs +++ b/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs @@ -46,7 +46,7 @@ public class ProviderInfo /// /// Gets the full name of the provider including the module name if available. /// - public string FullName + internal string FullName { get { diff --git a/src/System.Management.Automation/engine/Modules/ImportProvider.Tests.ps1 b/src/System.Management.Automation/engine/Modules/ImportProvider.Tests.ps1 index e700e9214d1..993138e80be 100644 --- a/src/System.Management.Automation/engine/Modules/ImportProvider.Tests.ps1 +++ b/src/System.Management.Automation/engine/Modules/ImportProvider.Tests.ps1 @@ -62,7 +62,7 @@ namespace module { } It "Import a PowerShell provider with correct name" { - $result = & $pwsh -NoProfile -Command "Import-Module -Name $testModulePath; (Get-PSProvider ReproModule\SamplePrv).FullName" - $result | Should -BeExactly "ReproModule\SamplePrv" + $result = & $pwsh -NoProfile -Command "Import-Module -Name $testModulePath; Get-Item ReproModule\SamplePrv::test.txt" + $result.PSPath | Should -BeExactly "ReproModule\SamplePrv::test.txt" } } From 47e0d30194e307cf6859b257d221fb40a9e26ffb Mon Sep 17 00:00:00 2001 From: Ilya Date: Sat, 25 Apr 2020 12:02:21 +0500 Subject: [PATCH 5/7] Address feedback --- .../engine/DataStoreAdapterProvider.cs | 10 +++++++++- .../engine/Modules/ModuleCmdletBase.cs | 12 ------------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs b/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs index cb340681b0f..2ba0a613430 100644 --- a/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs +++ b/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs @@ -77,10 +77,18 @@ string GetFullName(string name, string psSnapInName, string moduleName) return result; } - return _fullName ?? (_fullName = GetFullName(Name, PSSnapInName, ModuleName)); + if (_fullName != null && ModuleName.Equals(_cachedModuleName, StringComparison.Ordinal)) + { + return _fullName; + } + + _cachedModuleName = ModuleName; + return (_fullName = GetFullName(Name, PSSnapInName, ModuleName)); } } + private string _cachedModuleName = null; + /// /// Gets the Snap-in in which the provider is implemented. /// diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index 0c12aabfb10..a4b30616132 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -3088,20 +3088,8 @@ internal PSModuleInfo LoadModuleManifest( // In that case, the nested module will first be loaded with a different session state, and then when trying to load the RootModule via 'LoadModuleNamedInManifest', // the same loaded nested module will be reused for the RootModule by 'LoadModuleNamedInManifest'. - // Initially the original module name comes from RootModule manifest property but real name comes from the module (manifest) path. // Change the module name to match the manifest name, not the original name. - // Then do the same for all providers loaded in the module since a provider caches full name based on the module name. newManifestInfo.SetName(manifestInfo.Name); - if (ss != null) - { - foreach (ProviderInfo pi in ss.Provider.GetAll()) - { - if (object.ReferenceEquals(pi.Module, newManifestInfo)) - { - pi.SetModule(manifestInfo); - } - } - } // Copy in any nested modules... foreach (PSModuleInfo nm in manifestInfo.NestedModules) From 39014992cc0a624dd99883e2bc07c2a5dde8e1ea Mon Sep 17 00:00:00 2001 From: Ilya Date: Sat, 25 Apr 2020 12:45:52 +0500 Subject: [PATCH 6/7] Fix CodeFactor issue --- .../engine/DataStoreAdapterProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs b/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs index 2ba0a613430..f7ec879dfa5 100644 --- a/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs +++ b/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs @@ -83,7 +83,7 @@ string GetFullName(string name, string psSnapInName, string moduleName) } _cachedModuleName = ModuleName; - return (_fullName = GetFullName(Name, PSSnapInName, ModuleName)); + return _fullName = GetFullName(Name, PSSnapInName, ModuleName); } } From 1859ca6c3e4e6c9d40c1f6c4c29484ffd00359b7 Mon Sep 17 00:00:00 2001 From: Ilya Date: Sat, 25 Apr 2020 12:47:39 +0500 Subject: [PATCH 7/7] Fix Codacy issue --- .../engine/DataStoreAdapterProvider.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs b/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs index f7ec879dfa5..d341b2803dd 100644 --- a/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs +++ b/src/System.Management.Automation/engine/DataStoreAdapterProvider.cs @@ -37,6 +37,7 @@ public class ProviderInfo private SessionState _sessionState; private string _fullName; + private string _cachedModuleName; /// /// Gets the name of the provider. @@ -87,8 +88,6 @@ string GetFullName(string name, string psSnapInName, string moduleName) } } - private string _cachedModuleName = null; - /// /// Gets the Snap-in in which the provider is implemented. ///