diff --git a/src/System.Management.Automation/commands/utility/FormatAndOutput/common/DisplayDatabase/displayDescriptionData.cs b/src/System.Management.Automation/commands/utility/FormatAndOutput/common/DisplayDatabase/displayDescriptionData.cs index c8d0b26ae..a098b08f1 100644 --- a/src/System.Management.Automation/commands/utility/FormatAndOutput/common/DisplayDatabase/displayDescriptionData.cs +++ b/src/System.Management.Automation/commands/utility/FormatAndOutput/common/DisplayDatabase/displayDescriptionData.cs @@ -574,6 +574,7 @@ namespace Microsoft.PowerShell.Commands.Internal.Format { internal DatabaseLoadingInfo loadingInfo = null; internal string assemblyName = null; + internal string assemblyLocation = null; internal string baseName = null; internal string resourceId = null; } diff --git a/src/System.Management.Automation/commands/utility/FormatAndOutput/common/DisplayDatabase/displayResourceManagerCache.cs b/src/System.Management.Automation/commands/utility/FormatAndOutput/common/DisplayDatabase/displayResourceManagerCache.cs index 04cbdf9a1..84dac0626 100644 --- a/src/System.Management.Automation/commands/utility/FormatAndOutput/common/DisplayDatabase/displayResourceManagerCache.cs +++ b/src/System.Management.Automation/commands/utility/FormatAndOutput/common/DisplayDatabase/displayResourceManagerCache.cs @@ -77,7 +77,10 @@ namespace Microsoft.PowerShell.Commands.Internal.Format result = LoadingResult.AssemblyNotFound; return null; } - + else + { + resourceReference.assemblyLocation = loadResult.a.Location; + }; // load now the resource from the resource manager cache try diff --git a/src/System.Management.Automation/commands/utility/FormatAndOutput/common/DisplayDatabase/typeDataXmlLoader.cs b/src/System.Management.Automation/commands/utility/FormatAndOutput/common/DisplayDatabase/typeDataXmlLoader.cs index 81bb4148f..b5ef5a277 100644 --- a/src/System.Management.Automation/commands/utility/FormatAndOutput/common/DisplayDatabase/typeDataXmlLoader.cs +++ b/src/System.Management.Automation/commands/utility/FormatAndOutput/common/DisplayDatabase/typeDataXmlLoader.cs @@ -1832,8 +1832,7 @@ namespace Microsoft.PowerShell.Commands.Internal.Format { case DisplayResourceManagerCache.AssemblyBindingStatus.FoundInPath: { - assemblyDisplayName = - System.IO.Path.Combine(resource.loadingInfo.fileDirectory, resource.assemblyName); + assemblyDisplayName = resource.assemblyLocation; } break; case DisplayResourceManagerCache.AssemblyBindingStatus.FoundInGac: diff --git a/src/System.Management.Automation/utils/ResourceManagerCache.cs b/src/System.Management.Automation/utils/ResourceManagerCache.cs index 11c72b60b..cc9db9bae 100644 --- a/src/System.Management.Automation/utils/ResourceManagerCache.cs +++ b/src/System.Management.Automation/utils/ResourceManagerCache.cs @@ -177,8 +177,38 @@ namespace System.Management.Automation throw PSTraceSource.NewArgumentException("resourceId"); } - ResourceManager resourceManager = GetResourceManager(assembly, baseName); - string text = resourceManager.GetString(resourceId); + ResourceManager resourceManager = null; + string text = string.Empty; + + // For a non-existing resource defined by {assembly,baseName,resourceId} + // MissingManifestResourceException is thrown only at the time when resource retrieval method + // such as ResourceManager.GetString or ResourceManager.GetObject is called, + // not when you instantiate a ResourceManager object. + try + { + // try with original baseName first + // if it fails then try with alternative resource path format + resourceManager = GetResourceManager(assembly, baseName); + text = resourceManager.GetString(resourceId); + } + catch (MissingManifestResourceException) + { + const string resourcesSubstring = ".resources."; + int resourcesSubstringIndex = baseName.IndexOf(resourcesSubstring); + string newBaseName = string.Empty; + if (resourcesSubstringIndex != -1) + { + newBaseName = baseName.Substring(resourcesSubstringIndex + resourcesSubstring.Length); // e.g. "FileSystemProviderStrings" + } + else + { + newBaseName = string.Concat(assembly.GetName().Name, resourcesSubstring, baseName); // e.g. "System.Management.Automation.resources.FileSystemProviderStrings" + } + + resourceManager = GetResourceManager(assembly, newBaseName); + text = resourceManager.GetString(resourceId); + } + if (String.IsNullOrEmpty(text) && s_DFT_monitorFailingResourceLookup) { Diagnostics.Assert(false, diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Update-FormatData.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Update-FormatData.Tests.ps1 index 3e679a49b..3c54917f6 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Update-FormatData.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Update-FormatData.Tests.ps1 @@ -14,16 +14,16 @@ Describe "Update-FormatData" -Tags "CI" { } Context "Validate Update-FormatData update correctly" { - It "Should not throw upon reloading previous formatting file" { - { Update-FormatData } | Should Not throw - } + It "Should not throw upon reloading previous formatting file" { + { Update-FormatData } | Should Not throw + } - It "Should validly load formatting data" { - Get-FormatData -typename System.Diagnostics.Process | Export-FormatData -Path $path + It "Should validly load formatting data" { + Get-FormatData -typename System.Diagnostics.Process | Export-FormatData -Path $path $null = $ps.AddScript("Update-FormatData -prependPath $path") $ps.Invoke() $ps.HadErrors | Should be $false - } + } } } @@ -32,7 +32,7 @@ Describe "Update-FormatData basic functionality" -Tags "CI" { $testfilename = "testfile.ps1xml" $testfile = Join-Path -Path $TestDrive -ChildPath $testfilename - $xmlContent=@" + $xmlContent=@" AnyName @@ -48,12 +48,60 @@ Describe "Update-FormatData basic functionality" -Tags "CI" { "@ - $xmlContent > $testfile + $xmlContent > $testfile } - It "Update-FormatData with WhatIf should work"{ + It "Update-FormatData with WhatIf should work"{ { Update-FormatData -Append $testfile -WhatIf } | Should Not Throw { Update-FormatData -Prepend $testfile -WhatIf } | Should Not Throw - } + } +} + + +Describe "Update-FormatData with resources in CustomControls" -Tags "CI" { + + BeforeAll { + $templatePath = Join-Path $PSScriptRoot (Join-Path 'assets' 'UpdateFormatDataTests.format.ps1xml') + $formatFilePath = Join-Path $TestDrive 'UpdateFormatDataTests.format.ps1xml' + $ps = [powershell]::Create() + $iss = [system.management.automation.runspaces.initialsessionstate]::CreateDefault2() + $rs = [system.management.automation.runspaces.runspacefactory]::CreateRunspace($iss) + $rs.Open() + $ps.Runspace = $rs + } + AfterAll { + $rs.Close() + $ps.Dispose() + } + Context "Validate Update-FormatData" { + It "Resources in WindowsPS syntax should be loaded successfully" { + $format = Get-Content -Path $templatePath -Raw + $format.Replace("%BaseName%","FileSystemProviderStrings") | Set-Content -Path $formatFilePath -Force + $null = $ps.AddScript("Update-FormatData -PrependPath $formatFilePath") + $ps.Streams.Error.Clear() + $ps.Invoke() + $ps.Streams.Error | Should BeNullOrEmpty + + } + It "Resources in CorePS syntax should be loaded successfully" { + $format = Get-Content -Path $templatePath -Raw + $format.Replace("%BaseName%","System.Management.Automation.resources.FileSystemProviderStrings") | Set-Content -Path $formatFilePath -Force + $null = $ps.AddScript("Update-FormatData -PrependPath $formatFilePath") + $ps.Streams.Error.Clear() + $ps.Invoke() + $ps.Streams.Error | Should BeNullOrEmpty + } + It "Verify assembly path in error message when resource is Not found" { + $format = Get-Content -Path $templatePath -Raw + $format.Replace("%BaseName%","NonExistingResource") | Set-Content -Path $formatFilePath -Force + $null = $ps.AddScript("Update-FormatData -PrependPath $formatFilePath") + $ps.Streams.Error.Clear() + $ps.Invoke() + $sma = [appdomain]::CurrentDomain.GetAssemblies() | ? { if ($_.Location) {$_.Location.EndsWith("System.Management.Automation.dll")}} + $smaLocation = $sma.Location + $ps.Streams.Error | %{ $_.Exception.Message.Contains($smaLocation) | Should be $true } + $ps.Streams.Error | %{ $_.FullyQualifiedErrorId | Should Match 'FormatXmlUpdateException' } + } + } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/UpdateFormatDataTests.format.ps1xml b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/UpdateFormatDataTests.format.ps1xml new file mode 100644 index 000000000..8d4091035 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/UpdateFormatDataTests.format.ps1xml @@ -0,0 +1,31 @@ + + + + TestTypes + + NonExistingTestType + + + + + + + TestTypes-GroupingFormat + + + + + + 0 + + + + + + + + + + + +