From b5ab2ddd40d9adea6ccd83d175cd0bddb7710be0 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Mon, 5 Nov 2018 10:41:53 -0800 Subject: [PATCH] Load assembly from module base path before trying to load from GAC (#8073) [Breaking Change] When a binary module has the module assembly in GAC, we load the assembly from GAC before trying to load it from module base path. This change attempts to load it from module base path before looking up in GAC. --- .../engine/Modules/ModuleCmdletBase.cs | 10 ++++++---- .../Import-Module.Tests.ps1 | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index 3a6ba71ccd..340b95c49c 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -4505,13 +4505,15 @@ namespace Microsoft.PowerShell.Commands result += extension; } - //For dlls, we cannot get the path from the provider. - //We need to load the assembly and then get the path. - //If the module is already loaded, this is not expensive since the assembly is already loaded in the AppDomain + // For dlls, we cannot get the path from the provider. + // We need to load the assembly and then get the path. + // If the module is already loaded, this is not expensive since the assembly is already loaded in the AppDomain + // If the dll is not loaded, we load it from the resolved path. + // We attempt to load it from the resolved path before we try to look up in GAC on Windows. if (!string.IsNullOrEmpty(ext) && ext.Equals(".dll", StringComparison.OrdinalIgnoreCase)) { Exception ignored = null; - Assembly assembly = ExecutionContext.LoadAssembly(name, null, out ignored); + Assembly assembly = ExecutionContext.LoadAssembly(name, result, out ignored); if (assembly != null) { result = assembly.Location; diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Import-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Import-Module.Tests.ps1 index 1e48961a66..2aa59cd840 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Import-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Import-Module.Tests.ps1 @@ -179,6 +179,23 @@ namespace ModuleCmdlets } } + + It 'Should load from ModuleBase path before looking up in GAC' -Skip:(-not $IsWindows) { + $module = Get-Module PSScheduledJob -ListAvailable -SkipEditionCheck + $moduleBasePath = Split-Path $module.Path + $destPath = New-Item -ItemType Directory -Path "$TestDrive/PSScheduledJob" + $gacAssemblyPath = (Get-ChildItem "${env:WinDir}\Microsoft.NET\assembly\GAC_MSIL\Microsoft.PowerShell.ScheduledJob" -Recurse -Filter 'Microsoft.PowerShell.ScheduledJob.dll').FullName + + # Copy format, type and psd1 + Copy-Item "$moduleBasePath/PSScheduledJob*.*" -Destination $destPath -Force + + # Copy assembly to temp module folder" + Copy-Item $gacAssemblyPath -Destination $destPath -Force + + # Use a different pwsh so that we do not have the PSScheduledJob module already loaded. + $loadedAssemblyLocation = pwsh -noprofile -c "Import-Module $destPath -Force; [Microsoft.PowerShell.ScheduledJob.AddJobTriggerCommand].Assembly.Location" + $loadedAssemblyLocation | Should -BeLike "$TestDrive*\Microsoft.PowerShell.ScheduledJob.dll" + } } Describe "Import-Module should be case insensitive" -Tags 'CI' {