diff --git a/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/TaskbarJumpList.cs b/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/TaskbarJumpList.cs index 7d03d0b836..e567cd69ee 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/TaskbarJumpList.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/TaskbarJumpList.cs @@ -4,13 +4,41 @@ using System; using System.Diagnostics; using System.Reflection; +using System.Threading; + using static Microsoft.PowerShell.ComInterfaces; namespace Microsoft.PowerShell { internal static class TaskbarJumpList { - internal static void CreateElevatedEntry(string title) + // Creating a JumpList entry takes around 55ms when the PowerShell process is interactive and + // owns the current window (otherwise it does a fast exit anyway). Since there is no 'GET' like API, + // we always have to execute this call because we do not know if it has been created yet. + // The JumpList does persist as long as the filepath of the executable does not change but there + // could be disruptions to it like e.g. the bi-annual Windows update, we decided to + // not over-optimize this and always create the JumpList as a non-blocking background STA thread instead. + internal static void CreateRunAsAdministratorJumpList() + { + // Some COM APIs are implicitly STA only, therefore the executing thread must run in STA. + var thread = new Thread(() => + { + try + { + TaskbarJumpList.CreateElevatedEntry(ConsoleHostStrings.RunAsAdministrator); + } + catch (Exception exception) + { + // Due to COM threading complexity there might still be sporadic failures but they can be + // ignored as creating the JumpList is not critical and persists after its first creation. + Debug.Fail($"Creating 'Run as Administrator' JumpList failed. {exception}"); + } + }); + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + } + + private static void CreateElevatedEntry(string title) { // Check startupInfo first to know if the current shell is interactive and owns a window before proceeding // This check is fast (less than 1ms) and allows for quick-exit diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index 9f25e69732..fcff864724 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -193,25 +193,7 @@ namespace Microsoft.PowerShell } #if !UNIX - // Creating a JumpList entry takes around 55ms when the PowerShell process is interactive and - // owns the current window (otherwise it does a fast exit anyway). Since there is no 'GET' like API, - // we always have to execute this call because we do not know if it has been created yet. - // The JumpList does persist as long as the filepath of the executable does not change but there - // could be disruptions to it like e.g. the bi-annual Windows update, we decided to - // not over-optimize this and always create the JumpList as a non-blocking background task instead. - Task.Run(() => - { - try - { - TaskbarJumpList.CreateElevatedEntry(ConsoleHostStrings.RunAsAdministrator); - } - catch - { - // Sporadic failures have been observed in some environments. Since the JumpList persists once it - // has been registered, there is no harm suppressing the occasional failure. - } - } - ); + TaskbarJumpList.CreateRunAsAdministratorJumpList(); #endif // First check for and handle PowerShell running in a server mode.