diff --git a/src/System.Management.Automation/engine/Modules/ImportModuleCommand.cs b/src/System.Management.Automation/engine/Modules/ImportModuleCommand.cs index 226dd37a812..6f160e2490b 100644 --- a/src/System.Management.Automation/engine/Modules/ImportModuleCommand.cs +++ b/src/System.Management.Automation/engine/Modules/ImportModuleCommand.cs @@ -1870,18 +1870,7 @@ protected override void ProcessRecord() { if (this.UseWindowsPowerShell) { - var WindowsPowerShellCompatRemotingSession = CreateWindowsPowerShellCompatResources(); - if (WindowsPowerShellCompatRemotingSession != null) - { - foreach(PSModuleInfo moduleProxy in ImportModule_RemotelyViaPsrpSession(importModuleOptions, this.Name, this.FullyQualifiedName, WindowsPowerShellCompatRemotingSession, true)) - { - moduleProxy.IsWindowsPowerShellCompatModule = true; - System.Threading.Interlocked.Increment(ref s_WindowsPowerShellCompatUsageCounter); - - string message = StringUtil.Format(Modules.WinCompatModuleWarning, moduleProxy.Name, WindowsPowerShellCompatRemotingSession.Name); - WriteWarning(message); - } - } + ImportModulesUsingWinCompat(this.Name, this.FullyQualifiedName, importModuleOptions); } } else @@ -1890,6 +1879,27 @@ protected override void ProcessRecord() } } + internal override IList ImportModulesUsingWinCompat(IEnumerable moduleNames, IEnumerable moduleFullyQualifiedNames, ImportModuleOptions importModuleOptions) + { + PSSession WindowsPowerShellCompatRemotingSession = CreateWindowsPowerShellCompatResources(); + if (WindowsPowerShellCompatRemotingSession == null) + { + return new List(); + } + + var moduleProxyList = ImportModule_RemotelyViaPsrpSession(importModuleOptions, moduleNames, moduleFullyQualifiedNames, WindowsPowerShellCompatRemotingSession, usingWinCompat: true); + foreach(PSModuleInfo moduleProxy in moduleProxyList) + { + moduleProxy.IsWindowsPowerShellCompatModule = true; + System.Threading.Interlocked.Increment(ref s_WindowsPowerShellCompatUsageCounter); + + string message = StringUtil.Format(Modules.WinCompatModuleWarning, moduleProxy.Name, WindowsPowerShellCompatRemotingSession.Name); + WriteWarning(message); + } + + return moduleProxyList; + } + private void SetModuleBaseForEngineModules(string moduleName, System.Management.Automation.ExecutionContext context) { // Set modulebase of engine modules to point to $pshome diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index 68f613135b4..7fa4ec6a574 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -2367,14 +2367,7 @@ internal PSModuleInfo LoadModuleManifest( { if (importingModule) { - var commandInfo = new CmdletInfo("Import-Module", typeof(ImportModuleCommand)); - using var ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace); - ps.AddCommand(commandInfo); - ps.AddParameter("PassThru", true); - ps.AddParameter("Name", moduleManifestPath); - ps.AddParameter("UseWindowsPowerShell", true); - - var moduleProxies = ps.Invoke(); + IList moduleProxies = ImportModulesUsingWinCompat(new string [] {moduleManifestPath}, null, new ImportModuleOptions()); // we are loading by a single ManifestPath so expect max of 1 if(moduleProxies.Count > 0) @@ -4867,6 +4860,8 @@ internal void CleanupWindowsPowerShellCompatResources() } } + internal virtual IList ImportModulesUsingWinCompat(IEnumerable moduleNames, IEnumerable moduleFullyQualifiedNames, ImportModuleOptions importModuleOptions) {throw new System.NotImplementedException();} + private void RemoveTypesAndFormatting( IList formatFilesToRemove, IList typeFilesToRemove) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/CompatiblePSEditions.Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/CompatiblePSEditions.Module.Tests.ps1 index 43069749824..58302834fbb 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/CompatiblePSEditions.Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/CompatiblePSEditions.Module.Tests.ps1 @@ -30,7 +30,8 @@ function New-EditionCompatibleModule param( [Parameter(Mandatory = $true)][string]$ModuleName, [string]$DirPath, - [string[]]$CompatiblePSEditions) + [string[]]$CompatiblePSEditions, + [string]$ErrorGenerationCode='') $modulePath = Join-Path $DirPath $ModuleName @@ -41,7 +42,7 @@ function New-EditionCompatibleModule New-Item -Path $modulePath -ItemType Directory - New-Item -Path $psm1Path -Value "function Test-$ModuleName { `$true } function Test-${ModuleName}PSEdition { `$PSVersionTable.PSEdition }" -Force + New-Item -Path $psm1Path -Value "$ErrorGenerationCode function Test-$ModuleName { `$true } function Test-${ModuleName}PSEdition { `$PSVersionTable.PSEdition }" -Force if ($CompatiblePSEditions) { @@ -130,7 +131,6 @@ function New-TestNestedModule [scriptblock]::Create($newManifestCmd).Invoke() } - Describe "Get-Module with CompatiblePSEditions-checked paths" -Tag "CI" { BeforeAll { @@ -363,6 +363,50 @@ Describe "Import-Module from CompatiblePSEditions-checked paths" -Tag "CI" { } } +Describe "Additional tests for Import-Module with WinCompat" -Tag "CI" { + BeforeAll { + $ModuleName = "DesktopModule" + $basePath = Join-Path $TestDrive "WinCompatModules" + Remove-Item -Path $basePath -Recurse -ErrorAction SilentlyContinue + # create an incompatible module that generates an error on import + New-EditionCompatibleModule -ModuleName $ModuleName -CompatiblePSEditions "Desktop" -Dir $basePath -ErrorGenerationCode '1/0;' + } + + Context "Tests that ErrorAction/WarningAction have effect when Import-Module with WinCompat is used" { + BeforeAll { + Add-ModulePath $basePath + } + + AfterAll { + Restore-ModulePath + } + + It "Verify that Error is generated with default ErrorAction" -Skip:(-not $IsWindows) { + $LogPath = Join-Path $TestDrive (New-Guid).ToString() + pwsh -NoProfile -NonInteractive -c "[System.Management.Automation.Internal.InternalTestHooks]::SetTestHook('TestWindowsPowerShellPSHomeLocation', `'$basePath`');Import-Module $ModuleName" *> $LogPath + $LogPath | Should -FileContentMatch 'divide by zero' + } + + It "Verify that Warning is generated with default WarningAction" -Skip:(-not $IsWindows) { + $LogPath = Join-Path $TestDrive (New-Guid).ToString() + pwsh -NoProfile -NonInteractive -c "[System.Management.Automation.Internal.InternalTestHooks]::SetTestHook('TestWindowsPowerShellPSHomeLocation', `'$basePath`');Import-Module $ModuleName" *> $LogPath + $LogPath | Should -FileContentMatch 'loaded in Windows PowerShell' + } + + It "Verify that Error is Not generated with -ErrorAction Ignore" -Skip:(-not $IsWindows) { + $LogPath = Join-Path $TestDrive (New-Guid).ToString() + pwsh -NoProfile -NonInteractive -c "[System.Management.Automation.Internal.InternalTestHooks]::SetTestHook('TestWindowsPowerShellPSHomeLocation', `'$basePath`');Import-Module $ModuleName -ErrorAction Ignore" *> $LogPath + $LogPath | Should -Not -FileContentMatch 'divide by zero' + } + + It "Verify that Warning is Not generated with -WarningAction Ignore" -Skip:(-not $IsWindows) { + $LogPath = Join-Path $TestDrive (New-Guid).ToString() + pwsh -NoProfile -NonInteractive -c "[System.Management.Automation.Internal.InternalTestHooks]::SetTestHook('TestWindowsPowerShellPSHomeLocation', `'$basePath`');Import-Module $ModuleName -WarningAction Ignore" *> $LogPath + $LogPath | Should -Not -FileContentMatch 'loaded in Windows PowerShell' + } + } +} + Describe "PSModulePath changes interacting with other PowerShell processes" -Tag "Feature" { $PSDefaultParameterValues = @{ 'It:Skip' = (-not $IsWindows) }