mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-04 10:16:24 +02:00
* Rename source generation context file * fix build issue * fix path bug --------- Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
313 lines
12 KiB
C#
313 lines
12 KiB
C#
// Copyright (c) Microsoft Corporation
|
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
|
// See the LICENSE file in the project root for more information.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Runtime.InteropServices;
|
|
|
|
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;
|
|
using Microsoft.PowerToys.Telemetry;
|
|
|
|
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|
{
|
|
public partial class CmdNotFoundViewModel : Observable
|
|
{
|
|
public ButtonClickCommand CheckRequirementsEventHandler => new ButtonClickCommand(CheckCommandNotFoundRequirements);
|
|
|
|
public ButtonClickCommand InstallPowerShell7EventHandler => new ButtonClickCommand(InstallPowerShell7);
|
|
|
|
public ButtonClickCommand InstallWinGetClientModuleEventHandler => new ButtonClickCommand(InstallWinGetClientModule);
|
|
|
|
public ButtonClickCommand InstallModuleEventHandler => new ButtonClickCommand(InstallModule);
|
|
|
|
public ButtonClickCommand UninstallModuleEventHandler => new ButtonClickCommand(UninstallModule);
|
|
|
|
private GpoRuleConfigured _enabledGpoRuleConfiguration;
|
|
private bool _moduleIsGpoEnabled;
|
|
private bool _moduleIsGpoDisabled;
|
|
|
|
public static string AssemblyDirectory
|
|
{
|
|
get
|
|
{
|
|
return Path.TrimEndingDirectorySeparator(AppContext.BaseDirectory);
|
|
}
|
|
}
|
|
|
|
public CmdNotFoundViewModel()
|
|
{
|
|
InitializeEnabledValue();
|
|
}
|
|
|
|
private void InitializeEnabledValue()
|
|
{
|
|
_enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredCmdNotFoundEnabledValue();
|
|
_moduleIsGpoEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
|
|
_moduleIsGpoDisabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled;
|
|
|
|
// 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);
|
|
|
|
CheckCommandNotFoundRequirements();
|
|
}
|
|
|
|
private string _commandOutputLog;
|
|
|
|
public string CommandOutputLog
|
|
{
|
|
get => _commandOutputLog;
|
|
set
|
|
{
|
|
if (_commandOutputLog != value)
|
|
{
|
|
_commandOutputLog = value;
|
|
OnPropertyChanged(nameof(CommandOutputLog));
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool _isPowerShell7Detected;
|
|
|
|
private bool isPowerShellPreviewDetected;
|
|
private string powerShellPreviewPath;
|
|
|
|
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 IsModuleGpoEnabled
|
|
{
|
|
get => _moduleIsGpoEnabled;
|
|
}
|
|
|
|
public bool IsModuleGpoDisabled
|
|
{
|
|
get => _moduleIsGpoDisabled;
|
|
}
|
|
|
|
public string RunPowerShellOrPreviewScript(string powershellExecutable, string powershellArguments, bool hidePowerShellWindow = false)
|
|
{
|
|
if (isPowerShellPreviewDetected)
|
|
{
|
|
return RunPowerShellScript(Path.Combine(powerShellPreviewPath, "pwsh-preview.cmd"), powershellArguments, hidePowerShellWindow);
|
|
}
|
|
else
|
|
{
|
|
return RunPowerShellScript(powershellExecutable, powershellArguments, hidePowerShellWindow);
|
|
}
|
|
}
|
|
|
|
public string RunPowerShellScript(string powershellExecutable, string powershellArguments, bool hidePowerShellWindow = false)
|
|
{
|
|
string outputLog = string.Empty;
|
|
try
|
|
{
|
|
var startInfo = new ProcessStartInfo()
|
|
{
|
|
FileName = powershellExecutable,
|
|
Arguments = powershellArguments,
|
|
CreateNoWindow = hidePowerShellWindow,
|
|
UseShellExecute = false,
|
|
RedirectStandardOutput = true,
|
|
};
|
|
startInfo.EnvironmentVariables["NO_COLOR"] = "1";
|
|
var process = Process.Start(startInfo);
|
|
while (!process.StandardOutput.EndOfStream)
|
|
{
|
|
outputLog += process.StandardOutput.ReadLine() + "\r\n"; // Weirdly, PowerShell 7 won't give us new lines.
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
outputLog = ex.ToString();
|
|
}
|
|
|
|
CommandOutputLog = outputLog;
|
|
return outputLog;
|
|
}
|
|
|
|
public void CheckCommandNotFoundRequirements()
|
|
{
|
|
isPowerShellPreviewDetected = false;
|
|
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 (!IsPowerShell7Detected)
|
|
{
|
|
// powerShell Preview might be installed, check it.
|
|
try
|
|
{
|
|
// we have to search for the directory where the PowerShell preview command is located. It is added to the PATH environment variable, so we have to search for it there
|
|
foreach (string pathCandidate in Environment.GetEnvironmentVariable("PATH").Split(';'))
|
|
{
|
|
if (File.Exists(Path.Combine(pathCandidate, "pwsh-preview.cmd")))
|
|
{
|
|
result = RunPowerShellScript(Path.Combine(pathCandidate, "pwsh-preview.cmd"), arguments, true);
|
|
if (result.Contains("PowerShell 7.4 or greater detected."))
|
|
{
|
|
isPowerShellPreviewDetected = true;
|
|
IsPowerShell7Detected = true;
|
|
powerShellPreviewPath = pathCandidate;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// nothing to do. No additional PowerShell installation found
|
|
}
|
|
}
|
|
|
|
if (result.Contains("WinGet Client module detected."))
|
|
{
|
|
IsWinGetClientModuleDetected = true;
|
|
}
|
|
else if (result.Contains("WinGet Client module not detected.") || result.Contains("WinGet Client module needs to be updated."))
|
|
{
|
|
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.") || result.Contains("Outdated version of Command Not Found module found 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 = RunPowerShellOrPreviewScript("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 = RunPowerShellOrPreviewScript("pwsh.exe", arguments);
|
|
if (result.Contains("WinGet Client module detected.") || result.Contains("WinGet Client module updated."))
|
|
{
|
|
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}\\..\"";
|
|
var result = RunPowerShellOrPreviewScript("pwsh.exe", arguments);
|
|
|
|
if (result.Contains("Module is already registered in the profile file.")
|
|
|| result.Contains("Module was successfully registered in the profile file.")
|
|
|| result.Contains("Module was successfully upgraded 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}\"";
|
|
var result = RunPowerShellOrPreviewScript("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);
|
|
}
|
|
}
|
|
}
|