Introduce Command Not Found module (#26319)

* Introduce Command Not Found module

* rewrite module to depend on WinGet PowerShell module

* address Dongbo's feedback

* try and implement settings UI

* fix SUI build; try and store PowerShell object

* add and use object pool

* apply Dongbo's feedback

* add warm up; implement IPooledObjectPolicy

* Add module interface

* WIP trying to import module from settings

* Add EnableModule.ps1

* spellcheck

* spellcheck again

* Installer. Add DisableModule.ps1

* Fix styling

* Give the user some output from installing

* Prettify the Settings controls

* Add button to check PowerShell 7's version

* Fix Settings Assets paths

* Fix PowerShell 7 output

* Make module enable and disable scripts give better information

* Fix spellcheck

* Fix image files and placeholders

* Don't remove CmdNotFound on upgrade and don't fail on uninstall of
CmdNotFound

* Consistent install module scripts location on debug and installed

* installer: Avoid messageboxes and hide powershell on uninstalling CmdNotFound

* Fix psd1 file resolution when installed

* Fix spellcheck

* Add telemetry events

* Fix gpo files

* If GPO is set, enable/disable module on PT start depending on gpo value

* Cleanup module interface

* Cleanup settings code

* If GPO is set, disable Settings page logic

* Adding icons

* Update settings UI and strings

* Add telemetry for suggestions and feedbacks

* Fix sln file

* Fix build

* minor fixes

* Updating icon

* Remove global.json

* Remove unused PowerShell dependency

* Don't use preview version of Automation and fix NOTICE

* Fix signing

* Fix NOTICE.md

* Fix version checking for getfilesiginforedist.dll

* Fix spellchecker

* Fix README.md

* Fix false positives section in expect.txt

* Add logs to module interface

---------

Co-authored-by: Stefan Markovic <stefan@janeasystems.com>
Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
This commit is contained in:
Carlos Zamora
2024-01-03 07:43:42 -08:00
committed by GitHub
parent 3b90f73bd0
commit 46f5316858
65 changed files with 1633 additions and 63 deletions

View File

@@ -0,0 +1,123 @@
// 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.Diagnostics;
using System.IO;
using System.Reflection;
using global::PowerToys.GPOWrapper;
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 class CmdNotFoundViewModel : Observable
{
public ButtonClickCommand CheckPowershellVersionEventHandler => new ButtonClickCommand(CheckPowershellVersion);
public ButtonClickCommand InstallModuleEventHandler => new ButtonClickCommand(InstallModule);
public ButtonClickCommand UninstallModuleEventHandler => new ButtonClickCommand(UninstallModule);
private GpoRuleConfigured _enabledGpoRuleConfiguration;
private bool _enabledStateIsGPOConfigured;
public static string AssemblyDirectory
{
get
{
string codeBase = Assembly.GetExecutingAssembly().Location;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path);
}
}
public CmdNotFoundViewModel()
{
InitializeEnabledValue();
}
private void InitializeEnabledValue()
{
_enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredCmdNotFoundEnabledValue();
if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
{
// Get the enabled state from GPO.
_enabledStateIsGPOConfigured = true;
}
}
private string _commandOutputLog;
public string CommandOutputLog
{
get => _commandOutputLog;
set
{
if (_commandOutputLog != value)
{
_commandOutputLog = value;
OnPropertyChanged(nameof(CommandOutputLog));
}
}
}
public bool IsEnabledGpoConfigured
{
get => _enabledStateIsGPOConfigured;
}
public void RunPowerShellScript(string powershellArguments)
{
string outputLog = string.Empty;
try
{
var startInfo = new ProcessStartInfo()
{
FileName = "pwsh.exe",
Arguments = powershellArguments,
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;
}
public void CheckPowershellVersion()
{
var arguments = $"-NoProfile -NonInteractive -Command $PSVersionTable";
RunPowerShellScript(arguments);
}
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());
}
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());
}
}
}