[CmdNotFound]Improve installation workflow (#30727)

* [CmdNotFound]Improve installation workflow

* Fix typo

* Fix XAML styling

* Update src/settings-ui/Settings.UI/SettingsXAML/Views/CmdNotFoundPage.xaml

Co-authored-by: Davide Giacometti <davide.giacometti@outlook.it>

* Update src/settings-ui/Settings.UI/SettingsXAML/Views/CmdNotFoundPage.xaml

Co-authored-by: Davide Giacometti <davide.giacometti@outlook.it>

* Update src/settings-ui/Settings.UI/SettingsXAML/Views/CmdNotFoundPage.xaml

Co-authored-by: Davide Giacometti <davide.giacometti@outlook.it>

* Update src/settings-ui/Settings.UI/SettingsXAML/Views/CmdNotFoundPage.xaml

Co-authored-by: Davide Giacometti <davide.giacometti@outlook.it>

* Update src/settings-ui/Settings.UI/SettingsXAML/Views/CmdNotFoundPage.xaml

Co-authored-by: Davide Giacometti <davide.giacometti@outlook.it>

* Update src/settings-ui/Settings.UI/SettingsXAML/Views/CmdNotFoundPage.xaml

Co-authored-by: Davide Giacometti <davide.giacometti@outlook.it>

* Don't create window for checking requirements

* Hide install/uninstall buttons for CmdNotFound module

* Also install winget before Powershell 7

* Better detect processor architecture

* Fix spellcheck

* [CMDNotFound] UX improvements (#30740)

* UI improvements

* Updated label

* Update CmdNotFoundPage.xaml

* Update CmdNotFoundPage.xaml

* Update CmdNotFoundPage.xaml

* Better version detection

* Add some logging

* Add missing package install that's a prerequisite for winget

* Remove unused AllExperiments include

* Fix Logger library include

* Update PATH Environment variable after installing PS

* Fix OOBE UI spacing

* Use Invoke-WebRequest to get the deps and then install them from local path

* Spellcheck

* TEMP -> TMP

* User path is supposed to come after machine path

---------

Co-authored-by: Davide Giacometti <davide.giacometti@outlook.it>
Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Stefan Markovic <stefan@janeasystems.com>
This commit is contained in:
Jaime Bernardo
2024-01-05 09:26:49 +00:00
committed by GitHub
parent 5f2d8216ad
commit a7907ff63a
12 changed files with 456 additions and 45 deletions

View File

@@ -7,6 +7,7 @@ using System.Diagnostics;
using System.IO;
using System.Reflection;
using global::PowerToys.GPOWrapper;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events;
using Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands;
@@ -16,7 +17,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
{
public class CmdNotFoundViewModel : Observable
{
public ButtonClickCommand CheckPowershellVersionEventHandler => new ButtonClickCommand(CheckPowershellVersion);
public ButtonClickCommand CheckRequirementsEventHandler => new ButtonClickCommand(CheckCommandNotFoundRequirements);
public ButtonClickCommand InstallPowerShell7EventHandler => new ButtonClickCommand(InstallPowerShell7);
public ButtonClickCommand InstallWinGetClientModuleEventHandler => new ButtonClickCommand(InstallWinGetClientModule);
public ButtonClickCommand InstallModuleEventHandler => new ButtonClickCommand(InstallModule);
@@ -49,6 +54,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
// Get the enabled state from GPO.
_enabledStateIsGPOConfigured = true;
}
CheckCommandNotFoundRequirements();
}
private string _commandOutputLog;
@@ -66,20 +73,66 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
}
}
private bool _isPowerShell7Detected;
public bool IsPowerShell7Detected
{
get => _isPowerShell7Detected;
set
{
if (_isPowerShell7Detected != value)
{
_isPowerShell7Detected = value;
OnPropertyChanged(nameof(IsPowerShell7Detected));
}
}
}
private bool _isWinGetClientModuleDetected;
public bool IsWinGetClientModuleDetected
{
get => _isWinGetClientModuleDetected;
set
{
if (_isWinGetClientModuleDetected != value)
{
_isWinGetClientModuleDetected = value;
OnPropertyChanged(nameof(IsWinGetClientModuleDetected));
}
}
}
private bool _isCommandNotFoundModuleInstalled;
public bool IsCommandNotFoundModuleInstalled
{
get => _isCommandNotFoundModuleInstalled;
set
{
if (_isCommandNotFoundModuleInstalled != value)
{
_isCommandNotFoundModuleInstalled = value;
OnPropertyChanged(nameof(IsCommandNotFoundModuleInstalled));
}
}
}
public bool IsEnabledGpoConfigured
{
get => _enabledStateIsGPOConfigured;
}
public void RunPowerShellScript(string powershellArguments)
public string RunPowerShellScript(string powershellExecutable, string powershellArguments, bool hidePowerShellWindow = false)
{
string outputLog = string.Empty;
try
{
var startInfo = new ProcessStartInfo()
{
FileName = "pwsh.exe",
FileName = powershellExecutable,
Arguments = powershellArguments,
CreateNoWindow = hidePowerShellWindow,
UseShellExecute = false,
RedirectStandardOutput = true,
};
@@ -96,28 +149,112 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
}
CommandOutputLog = outputLog;
return outputLog;
}
public void CheckPowershellVersion()
public void CheckCommandNotFoundRequirements()
{
var arguments = $"-NoProfile -NonInteractive -Command $PSVersionTable";
RunPowerShellScript(arguments);
var ps1File = AssemblyDirectory + "\\Assets\\Settings\\Scripts\\CheckCmdNotFoundRequirements.ps1";
var arguments = $"-NoProfile -NonInteractive -ExecutionPolicy Unrestricted -File \"{ps1File}\"";
var result = RunPowerShellScript("pwsh.exe", arguments, true);
if (result.Contains("PowerShell 7.4 or greater detected."))
{
IsPowerShell7Detected = true;
}
else if (result.Contains("PowerShell 7.4 or greater not detected."))
{
IsPowerShell7Detected = false;
}
else if (result.Contains("pwsh.exe"))
{
// Likely an error saying there was an error starting pwsh.exe, so we can assume Powershell 7 was not detected.
CommandOutputLog += "PowerShell 7.4 or greater not detected. Installation instructions can be found on https://learn.microsoft.com/powershell/scripting/install/installing-powershell-on-windows \r\n";
IsPowerShell7Detected = false;
}
if (result.Contains("WinGet Client module detected."))
{
IsWinGetClientModuleDetected = true;
}
else if (result.Contains("WinGet Client module not detected."))
{
IsWinGetClientModuleDetected = false;
}
if (result.Contains("Command Not Found module is registered in the profile file."))
{
IsCommandNotFoundModuleInstalled = true;
}
else if (result.Contains("Command Not Found module is not registered in the profile file."))
{
IsCommandNotFoundModuleInstalled = false;
}
Logger.LogInfo(result);
}
public void InstallPowerShell7()
{
var ps1File = AssemblyDirectory + "\\Assets\\Settings\\Scripts\\InstallPowerShell7.ps1";
var arguments = $"-NoProfile -ExecutionPolicy Unrestricted -File \"{ps1File}\"";
var result = RunPowerShellScript("powershell.exe", arguments);
if (result.Contains("Powershell 7 successfully installed."))
{
IsPowerShell7Detected = true;
}
Logger.LogInfo(result);
// Update PATH environment variable to get pwsh.exe on further calls.
Environment.SetEnvironmentVariable("PATH", (Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine) ?? string.Empty) + ";" + (Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.User) ?? string.Empty), EnvironmentVariableTarget.Process);
}
public void InstallWinGetClientModule()
{
var ps1File = AssemblyDirectory + "\\Assets\\Settings\\Scripts\\InstallWinGetClientModule.ps1";
var arguments = $"-NoProfile -ExecutionPolicy Unrestricted -File \"{ps1File}\"";
var result = RunPowerShellScript("pwsh.exe", arguments);
if (result.Contains("WinGet Client module detected."))
{
IsWinGetClientModuleDetected = true;
}
else if (result.Contains("WinGet Client module not detected."))
{
IsWinGetClientModuleDetected = false;
}
Logger.LogInfo(result);
}
public void InstallModule()
{
var ps1File = AssemblyDirectory + "\\Assets\\Settings\\Scripts\\EnableModule.ps1";
var arguments = $"-NoProfile -ExecutionPolicy Unrestricted -File \"{ps1File}\" -scriptPath \"{AssemblyDirectory}\\..\"";
RunPowerShellScript(arguments);
PowerToysTelemetry.Log.WriteEvent(new CmdNotFoundInstallEvent());
var result = RunPowerShellScript("pwsh.exe", arguments);
if (result.Contains("Module is already registered in the profile file.") || result.Contains("Module was successfully registered in the profile file."))
{
IsCommandNotFoundModuleInstalled = true;
PowerToysTelemetry.Log.WriteEvent(new CmdNotFoundInstallEvent());
}
Logger.LogInfo(result);
}
public void UninstallModule()
{
var ps1File = AssemblyDirectory + "\\Assets\\Settings\\Scripts\\DisableModule.ps1";
var arguments = $"-NoProfile -ExecutionPolicy Unrestricted -File \"{ps1File}\"";
RunPowerShellScript(arguments);
PowerToysTelemetry.Log.WriteEvent(new CmdNotFoundUninstallEvent());
var result = RunPowerShellScript("pwsh.exe", arguments);
if (result.Contains("Removed the Command Not Found reference from the profile file.") || result.Contains("No instance of Command Not Found was found in the profile file."))
{
IsCommandNotFoundModuleInstalled = false;
PowerToysTelemetry.Log.WriteEvent(new CmdNotFoundUninstallEvent());
}
Logger.LogInfo(result);
}
}
}
}