diff --git a/src/System.Management.Automation/engine/CommandDiscovery.cs b/src/System.Management.Automation/engine/CommandDiscovery.cs index d0e2d568ab..c656f23fc3 100644 --- a/src/System.Management.Automation/engine/CommandDiscovery.cs +++ b/src/System.Management.Automation/engine/CommandDiscovery.cs @@ -306,7 +306,7 @@ namespace System.Management.Automation ScriptRequiresException scriptRequiresException = new ScriptRequiresException( scriptInfo.Name, - new Collection { requiredModule.Name }, + new Collection { requiredModule.GetRequiredModuleNotFoundVersionMessage() }, "ScriptRequiresMissingModules", false, error); diff --git a/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs b/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs index 8c333ec154..3c06ee856f 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs @@ -165,6 +165,49 @@ namespace Microsoft.PowerShell.Commands return null; } + internal string GetRequiredModuleNotFoundVersionMessage() + { + if (RequiredVersion is not null) + { + return StringUtil.Format( + Modules.RequiredModuleNotFoundRequiredVersion, + Name, + RequiredVersion); + } + + bool hasVersion = Version is not null; + bool hasMaximumVersion = MaximumVersion is not null; + + if (hasVersion && hasMaximumVersion) + { + return StringUtil.Format( + Modules.RequiredModuleNotFoundModuleAndMaximumVersion, + Name, + Version, + MaximumVersion); + } + + if (hasVersion) + { + return StringUtil.Format( + Modules.RequiredModuleNotFoundModuleVersion, + Name, + Version); + } + + if (hasMaximumVersion) + { + return StringUtil.Format( + Modules.RequiredModuleNotFoundMaximumVersion, + Name, + MaximumVersion); + } + + return StringUtil.Format( + Modules.RequiredModuleNotFoundWithoutVersion, + Name); + } + internal ModuleSpecification(PSModuleInfo moduleInfo) { ArgumentNullException.ThrowIfNull(moduleInfo); diff --git a/src/System.Management.Automation/resources/Modules.resx b/src/System.Management.Automation/resources/Modules.resx index b6cc75d6fa..4afcaa2585 100644 --- a/src/System.Management.Automation/resources/Modules.resx +++ b/src/System.Management.Automation/resources/Modules.resx @@ -231,6 +231,21 @@ The required module '{1}' with MinimumVersion '{2}' and MaximumVersion '{3}' is not loaded. Load the module or remove the module from 'RequiredModules' in the file '{0}'. + + The module '{0}' cannot be found with ModuleVersion '{1}'. + + + The module '{0}' cannot be found with RequiredVersion '{1}'. + + + The module '{0}' cannot be found with MaximumVersion '{1}'. + + + The module '{0}' cannot be found with ModuleVersion '{1}' and MaximumVersion '{2}'. + + + The module '{0}' cannot be found. + No modules were removed. Verify that the specification of modules to remove is correct and those modules exist in the runspace. diff --git a/test/powershell/Language/Scripting/Requires.Tests.ps1 b/test/powershell/Language/Scripting/Requires.Tests.ps1 index 30dd73451c..1625e0b3c1 100644 --- a/test/powershell/Language/Scripting/Requires.Tests.ps1 +++ b/test/powershell/Language/Scripting/Requires.Tests.ps1 @@ -118,21 +118,73 @@ Describe "#requires -Modules" -Tags "CI" { $badName = 'ModuleThatDoesNotExist' $badPath = Join-Path $TestDrive 'ModuleThatDoesNotExist' $version = '1.0' + $requiredVersion = '1.1' + $maximumVersion = '1.2' $testCases = @( - @{ ModuleRequirement = "'$badName'"; Scenario = 'name' } - @{ ModuleRequirement = "'$badPath'"; Scenario = 'path' } - @{ ModuleRequirement = "@{ ModuleName = '$badName'; ModuleVersion = '$version' }"; Scenario = 'fully qualified name with name' } - @{ ModuleRequirement = "@{ ModuleName = '$badPath'; ModuleVersion = '$version' }"; Scenario = 'fully qualified name with path' } + @{ + ModuleRequirement = $badName + Scenario = 'fully qualified with module name' + ExpectedMessageStrings = @($badName) + } + @{ + ModuleRequirement = $badPath + Scenario = 'fully qualified with module path' + ExpectedMessageStrings = @($badPath) + } + @{ + ModuleRequirement = "@{ ModuleName = '$badName'; ModuleVersion = '$version' }" + Scenario = 'fully qualified with module name and version' + ExpectedMessageStrings = @($badName, $version) + } + @{ + ModuleRequirement = "@{ ModuleName = '$badPath'; ModuleVersion = '$version' }" + Scenario = 'fully qualified with module name and version' + ExpectedMessageStrings = @($badPath, $version) + } + @{ + ModuleRequirement = "@{ ModuleName = '$badName'; RequiredVersion = '$requiredVersion' }" + Scenario = 'fully qualified with module name and required version' + ExpectedMessageStrings = @($badName, $requiredVersion) + } + @{ + ModuleRequirement = "@{ ModuleName = '$badPath'; RequiredVersion = '$requiredVersion' }" + Scenario = 'fully qualified with module path and required version' + ExpectedMessageStrings = @($badPath, $requiredVersion) + } + @{ + ModuleRequirement = "@{ ModuleName = '$badName'; MaximumVersion = '$maximumVersion' }" + Scenario = 'fully qualified with module name and maximum version' + ExpectedMessageStrings = @($badName, $maximumVersion) + } + @{ + ModuleRequirement = "@{ ModuleName = '$badPath'; MaximumVersion = '$maximumVersion' }" + Scenario = 'fully qualified with module path and maximum version' + ExpectedMessageStrings = @($badPath, $maximumVersion) + } + @{ + ModuleRequirement = "@{ ModuleName = '$badName'; ModuleVersion = '$version'; MaximumVersion = '$maximumVersion' }" + Scenario = 'fully qualified with module name and version and maximum version' + ExpectedMessageStrings = @($badName, $version, $maximumVersion) + } + @{ + ModuleRequirement = "@{ ModuleName = '$badPath'; ModuleVersion = '$version'; MaximumVersion = '$maximumVersion' }" + Scenario = 'fully qualified with module path and version and maximum version' + ExpectedMessageStrings = @($badPath, $version, $maximumVersion) + } ) } It "Fails parsing a script that requires module by " -TestCases $testCases { - param([string]$ModuleRequirement, [string]$Scenario) + param([string]$ModuleRequirement, [string]$Scenario, [string[]]$ExpectedMessageStrings) $script = "#requires -Modules $ModuleRequirement`n`nWrite-Output 'failed'" $null = New-Item -Path $scriptPath -Value $script -Force - { & $scriptPath } | Should -Throw -ErrorId 'ScriptRequiresMissingModules' + $ex = { & $scriptPath } | Should -Throw -ErrorId 'ScriptRequiresMissingModules' -PassThru + + $expectedPattern = $ExpectedMessageStrings.ForEach{ [regex]::Escape($_) } -join '|' + $stringMatches = [regex]::Matches($ex.Exception.Message, $expectedPattern) + $stringMatches | Should -HaveCount $ExpectedMessageStrings.Count } }