From f4c3f792029da222f70d4538350b2eba399f55c9 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Tue, 28 Apr 2020 10:15:37 -0700 Subject: [PATCH] Prompt to update PackageManagement when using an old version (#1239) * prompt to update PackageManagement if it is older than 1.4.6 * rob's feedback --- .../Handlers/GetVersionHandler.cs | 94 ++++++++++++++++++- .../Workspace/LanguageServerSettings.cs | 3 + 2 files changed, 93 insertions(+), 4 deletions(-) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/GetVersionHandler.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/GetVersionHandler.cs index 551cdc144..e055380d1 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/GetVersionHandler.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/GetVersionHandler.cs @@ -4,23 +4,41 @@ // using System; +using System.Management.Automation; +using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Microsoft.PowerShell.EditorServices.Services; +using Microsoft.PowerShell.EditorServices.Services.PowerShellContext; using Microsoft.PowerShell.EditorServices.Utility; +using OmniSharp.Extensions.LanguageServer.Protocol.Models; +using OmniSharp.Extensions.LanguageServer.Protocol.Server; namespace Microsoft.PowerShell.EditorServices.Handlers { internal class GetVersionHandler : IGetVersionHandler { + private static readonly Version s_desiredPackageManagementVersion = new Version(1, 4, 6); + private readonly ILogger _logger; + private readonly PowerShellContextService _powerShellContextService; + private readonly ILanguageServer _languageServer; + private readonly ConfigurationService _configurationService; - public GetVersionHandler(ILoggerFactory factory) + public GetVersionHandler( + ILoggerFactory factory, + PowerShellContextService powerShellContextService, + ILanguageServer languageServer, + ConfigurationService configurationService) { _logger = factory.CreateLogger(); + _powerShellContextService = powerShellContextService; + _languageServer = languageServer; + _configurationService = configurationService; } - public Task Handle(GetVersionParams request, CancellationToken cancellationToken) + public async Task Handle(GetVersionParams request, CancellationToken cancellationToken) { var architecture = PowerShellProcessArchitecture.Unknown; // This should be changed to using a .NET call sometime in the future... but it's just for logging purposes. @@ -37,13 +55,18 @@ public Task Handle(GetVersionParams request, CancellationToke } } - return Task.FromResult(new PowerShellVersion + if (VersionUtils.IsPS5 && _configurationService.CurrentSettings.PromptToUpdatePackageManagement) + { + await CheckPackageManagement().ConfigureAwait(false); + } + + return new PowerShellVersion { Version = VersionUtils.PSVersionString, Edition = VersionUtils.PSEdition, DisplayVersion = VersionUtils.PSVersion.ToString(2), Architecture = architecture.ToString() - }); + }; } private enum PowerShellProcessArchitecture @@ -52,5 +75,68 @@ private enum PowerShellProcessArchitecture X86, X64 } + + private async Task CheckPackageManagement() + { + PSCommand getModule = new PSCommand().AddCommand("Get-Module").AddParameter("ListAvailable").AddParameter("Name", "PackageManagement"); + foreach (PSModuleInfo module in await _powerShellContextService.ExecuteCommandAsync(getModule)) + { + // The user has a good enough version of PackageManagement + if(module.Version >= s_desiredPackageManagementVersion) + { + break; + } + + _logger.LogDebug("Old version of PackageManagement detected. Attempting to update."); + + var takeActionText = "Yes"; + MessageActionItem messageAction = await _languageServer.Window.ShowMessage(new ShowMessageRequestParams + { + Message = "You have an older version of PackageManagement known to cause issues with the PowerShell extension. Would you like to update PackageManagement (You will need to restart the PowerShell extension after)?", + Type = MessageType.Warning, + Actions = new [] + { + new MessageActionItem + { + Title = takeActionText + }, + new MessageActionItem + { + Title = "Not now" + } + } + }); + + // If the user chose "Not now" ignore it for the rest of the session. + if (messageAction?.Title == takeActionText) + { + StringBuilder errors = new StringBuilder(); + await _powerShellContextService.ExecuteScriptStringAsync( + "powershell.exe -NoLogo -NoProfile -Command 'Install-Module -Name PackageManagement -Force -MinimumVersion 1.4.6 -Scope CurrentUser -AllowClobber'", + errors, + writeInputToHost: true, + writeOutputToHost: true, + addToHistory: true).ConfigureAwait(false); + + if (errors.Length == 0) + { + _languageServer.Window.ShowMessage(new ShowMessageParams + { + Type = MessageType.Info, + Message = "PackageManagement updated, If you already had PackageManagement loaded in your session, please restart the PowerShell extension." + }); + } + else + { + // There were errors installing PackageManagement. + _languageServer.Window.ShowMessage(new ShowMessageParams + { + Type = MessageType.Error, + Message = "PackageManagement update failed. Please run the following command in a new Windows PowerShell session and then restart the PowerShell extension: `Install-Module PackageManagement -Force -AllowClobber -MinimumVersion 1.4.6`" + }); + } + } + } + } } } diff --git a/src/PowerShellEditorServices/Services/Workspace/LanguageServerSettings.cs b/src/PowerShellEditorServices/Services/Workspace/LanguageServerSettings.cs index 14776c6e1..e2c9dab70 100644 --- a/src/PowerShellEditorServices/Services/Workspace/LanguageServerSettings.cs +++ b/src/PowerShellEditorServices/Services/Workspace/LanguageServerSettings.cs @@ -20,6 +20,8 @@ internal class LanguageServerSettings private readonly object updateLock = new object(); public bool EnableProfileLoading { get; set; } + public bool PromptToUpdatePackageManagement { get; set; } + public ScriptAnalysisSettings ScriptAnalysis { get; set; } public CodeFormattingSettings CodeFormatting { get; set; } @@ -46,6 +48,7 @@ public void Update( lock (updateLock) { this.EnableProfileLoading = settings.EnableProfileLoading; + this.PromptToUpdatePackageManagement = settings.PromptToUpdatePackageManagement; this.ScriptAnalysis.Update( settings.ScriptAnalysis, workspaceRootPath,