diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index eb6adb8b7a3..a26c2c8cfa1 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -1573,6 +1573,7 @@ public static class InternalTestHooks internal static bool UseDebugAmsiImplementation; internal static bool BypassAppLockerPolicyCaching; internal static bool BypassOnlineHelpRetrieval; + internal static bool ThrowHelpCultureNotSupported; internal static bool ForcePromptForChoiceDefaultOption; internal static bool NoPromptForPassword; internal static bool ForceFormatListFixedLabelWidth; diff --git a/src/System.Management.Automation/help/UpdatableHelpCommandBase.cs b/src/System.Management.Automation/help/UpdatableHelpCommandBase.cs index af410e4bd6d..1c0576c95b6 100644 --- a/src/System.Management.Automation/help/UpdatableHelpCommandBase.cs +++ b/src/System.Management.Automation/help/UpdatableHelpCommandBase.cs @@ -509,6 +509,7 @@ private void ProcessModule(UpdatableHelpModuleInfo module) // Win8: 572882 When the system locale is English and the UI is JPN, // running "update-help" still downs English help content. var cultures = _language ?? _helpSystem.GetCurrentUICulture(); + UpdatableHelpSystemException implicitCultureNotSupported = null; foreach (string culture in cultures) { @@ -558,6 +559,12 @@ private void ProcessModule(UpdatableHelpModuleInfo module) // Display the error message only if we are not using the fallback chain ProcessException(module.ModuleName, culture, e); } + else + { + // Hold first exception, it will be displayed if fallback chain fails + WriteVerbose(StringUtil.Format(HelpDisplayStrings.HelpCultureNotSupportedFallback, e.Message)); + implicitCultureNotSupported ??= e; + } } else { @@ -581,13 +588,19 @@ private void ProcessModule(UpdatableHelpModuleInfo module) } } - // If -Language is not specified, we only install + // If -UICulture is not specified, we only install // one culture from the fallback chain if (_language == null && installed) { - break; + return; } } + + // If the exception is not null and did not return early, then all of the fallback chain failed + if (implicitCultureNotSupported != null) + { + ProcessException(module.ModuleName, cultures.First(), implicitCultureNotSupported); + } } /// diff --git a/src/System.Management.Automation/help/UpdateHelpCommand.cs b/src/System.Management.Automation/help/UpdateHelpCommand.cs index 01b17cbad7e..3e99f5a26ef 100644 --- a/src/System.Management.Automation/help/UpdateHelpCommand.cs +++ b/src/System.Management.Automation/help/UpdateHelpCommand.cs @@ -214,6 +214,14 @@ protected override void ProcessRecord() /// True if the module has been processed, false if not. internal override bool ProcessModuleWithCulture(UpdatableHelpModuleInfo module, string culture) { + // Simulate culture not found + if (InternalTestHooks.ThrowHelpCultureNotSupported) + { + throw new UpdatableHelpSystemException("HelpCultureNotSupported", + StringUtil.Format(HelpDisplayStrings.HelpCultureNotSupported, culture, "en-US"), + ErrorCategory.InvalidOperation, null, null); + } + UpdatableHelpInfo currentHelpInfo = null; UpdatableHelpInfo newHelpInfo = null; string helpInfoUri = null; diff --git a/src/System.Management.Automation/resources/HelpDisplayStrings.resx b/src/System.Management.Automation/resources/HelpDisplayStrings.resx index 8866eea8d61..222c57e3300 100644 --- a/src/System.Management.Automation/resources/HelpDisplayStrings.resx +++ b/src/System.Management.Automation/resources/HelpDisplayStrings.resx @@ -306,6 +306,10 @@ The specified culture is not supported: {0}. Specify a culture from the following list: {{{1}}}. + + Postponing error and trying fallback cultures, will show as error if none of fallbacks are supported: +{0} + The ModuleBase directory cannot be found. Verify the directory and try again. diff --git a/test/powershell/engine/Help/HelpSystem.Tests.ps1 b/test/powershell/engine/Help/HelpSystem.Tests.ps1 index bd523b1033e..e34cd956075 100644 --- a/test/powershell/engine/Help/HelpSystem.Tests.ps1 +++ b/test/powershell/engine/Help/HelpSystem.Tests.ps1 @@ -30,7 +30,8 @@ function UpdateHelpFromLocalContentPath { throw "Unable to find help content at '$helpContentPath'" } - Update-Help -Module $ModuleName -SourcePath $helpContentPath -Force -ErrorAction Stop -Scope $Scope + # Test files are 'en-US', set explicit culture so test does not help on non-US systems + Update-Help -Module $ModuleName -SourcePath $helpContentPath -UICulture 'en-US' -Force -ErrorAction Stop -Scope $Scope } function GetCurrentUserHelpRoot { diff --git a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 index f6707147324..f767ff4ea7f 100644 --- a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 +++ b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 @@ -434,6 +434,34 @@ Describe "Validate Update-Help -SourcePath for all PowerShell modules for user s RunUpdateHelpTests -Tag "Feature" -useSourcePath -Scope 'CurrentUser' } +Describe "Validate 'Update-Help' shows 'HelpCultureNotSupported' when thrown" -Tags @('Feature') { + BeforeAll { + [System.Management.Automation.Internal.InternalTestHooks]::SetTestHook('ThrowHelpCultureNotSupported', $true) + } + AfterAll { + [System.Management.Automation.Internal.InternalTestHooks]::SetTestHook('ThrowHelpCultureNotSupported', $false) + } + + It 'Shows error if help culture does not match: ' -TestCases @( + @{ 'name' = 'implicit culture'; 'culture' = $null } + @{ 'name' = 'explicit culture en-GB'; 'culture' = 'en-GB' } + @{ 'name' = 'explicit culture de-DE'; 'culture' = 'de-DE' } + ) { + param ($name, $culture) + # Cannot pass null, have to splat to skip argument entirely + $cultureArg = $culture ? @{ 'UICulture' = $culture } : @{} + $cultureUsed = $culture ?? (Get-Culture) + + $ErrorVariable = $null + $VerboseOutput = New-TemporaryFile + Update-Help @cultureArg -ErrorVariable ErrorVariable -ErrorAction SilentlyContinue -Verbose 4>$VerboseOutput + $ErrorVariable | Should -Match "No UI culture was found that matches the following pattern: ${cultureUsed}" + if (-not $culture) { + Get-Content -Raw $VerboseOutput | Should -Match 'Postponing error and trying fallback cultures' + } + } +} + Describe "Validate 'Save-Help -DestinationPath for one PowerShell modules." -Tags @('CI', 'RequireAdminOnWindows') { BeforeAll { $SavedProgressPreference = $ProgressPreference