From 46f5316858b7c601d161c05b77102797540b3883 Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Wed, 3 Jan 2024 07:43:42 -0800 Subject: [PATCH] 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 Co-authored-by: Jaime Bernardo Co-authored-by: Niels Laute --- .github/actions/spell-check/expect.txt | 27 +-- .github/actions/spell-check/patterns.txt | 3 + .pipelines/ESRPSigning_core.json | 6 +- .pipelines/versionAndSignCheck.ps1 | 1 + Directory.Packages.props | 2 + NOTICE.md | 2 + PowerToys.sln | 33 +++ README.md | 16 +- doc/images/icons/Command Not Found.png | Bin 0 -> 24678 bytes installer/PowerToysSetup/CmdNotFound.wxs | 24 ++ installer/PowerToysSetup/Common.wxi | 1 + .../PowerToysSetup/PowerToysInstaller.wixproj | 23 +- installer/PowerToysSetup/Product.wxs | 19 +- installer/PowerToysSetup/Settings.wxs | 14 ++ .../CustomAction.cpp | 22 ++ .../CustomAction.def | 3 +- src/common/GPOWrapper/GPOWrapper.cpp | 4 + src/common/GPOWrapper/GPOWrapper.h | 1 + src/common/GPOWrapper/GPOWrapper.idl | 1 + src/common/GPOWrapperProjection/GPOWrapper.cs | 5 + src/common/ManagedCommon/ManagedCommon.csproj | 2 +- src/common/ManagedCommon/ModuleType.cs | 1 + src/common/logger/logger_settings.h | 2 + src/common/utils/gpo.h | 6 + src/gpo/assets/PowerToys.admx | 11 + src/gpo/assets/en-US/PowerToys.adml | 2 + .../CmdNotFound/CmdNotFound.csproj | 67 ++++++ src/modules/cmdNotFound/CmdNotFound/Init.cs | 57 +++++ .../PooledPowerShellObjectPolicy.cs | 34 +++ .../CmdNotFoundFeedbackProvidedEvent.cs | 16 ++ .../CmdNotFoundSuggestionProvidedEvent.cs | 16 ++ .../CmdNotFound/WinGetCommandNotFound.psd1 | 11 + .../WinGetCommandNotFoundFeedbackPredictor.cs | 206 ++++++++++++++++++ .../CmdNotFoundModuleInterface.rc | 108 +++++++++ .../CmdNotFoundModuleInterface.vcxproj | 107 +++++++++ ...CmdNotFoundModuleInterface.vcxproj.filters | 45 ++++ .../CmdNotFoundModuleInterface/dllmain.cpp | 161 ++++++++++++++ .../CmdNotFoundModuleInterface/pch.cpp | 5 + .../CmdNotFoundModuleInterface/pch.h | 16 ++ .../CmdNotFoundModuleInterface/resource.h | 21 ++ .../CmdNotFoundModuleInterface/trace.cpp | 30 +++ .../CmdNotFoundModuleInterface/trace.h | 11 + src/runner/main.cpp | 1 + .../CmdNotFoundSettings.cs | 42 ++++ .../Settings.UI.Library/EnabledModules.cs | 17 ++ .../Events/CmdNotFoundInstallEvent.cs | 16 ++ .../Events/CmdNotFoundUninstallEvent.cs | 16 ++ .../FluentIcons/FluentIconsCmdNotFound.png | Bin 0 -> 2009 bytes .../Assets/Settings/Modules/CmdNotFound.png | Bin 0 -> 21435 bytes .../Settings/Modules/OOBE/CmdNotFound.png | Bin 0 -> 22060 bytes .../Assets/Settings/Scripts/DisableModule.ps1 | 35 +++ .../Assets/Settings/Scripts/EnableModule.ps1 | 38 ++++ .../Settings.UI/Helpers/ModuleHelper.cs | 5 + .../OOBE/Enums/PowerToysModules.cs | 1 + .../Settings.UI/PowerToys.Settings.csproj | 37 ++-- .../Settings.UI/SettingsXAML/App.xaml.cs | 1 + .../OOBE/Views/OobeCmdNotFound.xaml | 32 +++ .../OOBE/Views/OobeCmdNotFound.xaml.cs | 45 ++++ .../OOBE/Views/OobeShellPage.xaml | 4 + .../OOBE/Views/OobeShellPage.xaml.cs | 6 + .../SettingsXAML/Views/CmdNotFoundPage.xaml | 60 +++++ .../Views/CmdNotFoundPage.xaml.cs | 21 ++ .../SettingsXAML/Views/ShellPage.xaml | 5 + .../Settings.UI/Strings/en-us/Resources.resw | 49 +++++ .../ViewModels/CmdNotFoundViewModel.cs | 123 +++++++++++ 65 files changed, 1633 insertions(+), 63 deletions(-) create mode 100644 doc/images/icons/Command Not Found.png create mode 100644 installer/PowerToysSetup/CmdNotFound.wxs create mode 100644 src/modules/cmdNotFound/CmdNotFound/CmdNotFound.csproj create mode 100644 src/modules/cmdNotFound/CmdNotFound/Init.cs create mode 100644 src/modules/cmdNotFound/CmdNotFound/PooledPowerShellObjectPolicy.cs create mode 100644 src/modules/cmdNotFound/CmdNotFound/Telemetry/CmdNotFoundFeedbackProvidedEvent.cs create mode 100644 src/modules/cmdNotFound/CmdNotFound/Telemetry/CmdNotFoundSuggestionProvidedEvent.cs create mode 100644 src/modules/cmdNotFound/CmdNotFound/WinGetCommandNotFound.psd1 create mode 100644 src/modules/cmdNotFound/CmdNotFound/WinGetCommandNotFoundFeedbackPredictor.cs create mode 100644 src/modules/cmdNotFound/CmdNotFoundModuleInterface/CmdNotFoundModuleInterface.rc create mode 100644 src/modules/cmdNotFound/CmdNotFoundModuleInterface/CmdNotFoundModuleInterface.vcxproj create mode 100644 src/modules/cmdNotFound/CmdNotFoundModuleInterface/CmdNotFoundModuleInterface.vcxproj.filters create mode 100644 src/modules/cmdNotFound/CmdNotFoundModuleInterface/dllmain.cpp create mode 100644 src/modules/cmdNotFound/CmdNotFoundModuleInterface/pch.cpp create mode 100644 src/modules/cmdNotFound/CmdNotFoundModuleInterface/pch.h create mode 100644 src/modules/cmdNotFound/CmdNotFoundModuleInterface/resource.h create mode 100644 src/modules/cmdNotFound/CmdNotFoundModuleInterface/trace.cpp create mode 100644 src/modules/cmdNotFound/CmdNotFoundModuleInterface/trace.h create mode 100644 src/settings-ui/Settings.UI.Library/CmdNotFoundSettings.cs create mode 100644 src/settings-ui/Settings.UI.Library/Telemetry/Events/CmdNotFoundInstallEvent.cs create mode 100644 src/settings-ui/Settings.UI.Library/Telemetry/Events/CmdNotFoundUninstallEvent.cs create mode 100644 src/settings-ui/Settings.UI/Assets/Settings/FluentIcons/FluentIconsCmdNotFound.png create mode 100644 src/settings-ui/Settings.UI/Assets/Settings/Modules/CmdNotFound.png create mode 100644 src/settings-ui/Settings.UI/Assets/Settings/Modules/OOBE/CmdNotFound.png create mode 100644 src/settings-ui/Settings.UI/Assets/Settings/Scripts/DisableModule.ps1 create mode 100644 src/settings-ui/Settings.UI/Assets/Settings/Scripts/EnableModule.ps1 create mode 100644 src/settings-ui/Settings.UI/SettingsXAML/OOBE/Views/OobeCmdNotFound.xaml create mode 100644 src/settings-ui/Settings.UI/SettingsXAML/OOBE/Views/OobeCmdNotFound.xaml.cs create mode 100644 src/settings-ui/Settings.UI/SettingsXAML/Views/CmdNotFoundPage.xaml create mode 100644 src/settings-ui/Settings.UI/SettingsXAML/Views/CmdNotFoundPage.xaml.cs create mode 100644 src/settings-ui/Settings.UI/ViewModels/CmdNotFoundViewModel.cs diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index a36b157274..2091f78ed3 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -161,7 +161,6 @@ CHANGECBCHAIN changecursor CHILDACTIVATE CHILDWINDOW -CHT cidl cim CImage @@ -182,6 +181,7 @@ clrcall CLSCTX Clusion cmder +CMDNOTFOUNDMODULEINTERFACE Cmds CMIC CMINVOKECOMMANDINFO @@ -219,7 +219,6 @@ CONFIGW CONFLICTINGMODIFIERKEY CONFLICTINGMODIFIERSHORTCUT CONOUT -constexpr consts contentdialog contentfiles @@ -319,7 +318,6 @@ DESKTOPABSOLUTEEDITING DESKTOPABSOLUTEPARSING desktopshorcutinstalled desktopwindowxamlsource -DEU devblogs devdocs devenum @@ -508,6 +506,7 @@ GETCLIENTAREAANIMATION GETDESKWALLPAPER GETDLGCODE GETDPISCALEDSIZE +getfilesiginforedist GETICON GETMINMAXINFO GETPROPERTYSTOREFLAGS @@ -538,7 +537,6 @@ Hanzi Hardlines hardlinks HARDWAREINPUT -hashcode Hashset hashtag HASHVAL @@ -557,7 +555,6 @@ hcwhite hdc hdrop hdwwiz -HEB Helpline helptext HGFE @@ -720,7 +717,6 @@ jif jjw jobject jpe -JPN jpnime Jsons jsonval @@ -746,10 +742,7 @@ killrunner Knownfolders KSPROPERTY Kybd -LAlt -Lambson languagesjson -langword lastcodeanalysissucceeded Lastdevice LAYOUTRTL @@ -907,6 +900,8 @@ MOUSEHWHEEL MOUSEINPUT MOVESIZEEND MOVESIZESTART +MOZILLAPL +MOZPL mpmc MRM MRT @@ -972,6 +967,7 @@ newdev newitem newpath newrow +newsgroups NIF NLD NLog @@ -984,7 +980,6 @@ NOCLOSEPROCESS NOCOALESCE NOCOPYBITS nodeca -nodiscard nodoc NODRAWCAPTION NODRAWICON @@ -1093,7 +1088,6 @@ pcch pcelt pch PCIDLIST -pcs PCWSTR pdisp pdo @@ -1304,7 +1298,6 @@ RKey RNumber roadmap rop -roundf ROUNDSMALL rpcrt RRF @@ -1320,12 +1313,11 @@ rundll rungameid RUNLEVEL runsettings +runspace runtimeclass runtimeobject runtimepack runtimes -RUS -RValue rvm rwin rwl @@ -1506,7 +1498,6 @@ subquery Superbar sut svchost -SVE SVGIn SVGIO svgz @@ -1579,7 +1570,6 @@ tlbimp TMPVAR TNP toggleswitch -tonos toolkitcontrols toolkitconverters Toolset @@ -1715,7 +1705,6 @@ wcsnicmp WDA wdp wdupenv -weakme webbrowsers webcam webpage @@ -1724,7 +1713,6 @@ wekyb Wevtapi wgpocpl WIC -wifi wil winapi winappdriver @@ -1852,9 +1840,6 @@ zonable zoneset Zoneszonabletester zzz -newsgroups -MOZILLAPL -MOZPL # FALSE POSITIVES diff --git a/.github/actions/spell-check/patterns.txt b/.github/actions/spell-check/patterns.txt index daf0220efe..d48cec9abd 100644 --- a/.github/actions/spell-check/patterns.txt +++ b/.github/actions/spell-check/patterns.txt @@ -118,6 +118,9 @@ aka\.ms/[a-zA-Z0-9]+ # YouTube url \b(?:(?:www\.|)youtube\.com|youtu.be)/(?:channel/|embed/|user/|playlist\?list=|watch\?v=|v/|)[-a-zA-Z0-9?&=_%]* +# power shell gallery website +\bpowershellgallery.com/[-_a-zA-Z0-9()=./%]* + # uuid: (or CompGUIDPrefix) L?(["']|[-<({>]|\b)[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{10,12}(?:\g{-1}|[<})>]) diff --git a/.pipelines/ESRPSigning_core.json b/.pipelines/ESRPSigning_core.json index 73bc45ed03..a6350ec764 100644 --- a/.pipelines/ESRPSigning_core.json +++ b/.pipelines/ESRPSigning_core.json @@ -28,7 +28,10 @@ "PowerToys.AlwaysOnTop.exe", "PowerToys.AlwaysOnTopModuleInterface.dll", - + + "PowerToys.CmdNotFoundModuleInterface.dll", + "PowerToys.CmdNotFound.dll", + "PowerToys.ColorPicker.dll", "PowerToys.ColorPickerUI.dll", "PowerToys.ColorPickerUI.exe", @@ -251,6 +254,7 @@ "Mages.Core.dll", "JetBrains.Annotations.dll", "NLog.Extensions.Logging.dll", + "getfilesiginforedist.dll", "concrt140_app.dll", "msvcp140_1_app.dll", "msvcp140_2_app.dll", diff --git a/.pipelines/versionAndSignCheck.ps1 b/.pipelines/versionAndSignCheck.ps1 index 42b66ed8bc..d5960efb64 100644 --- a/.pipelines/versionAndSignCheck.ps1 +++ b/.pipelines/versionAndSignCheck.ps1 @@ -24,6 +24,7 @@ $versionExceptions = @( $nullVersionExceptions = @( "codicon.ttf", "e_sqlite3.dll", + "getfilesiginforedist.dll", "vcamp140_app.dll", "vcruntime140_app.dll", "vcruntime140_1_app.dll", diff --git a/Directory.Packages.props b/Directory.Packages.props index cb36c3beaf..61ca429ea1 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -33,6 +33,7 @@ + @@ -66,6 +67,7 @@ + diff --git a/NOTICE.md b/NOTICE.md index 59adbebaed..47d5e68545 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -1321,6 +1321,7 @@ EXHIBIT A -Mozilla Public License. - Microsoft.Extensions.Hosting.WindowsServices 8.0.0 - Microsoft.Extensions.Logging 8.0.0 - Microsoft.Extensions.Logging.Abstractions 8.0.0 +- Microsoft.Extensions.ObjectPool 5.0.17 - Microsoft.NET.Test.Sdk 17.6.3 - Microsoft.Toolkit.Uwp.Notifications 7.1.2 - Microsoft.Web.WebView2 1.0.2088.41 @@ -1350,6 +1351,7 @@ EXHIBIT A -Mozilla Public License. - System.IO.Abstractions 17.2.3 - System.IO.Abstractions.TestingHelpers 17.2.3 - System.Management 8.0.0 +- System.Management.Automation 7.4.0 - System.Reactive 6.0.0-preview.9 - System.Runtime.Caching 8.0.0 - System.ServiceProcess.ServiceController 8.0.0 diff --git a/PowerToys.sln b/PowerToys.sln index c3a17c1804..6c37839b19 100644 --- a/PowerToys.sln +++ b/PowerToys.sln @@ -538,6 +538,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CropAndLock", "src\modules\ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CropAndLockModuleInterface", "src\modules\CropAndLock\CropAndLockModuleInterface\CropAndLockModuleInterface.vcxproj", "{3157FA75-86CF-4EE2-8F62-C43F776493C6}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CmdNotFound", "src\modules\cmdNotFound\CmdNotFound\CmdNotFound.csproj", "{A37865FE-2881-449F-8ADB-B8CD373D6D79}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "cmdNotFound", "cmdNotFound", "{4C0D0746-BE5B-49EE-BD5D-A7811628AE8B}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-FancyZonesEditor", "src\modules\fancyzones\UnitTests-FancyZonesEditor\UnitTests-FancyZonesEditor.csproj", "{FC8EB78F-F061-4BD9-A3F6-507BEA965E2B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EnvironmentVariables", "EnvironmentVariables", "{538ED0BB-B863-4B20-98CC-BCDF7FA0B68A}" @@ -558,6 +562,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-QoiPreviewHandler EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-QoiThumbnailProvider", "src\modules\previewpane\UnitTests-QoiThumbnailProvider\UnitTests-QoiThumbnailProvider.csproj", "{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdNotFoundModuleInterface", "src\modules\cmdNotFound\CmdNotFoundModuleInterface\CmdNotFoundModuleInterface.vcxproj", "{0014D652-901F-4456-8D65-06FC5F997FB0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 @@ -2328,6 +2334,18 @@ Global {3157FA75-86CF-4EE2-8F62-C43F776493C6}.Release|x64.Build.0 = Release|x64 {3157FA75-86CF-4EE2-8F62-C43F776493C6}.Release|x86.ActiveCfg = Release|x64 {3157FA75-86CF-4EE2-8F62-C43F776493C6}.Release|x86.Build.0 = Release|x64 + {A37865FE-2881-449F-8ADB-B8CD373D6D79}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {A37865FE-2881-449F-8ADB-B8CD373D6D79}.Debug|ARM64.Build.0 = Debug|ARM64 + {A37865FE-2881-449F-8ADB-B8CD373D6D79}.Debug|x64.ActiveCfg = Debug|x64 + {A37865FE-2881-449F-8ADB-B8CD373D6D79}.Debug|x64.Build.0 = Debug|x64 + {A37865FE-2881-449F-8ADB-B8CD373D6D79}.Debug|x86.ActiveCfg = Debug|x64 + {A37865FE-2881-449F-8ADB-B8CD373D6D79}.Debug|x86.Build.0 = Debug|x64 + {A37865FE-2881-449F-8ADB-B8CD373D6D79}.Release|ARM64.ActiveCfg = Release|ARM64 + {A37865FE-2881-449F-8ADB-B8CD373D6D79}.Release|ARM64.Build.0 = Release|ARM64 + {A37865FE-2881-449F-8ADB-B8CD373D6D79}.Release|x64.ActiveCfg = Release|x64 + {A37865FE-2881-449F-8ADB-B8CD373D6D79}.Release|x64.Build.0 = Release|x64 + {A37865FE-2881-449F-8ADB-B8CD373D6D79}.Release|x86.ActiveCfg = Release|x64 + {A37865FE-2881-449F-8ADB-B8CD373D6D79}.Release|x86.Build.0 = Release|x64 {FC8EB78F-F061-4BD9-A3F6-507BEA965E2B}.Debug|ARM64.ActiveCfg = Debug|ARM64 {FC8EB78F-F061-4BD9-A3F6-507BEA965E2B}.Debug|ARM64.Build.0 = Debug|ARM64 {FC8EB78F-F061-4BD9-A3F6-507BEA965E2B}.Debug|x64.ActiveCfg = Debug|x64 @@ -2436,6 +2454,18 @@ Global {F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}.Release|x64.Build.0 = Release|x64 {F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}.Release|x86.ActiveCfg = Release|x64 {F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}.Release|x86.Build.0 = Release|x64 + {0014D652-901F-4456-8D65-06FC5F997FB0}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {0014D652-901F-4456-8D65-06FC5F997FB0}.Debug|ARM64.Build.0 = Debug|ARM64 + {0014D652-901F-4456-8D65-06FC5F997FB0}.Debug|x64.ActiveCfg = Debug|x64 + {0014D652-901F-4456-8D65-06FC5F997FB0}.Debug|x64.Build.0 = Debug|x64 + {0014D652-901F-4456-8D65-06FC5F997FB0}.Debug|x86.ActiveCfg = Debug|Win32 + {0014D652-901F-4456-8D65-06FC5F997FB0}.Debug|x86.Build.0 = Debug|Win32 + {0014D652-901F-4456-8D65-06FC5F997FB0}.Release|ARM64.ActiveCfg = Release|ARM64 + {0014D652-901F-4456-8D65-06FC5F997FB0}.Release|ARM64.Build.0 = Release|ARM64 + {0014D652-901F-4456-8D65-06FC5F997FB0}.Release|x64.ActiveCfg = Release|x64 + {0014D652-901F-4456-8D65-06FC5F997FB0}.Release|x64.Build.0 = Release|x64 + {0014D652-901F-4456-8D65-06FC5F997FB0}.Release|x86.ActiveCfg = Release|Win32 + {0014D652-901F-4456-8D65-06FC5F997FB0}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2630,6 +2660,8 @@ Global {3B227528-4BA6-4CAF-B44A-A10C78A64849} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC} {F5E1146E-B7B3-4E11-85FD-270A500BD78C} = {3B227528-4BA6-4CAF-B44A-A10C78A64849} {3157FA75-86CF-4EE2-8F62-C43F776493C6} = {3B227528-4BA6-4CAF-B44A-A10C78A64849} + {A37865FE-2881-449F-8ADB-B8CD373D6D79} = {4C0D0746-BE5B-49EE-BD5D-A7811628AE8B} + {4C0D0746-BE5B-49EE-BD5D-A7811628AE8B} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC} {FC8EB78F-F061-4BD9-A3F6-507BEA965E2B} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD} {538ED0BB-B863-4B20-98CC-BCDF7FA0B68A} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC} {51465DA1-C18B-4B99-93E1-ECF8E0FA0CBA} = {538ED0BB-B863-4B20-98CC-BCDF7FA0B68A} @@ -2640,6 +2672,7 @@ Global {6B04803D-B418-4833-A67E-B0FC966636A5} = {2F305555-C296-497E-AC20-5FA1B237996A} {3940AD4D-F748-4BE4-9083-85769CD553EF} = {2F305555-C296-497E-AC20-5FA1B237996A} {F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38} = {2F305555-C296-497E-AC20-5FA1B237996A} + {0014D652-901F-4456-8D65-06FC5F997FB0} = {4C0D0746-BE5B-49EE-BD5D-A7811628AE8B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0} diff --git a/README.md b/README.md index 575abe4c54..110865b35c 100644 --- a/README.md +++ b/README.md @@ -17,14 +17,14 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline | | Current utilities: | | |--------------|--------------------|--------------| -| [Always on Top](https://aka.ms/PowerToysOverview_AoT) | [PowerToys Awake](https://aka.ms/PowerToysOverview_Awake) | [Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) | -| [Crop And Lock](https://aka.ms/PowerToysOverview_CropAndLock) | [Environment Variables](https://aka.ms/PowerToysOverview_EnvironmentVariables) | [FancyZones](https://aka.ms/PowerToysOverview_FancyZones) | -| [File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) | [File Locksmith](https://aka.ms/PowerToysOverview_FileLocksmith) | [Hosts File Editor](https://aka.ms/PowerToysOverview_HostsFileEditor) | -| [Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) | [Mouse utilities](https://aka.ms/PowerToysOverview_MouseUtilities) | -| [Mouse Without Borders](https://aka.ms/PowerToysOverview_MouseWithoutBorders) | [Peek](https://aka.ms/PowerToysOverview_Peek) | [Paste as Plain Text](https://aka.ms/PowerToysOverview_PastePlain) | -| [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) | [Quick Accent](https://aka.ms/PowerToysOverview_QuickAccent) | -| [Registry Preview](https://aka.ms/PowerToysOverview_RegistryPreview) | [Screen Ruler](https://aka.ms/PowerToysOverview_ScreenRuler) | [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) | -| [Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [Video Conference Mute](https://aka.ms/PowerToysOverview_VideoConference) | +| [Always on Top](https://aka.ms/PowerToysOverview_AoT) | [PowerToys Awake](https://aka.ms/PowerToysOverview_Awake) | [Command Not Found](https://aka.ms/PowerToysOverview_CmdNotFound) | +| [Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) | [Crop And Lock](https://aka.ms/PowerToysOverview_CropAndLock) | [Environment Variables](https://aka.ms/PowerToysOverview_EnvironmentVariables) | +| [FancyZones](https://aka.ms/PowerToysOverview_FancyZones) | [File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) | [File Locksmith](https://aka.ms/PowerToysOverview_FileLocksmith) | +| [Hosts File Editor](https://aka.ms/PowerToysOverview_HostsFileEditor) | [Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) | +| [Mouse utilities](https://aka.ms/PowerToysOverview_MouseUtilities) | [Mouse Without Borders](https://aka.ms/PowerToysOverview_MouseWithoutBorders) | [Peek](https://aka.ms/PowerToysOverview_Peek) | +| [Paste as Plain Text](https://aka.ms/PowerToysOverview_PastePlain) | [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) | +| [Quick Accent](https://aka.ms/PowerToysOverview_QuickAccent) | [Registry Preview](https://aka.ms/PowerToysOverview_RegistryPreview) | [Screen Ruler](https://aka.ms/PowerToysOverview_ScreenRuler) | +| [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) | [Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [Video Conference Mute](https://aka.ms/PowerToysOverview_VideoConference) | ## Installing and running Microsoft PowerToys diff --git a/doc/images/icons/Command Not Found.png b/doc/images/icons/Command Not Found.png new file mode 100644 index 0000000000000000000000000000000000000000..8243b9f8c8eb7d7751785665ed3cb8cbc207a032 GIT binary patch literal 24678 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%0A}AGp|?ShzXY1k*DEM${w0Ry>xr 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 H<`Mq`xBUcK literal 0 HcmV?d00001 diff --git a/installer/PowerToysSetup/CmdNotFound.wxs b/installer/PowerToysSetup/CmdNotFound.wxs new file mode 100644 index 0000000000..3ac8445d88 --- /dev/null +++ b/installer/PowerToysSetup/CmdNotFound.wxs @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/installer/PowerToysSetup/Common.wxi b/installer/PowerToysSetup/Common.wxi index 4a1c93fc8e..6e68ce1986 100644 --- a/installer/PowerToysSetup/Common.wxi +++ b/installer/PowerToysSetup/Common.wxi @@ -18,6 +18,7 @@ + diff --git a/installer/PowerToysSetup/PowerToysInstaller.wixproj b/installer/PowerToysSetup/PowerToysInstaller.wixproj index 6a4f3b80cb..8fb186ebb6 100644 --- a/installer/PowerToysSetup/PowerToysInstaller.wixproj +++ b/installer/PowerToysSetup/PowerToysInstaller.wixproj @@ -1,5 +1,6 @@ - + @@ -14,7 +15,7 @@ SET PTRoot=$(SolutionDir)\.. call "..\..\..\publish.cmd" x64 ) call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateMonacoWxs.ps1 -monacoWxsFile "$(MSBuildThisFileDirectory)\MonacoSRC.wxs" - + @@ -25,7 +26,7 @@ SET PTRoot=$(SolutionDir)\.. call "..\..\..\publish.cmd" arm64 ) call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateMonacoWxs.ps1 -monacoWxsFile "$(MSBuildThisFileDirectory)\MonacoSRC.wxs" - + Always @@ -67,7 +68,7 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil - Release + Release $(Platform) 3.10 022a9d30-7c4f-416d-a9df-5ff2661cc0ad @@ -103,6 +104,7 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil + @@ -180,17 +182,6 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil --> - + \ No newline at end of file diff --git a/installer/PowerToysSetup/Product.wxs b/installer/PowerToysSetup/Product.wxs index 2dea1fab55..ee15ec090a 100644 --- a/installer/PowerToysSetup/Product.wxs +++ b/installer/PowerToysSetup/Product.wxs @@ -72,6 +72,7 @@ + @@ -133,6 +134,7 @@ + @@ -159,6 +161,9 @@ Installed AND (REMOVE="ALL") + + Installed AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL") + Installed AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL") @@ -200,6 +205,10 @@ Property="UnApplyModulesRegistryChangeSets" Value="[INSTALLFOLDER]" /> + + @@ -252,7 +261,15 @@ BinaryKey="PTCustomActions" DllEntry="UninstallServicesCA" /> - + + + + + @@ -45,6 +47,16 @@ + + + + + + + + + + @@ -55,7 +67,9 @@ + + diff --git a/installer/PowerToysSetupCustomActions/CustomAction.cpp b/installer/PowerToysSetupCustomActions/CustomAction.cpp index c76e2203f8..290df09898 100644 --- a/installer/PowerToysSetupCustomActions/CustomAction.cpp +++ b/installer/PowerToysSetupCustomActions/CustomAction.cpp @@ -433,7 +433,29 @@ UINT __stdcall RemoveWindowsServiceByName(std::wstring serviceName) return ERROR_SUCCESS; } +UINT __stdcall UninstallCommandNotFoundModuleCA(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + std::wstring installationFolder; + std::string command; + hr = WcaInitialize(hInstall, "UninstallCommandNotFoundModule"); + ExitOnFailure(hr, "Failed to initialize"); + + hr = getInstallFolder(hInstall, installationFolder); + ExitOnFailure(hr, "Failed to get installFolder."); + + command = "pwsh.exe"; + command += " "; + command += "-NoProfile -NonInteractive -NoLogo -WindowStyle Hidden -ExecutionPolicy Unrestricted -File \"" + winrt::to_string(installationFolder) + "\\WinUI3Apps\\Assets\\Settings\\Scripts\\DisableModule.ps1" + "\""; + + system(command.c_str()); + +LExit: + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} UINT __stdcall UninstallServicesCA(MSIHANDLE hInstall) { diff --git a/installer/PowerToysSetupCustomActions/CustomAction.def b/installer/PowerToysSetupCustomActions/CustomAction.def index 7c3c058d9c..6a503da797 100644 --- a/installer/PowerToysSetupCustomActions/CustomAction.def +++ b/installer/PowerToysSetupCustomActions/CustomAction.def @@ -22,4 +22,5 @@ EXPORTS UninstallVirtualCameraDriverCA UnRegisterContextMenuPackagesCA UninstallEmbeddedMSIXCA - UninstallServicesCA \ No newline at end of file + UninstallServicesCA + UninstallCommandNotFoundModuleCA \ No newline at end of file diff --git a/src/common/GPOWrapper/GPOWrapper.cpp b/src/common/GPOWrapper/GPOWrapper.cpp index 77d81e8516..c3177d60db 100644 --- a/src/common/GPOWrapper/GPOWrapper.cpp +++ b/src/common/GPOWrapper/GPOWrapper.cpp @@ -12,6 +12,10 @@ namespace winrt::PowerToys::GPOWrapper::implementation { return static_cast(powertoys_gpo::getConfiguredAwakeEnabledValue()); } + GpoRuleConfigured GPOWrapper::GetConfiguredCmdNotFoundEnabledValue() + { + return static_cast(powertoys_gpo::getConfiguredCmdNotFoundEnabledValue()); + } GpoRuleConfigured GPOWrapper::GetConfiguredColorPickerEnabledValue() { return static_cast(powertoys_gpo::getConfiguredColorPickerEnabledValue()); diff --git a/src/common/GPOWrapper/GPOWrapper.h b/src/common/GPOWrapper/GPOWrapper.h index c29fac95b6..bd153ed258 100644 --- a/src/common/GPOWrapper/GPOWrapper.h +++ b/src/common/GPOWrapper/GPOWrapper.h @@ -9,6 +9,7 @@ namespace winrt::PowerToys::GPOWrapper::implementation GPOWrapper() = default; static GpoRuleConfigured GetConfiguredAlwaysOnTopEnabledValue(); static GpoRuleConfigured GetConfiguredAwakeEnabledValue(); + static GpoRuleConfigured GetConfiguredCmdNotFoundEnabledValue(); static GpoRuleConfigured GetConfiguredColorPickerEnabledValue(); static GpoRuleConfigured GetConfiguredCropAndLockEnabledValue(); static GpoRuleConfigured GetConfiguredFancyZonesEnabledValue(); diff --git a/src/common/GPOWrapper/GPOWrapper.idl b/src/common/GPOWrapper/GPOWrapper.idl index d0e3ebbd4f..3b4c0eca28 100644 --- a/src/common/GPOWrapper/GPOWrapper.idl +++ b/src/common/GPOWrapper/GPOWrapper.idl @@ -13,6 +13,7 @@ namespace PowerToys [default_interface] static runtimeclass GPOWrapper { static GpoRuleConfigured GetConfiguredAlwaysOnTopEnabledValue(); static GpoRuleConfigured GetConfiguredAwakeEnabledValue(); + static GpoRuleConfigured GetConfiguredCmdNotFoundEnabledValue(); static GpoRuleConfigured GetConfiguredColorPickerEnabledValue(); static GpoRuleConfigured GetConfiguredCropAndLockEnabledValue(); static GpoRuleConfigured GetConfiguredFancyZonesEnabledValue(); diff --git a/src/common/GPOWrapperProjection/GPOWrapper.cs b/src/common/GPOWrapperProjection/GPOWrapper.cs index 92196323e5..5e1ef14748 100644 --- a/src/common/GPOWrapperProjection/GPOWrapper.cs +++ b/src/common/GPOWrapperProjection/GPOWrapper.cs @@ -27,6 +27,11 @@ namespace PowerToys.GPOWrapperProjection return (GpoRuleConfigured)PowerToys.GPOWrapper.GPOWrapper.GetConfiguredFancyZonesEnabledValue(); } + public static GpoRuleConfigured GetConfiguredCmdNotFoundEnabledValue() + { + return (GpoRuleConfigured)PowerToys.GPOWrapper.GPOWrapper.GetConfiguredCmdNotFoundEnabledValue(); + } + public static GpoRuleConfigured GetConfiguredColorPickerEnabledValue() { return (GpoRuleConfigured)PowerToys.GPOWrapper.GPOWrapper.GetConfiguredColorPickerEnabledValue(); diff --git a/src/common/ManagedCommon/ManagedCommon.csproj b/src/common/ManagedCommon/ManagedCommon.csproj index 53ca704109..dbe6eca3f7 100644 --- a/src/common/ManagedCommon/ManagedCommon.csproj +++ b/src/common/ManagedCommon/ManagedCommon.csproj @@ -4,7 +4,7 @@ net8.0-windows - win-x64;win-arm64 + win-x64;win-arm64 $(Version).0 Microsoft Corporation PowerToys diff --git a/src/common/ManagedCommon/ModuleType.cs b/src/common/ManagedCommon/ModuleType.cs index 3a489711b0..0bbfaeeda3 100644 --- a/src/common/ManagedCommon/ModuleType.cs +++ b/src/common/ManagedCommon/ModuleType.cs @@ -9,6 +9,7 @@ namespace ManagedCommon AlwaysOnTop, Awake, ColorPicker, + CmdNotFound, CropAndLock, EnvironmentVariables, FancyZones, diff --git a/src/common/logger/logger_settings.h b/src/common/logger/logger_settings.h index 91dd5faae8..cc1b3825ce 100644 --- a/src/common/logger/logger_settings.h +++ b/src/common/logger/logger_settings.h @@ -67,6 +67,8 @@ struct LogSettings inline const static std::string cropAndLockLoggerName = "crop-and-lock"; inline const static std::wstring registryPreviewLogPath = L"Logs\\registryPreview-log.txt"; inline const static std::string environmentVariablesLoggerName = "environment-variables"; + inline const static std::wstring cmdNotFoundLogPath = L"Logs\\cmd-not-found-log.txt"; + inline const static std::string cmdNotFoundLoggerName = "cmd-not-found"; inline const static int retention = 30; std::wstring logLevel; LogSettings(); diff --git a/src/common/utils/gpo.h b/src/common/utils/gpo.h index be88e0d22d..016bd744cc 100644 --- a/src/common/utils/gpo.h +++ b/src/common/utils/gpo.h @@ -24,6 +24,7 @@ namespace powertoys_gpo { const std::wstring POLICY_CONFIGURE_ENABLED_GLOBAL_ALL_UTILITIES = L"ConfigureGlobalUtilityEnabledState"; const std::wstring POLICY_CONFIGURE_ENABLED_ALWAYS_ON_TOP = L"ConfigureEnabledUtilityAlwaysOnTop"; const std::wstring POLICY_CONFIGURE_ENABLED_AWAKE = L"ConfigureEnabledUtilityAwake"; + const std::wstring POLICY_CONFIGURE_ENABLED_CMD_NOT_FOUND = L"ConfigureEnabledUtilityCmdNotFound"; const std::wstring POLICY_CONFIGURE_ENABLED_COLOR_PICKER = L"ConfigureEnabledUtilityColorPicker"; const std::wstring POLICY_CONFIGURE_ENABLED_CROP_AND_LOCK = L"ConfigureEnabledUtilityCropAndLock"; const std::wstring POLICY_CONFIGURE_ENABLED_FANCYZONES = L"ConfigureEnabledUtilityFancyZones"; @@ -224,6 +225,11 @@ namespace powertoys_gpo { return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_AWAKE); } + inline gpo_rule_configured_t getConfiguredCmdNotFoundEnabledValue() + { + return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_CMD_NOT_FOUND); + } + inline gpo_rule_configured_t getConfiguredColorPickerEnabledValue() { return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_COLOR_PICKER); diff --git a/src/gpo/assets/PowerToys.admx b/src/gpo/assets/PowerToys.admx index 0b135f665e..59a0973dcf 100644 --- a/src/gpo/assets/PowerToys.admx +++ b/src/gpo/assets/PowerToys.admx @@ -15,6 +15,7 @@ + @@ -59,6 +60,16 @@ + + + + + + + + + + diff --git a/src/gpo/assets/en-US/PowerToys.adml b/src/gpo/assets/en-US/PowerToys.adml index de04d77c8b..2f69d63986 100644 --- a/src/gpo/assets/en-US/PowerToys.adml +++ b/src/gpo/assets/en-US/PowerToys.adml @@ -17,6 +17,7 @@ PowerToys version 0.73.0 or later PowerToys version 0.75.0 or later PowerToys version 0.76.0 or later + PowerToys version 0.77.0 or later This policy configures the enabled state for all PowerToys utilities. @@ -112,6 +113,7 @@ Note: Changes require a restart of PowerToys Run. Always On Top: Configure enabled state Awake: Configure enabled state Color Picker: Configure enabled state + Command Not Found: Configure enabled state Crop And Lock: Configure enabled state Environment Variables: Configure enabled state FancyZones: Configure enabled state diff --git a/src/modules/cmdNotFound/CmdNotFound/CmdNotFound.csproj b/src/modules/cmdNotFound/CmdNotFound/CmdNotFound.csproj new file mode 100644 index 0000000000..0d4f12d5b4 --- /dev/null +++ b/src/modules/cmdNotFound/CmdNotFound/CmdNotFound.csproj @@ -0,0 +1,67 @@ + + + + + net8.0-windows10.0.22621.0 + 10.0.19041.0 + 10.0.19041.0 + win-x64;win-arm64 + enable + Microsoft Corporation + PowerToys + enable + PowerToys CommandNotFound + PowerToys.CmdNotFound + false + true + ..\..\..\..\$(Platform)\$(Configuration) + false + false + true + true + + + + + win-x64 + + + win-arm64 + + + + DEBUG;TRACE + full + prompt + 4 + false + + + + TRACE;RELEASE + true + pdbonly + prompt + 4 + + + + + contentFiles + all + + + contentFiles + all + + + PreserveNewest + PreserveNewest + + + + + + + + diff --git a/src/modules/cmdNotFound/CmdNotFound/Init.cs b/src/modules/cmdNotFound/CmdNotFound/Init.cs new file mode 100644 index 0000000000..4d4ecb6d60 --- /dev/null +++ b/src/modules/cmdNotFound/CmdNotFound/Init.cs @@ -0,0 +1,57 @@ +// 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.Management.Automation; +using System.Management.Automation.Subsystem; +using System.Management.Automation.Subsystem.Feedback; +using System.Management.Automation.Subsystem.Prediction; + +namespace WinGetCommandNotFound +{ + public sealed class Init : IModuleAssemblyInitializer, IModuleAssemblyCleanup + { + internal const string Id = "e5351aa4-dfde-4d4d-bf0f-1a2f5a37d8d6"; + + public void OnImport() + { + if (!Platform.IsWindows || !IsWinGetInstalled()) + { + return; + } + + SubsystemManager.RegisterSubsystem(SubsystemKind.FeedbackProvider, WinGetCommandNotFoundFeedbackPredictor.Singleton); + SubsystemManager.RegisterSubsystem(SubsystemKind.CommandPredictor, WinGetCommandNotFoundFeedbackPredictor.Singleton); + } + + public void OnRemove(PSModuleInfo psModuleInfo) + { + if (!IsWinGetInstalled()) + { + return; + } + + SubsystemManager.UnregisterSubsystem(new Guid(Id)); + SubsystemManager.UnregisterSubsystem(new Guid(Id)); + } + + private bool IsWinGetInstalled() + { + // Ensure WinGet is installed + using (var pwsh = PowerShell.Create(RunspaceMode.CurrentRunspace)) + { + var results = pwsh.AddCommand("Get-Command") + .AddParameter("Name", "winget") + .AddParameter("CommandType", "Application") + .Invoke(); + + if (results.Count is 0) + { + return false; + } + } + + return true; + } + } +} diff --git a/src/modules/cmdNotFound/CmdNotFound/PooledPowerShellObjectPolicy.cs b/src/modules/cmdNotFound/CmdNotFound/PooledPowerShellObjectPolicy.cs new file mode 100644 index 0000000000..75d2ba8922 --- /dev/null +++ b/src/modules/cmdNotFound/CmdNotFound/PooledPowerShellObjectPolicy.cs @@ -0,0 +1,34 @@ +// 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.Management.Automation; +using System.Management.Automation.Runspaces; +using Microsoft.Extensions.ObjectPool; + +namespace WinGetCommandNotFound +{ + public sealed class PooledPowerShellObjectPolicy : IPooledObjectPolicy + { + private static readonly string[] WingetClientModuleName = new[] { "Microsoft.WinGet.Client" }; + + public PowerShell Create() + { + var iss = InitialSessionState.CreateDefault2(); + iss.ImportPSModule(WingetClientModuleName); + return PowerShell.Create(iss); + } + + public bool Return(PowerShell obj) + { + if (obj != null) + { + obj.Commands.Clear(); + obj.Streams.ClearStreams(); + return true; + } + + return false; + } + } +} diff --git a/src/modules/cmdNotFound/CmdNotFound/Telemetry/CmdNotFoundFeedbackProvidedEvent.cs b/src/modules/cmdNotFound/CmdNotFound/Telemetry/CmdNotFoundFeedbackProvidedEvent.cs new file mode 100644 index 0000000000..83563bbe35 --- /dev/null +++ b/src/modules/cmdNotFound/CmdNotFound/Telemetry/CmdNotFoundFeedbackProvidedEvent.cs @@ -0,0 +1,16 @@ +// 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.Diagnostics.Tracing; +using Microsoft.PowerToys.Telemetry; +using Microsoft.PowerToys.Telemetry.Events; + +namespace WinGetCommandNotFound.Telemetry +{ + [EventData] + public class CmdNotFoundFeedbackProvidedEvent : EventBase, IEvent + { + public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage; + } +} diff --git a/src/modules/cmdNotFound/CmdNotFound/Telemetry/CmdNotFoundSuggestionProvidedEvent.cs b/src/modules/cmdNotFound/CmdNotFound/Telemetry/CmdNotFoundSuggestionProvidedEvent.cs new file mode 100644 index 0000000000..2f55dbbb39 --- /dev/null +++ b/src/modules/cmdNotFound/CmdNotFound/Telemetry/CmdNotFoundSuggestionProvidedEvent.cs @@ -0,0 +1,16 @@ +// 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.Diagnostics.Tracing; +using Microsoft.PowerToys.Telemetry; +using Microsoft.PowerToys.Telemetry.Events; + +namespace WinGetCommandNotFound.Telemetry +{ + [EventData] + public class CmdNotFoundSuggestionProvidedEvent : EventBase, IEvent + { + public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage; + } +} diff --git a/src/modules/cmdNotFound/CmdNotFound/WinGetCommandNotFound.psd1 b/src/modules/cmdNotFound/CmdNotFound/WinGetCommandNotFound.psd1 new file mode 100644 index 0000000000..c7a1118eac --- /dev/null +++ b/src/modules/cmdNotFound/CmdNotFound/WinGetCommandNotFound.psd1 @@ -0,0 +1,11 @@ +@{ + ModuleVersion = '0.1.0' + GUID = '28c9afa2-92e5-413e-8e53-44b2d7a83ac6' + Author = 'Carlos Zamora' + CompanyName = "Microsoft Corporation" + Copyright = "Copyright (c) Microsoft Corporation." + Description = 'Enable suggestions on how to install missing commands via winget' + PowerShellVersion = '7.4' + NestedModules = @('PowerToys.CmdNotFound.dll') + RequiredModules = @(@{ModuleName = 'Microsoft.WinGet.Client'; ModuleVersion = "0.2.1"; }) +} diff --git a/src/modules/cmdNotFound/CmdNotFound/WinGetCommandNotFoundFeedbackPredictor.cs b/src/modules/cmdNotFound/CmdNotFound/WinGetCommandNotFoundFeedbackPredictor.cs new file mode 100644 index 0000000000..681b073bad --- /dev/null +++ b/src/modules/cmdNotFound/CmdNotFound/WinGetCommandNotFoundFeedbackPredictor.cs @@ -0,0 +1,206 @@ +// 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.Collections; +using System.Collections.ObjectModel; +using System.Globalization; +using System.Management.Automation; +using System.Management.Automation.Subsystem.Feedback; +using System.Management.Automation.Subsystem.Prediction; +using Microsoft.Extensions.ObjectPool; +using Microsoft.PowerToys.Telemetry; + +namespace WinGetCommandNotFound +{ + public sealed class WinGetCommandNotFoundFeedbackPredictor : IFeedbackProvider, ICommandPredictor + { + private readonly Guid _guid; + + private readonly ObjectPool _pool; + + private const int _maxSuggestions = 20; + + private List? _candidates; + + private bool _warmedUp; + + public static WinGetCommandNotFoundFeedbackPredictor Singleton { get; } = new WinGetCommandNotFoundFeedbackPredictor(Init.Id); + + private WinGetCommandNotFoundFeedbackPredictor(string guid) + { + _guid = new Guid(guid); + + var provider = new DefaultObjectPoolProvider(); + _pool = provider.Create(new PooledPowerShellObjectPolicy()); + _pool.Return(_pool.Get()); + Task.Run(() => WarmUp()); + } + + public Guid Id => _guid; + + public string Name => "Windows Package Manager - WinGet"; + + public string Description => "Finds missing commands that can be installed via WinGet."; + + public Dictionary? FunctionsToDefine => null; + + private void WarmUp() + { + var ps = _pool.Get(); + try + { + ps.AddCommand("Find-WinGetPackage") + .AddParameter("Count", 1) + .Invoke(); + } + finally + { + _pool.Return(ps); + _warmedUp = true; + } + } + + /// + /// Gets feedback based on the given commandline and error record. + /// + public FeedbackItem? GetFeedback(FeedbackContext context, CancellationToken token) + { + var target = (string)context.LastError!.TargetObject; + if (target is not null) + { + bool tooManySuggestions = false; + string packageMatchFilterField = "command"; + var pkgList = FindPackages(target, ref tooManySuggestions, ref packageMatchFilterField); + if (pkgList.Count == 0) + { + return null; + } + + // Build list of suggestions + _candidates = new List(); + foreach (var pkg in pkgList) + { + _candidates.Add(string.Format(CultureInfo.InvariantCulture, "winget install --id {0}", pkg.Members["Id"].Value.ToString())); + } + + // Build footer message + var footerMessage = tooManySuggestions ? + string.Format(CultureInfo.InvariantCulture, "Additional results can be found using \"winget search --{0} {1}\"", packageMatchFilterField, target) : + null; + + PowerToysTelemetry.Log.WriteEvent(new Telemetry.CmdNotFoundFeedbackProvidedEvent()); + + return new FeedbackItem( + "Try installing this package using winget:", + _candidates, + footerMessage, + FeedbackDisplayLayout.Portrait); + } + + return null; + } + + private Collection FindPackages(string query, ref bool tooManySuggestions, ref string packageMatchFilterField) + { + if (!_warmedUp) + { + return new Collection(); + } + + var ps = _pool.Get(); + try + { + var common = new Hashtable() + { + ["Source"] = "winget", + }; + + // 1) Search by command + var pkgList = ps.AddCommand("Find-WinGetPackage") + .AddParameter("Command", query) + .AddParameter("MatchOption", "StartsWithCaseInsensitive") + .AddParameters(common) + .Invoke(); + if (pkgList.Count > 0) + { + tooManySuggestions = pkgList.Count > _maxSuggestions; + packageMatchFilterField = "command"; + return pkgList; + } + + // 2) No matches found, + // search by name + ps.Commands.Clear(); + pkgList = ps.AddCommand("Find-WinGetPackage") + .AddParameter("Name", query) + .AddParameter("MatchOption", "ContainsCaseInsensitive") + .AddParameters(common) + .Invoke(); + if (pkgList.Count > 0) + { + tooManySuggestions = pkgList.Count > _maxSuggestions; + packageMatchFilterField = "name"; + return pkgList; + } + + // 3) No matches found, + // search by moniker + ps.Commands.Clear(); + pkgList = ps.AddCommand("Find-WinGetPackage") + .AddParameter("Moniker", query) + .AddParameter("MatchOption", "ContainsCaseInsensitive") + .AddParameters(common) + .Invoke(); + tooManySuggestions = pkgList.Count > _maxSuggestions; + packageMatchFilterField = "moniker"; + return pkgList; + } + finally + { + _pool.Return(ps); + } + } + + public bool CanAcceptFeedback(PredictionClient client, PredictorFeedbackKind feedback) + { + return feedback switch + { + PredictorFeedbackKind.CommandLineAccepted => true, + _ => false, + }; + } + + public SuggestionPackage GetSuggestion(PredictionClient client, PredictionContext context, CancellationToken cancellationToken) + { + if (_candidates is not null) + { + string input = context.InputAst.Extent.Text; + List? result = null; + + foreach (string c in _candidates) + { + if (c.StartsWith(input, StringComparison.OrdinalIgnoreCase)) + { + result ??= new List(_candidates.Count); + result.Add(new PredictiveSuggestion(c)); + } + } + + if (result is not null) + { + PowerToysTelemetry.Log.WriteEvent(new Telemetry.CmdNotFoundSuggestionProvidedEvent()); + return new SuggestionPackage(result); + } + } + + return default; + } + + public void OnCommandLineAccepted(PredictionClient client, IReadOnlyList history) + { + // Reset the candidate state. + _candidates = null; + } + } +} diff --git a/src/modules/cmdNotFound/CmdNotFoundModuleInterface/CmdNotFoundModuleInterface.rc b/src/modules/cmdNotFound/CmdNotFoundModuleInterface/CmdNotFoundModuleInterface.rc new file mode 100644 index 0000000000..e9ac022fc5 --- /dev/null +++ b/src/modules/cmdNotFound/CmdNotFoundModuleInterface/CmdNotFoundModuleInterface.rc @@ -0,0 +1,108 @@ +// Microsoft Visual C++ generated resource script. +// +#include +#include "resource.h" +#include "../../../common/version/version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +1 VERSIONINFO +FILEVERSION FILE_VERSION +PRODUCTVERSION PRODUCT_VERSION +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG +FILEFLAGS VS_FF_DEBUG +#else +FILEFLAGS 0x0L +#endif +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_DLL +FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset + BEGIN + VALUE "CompanyName", COMPANY_NAME + VALUE "FileDescription", FILE_DESCRIPTION + VALUE "FileVersion", FILE_VERSION_STRING + VALUE "InternalName", INTERNAL_NAME + VALUE "LegalCopyright", COPYRIGHT_NOTE + VALUE "OriginalFilename", ORIGINAL_FILENAME + VALUE "ProductName", PRODUCT_NAME + VALUE "ProductVersion", PRODUCT_VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset + END +END + + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_CMD_NOT_FOUND_NAME "Command Not Found" +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/modules/cmdNotFound/CmdNotFoundModuleInterface/CmdNotFoundModuleInterface.vcxproj b/src/modules/cmdNotFound/CmdNotFoundModuleInterface/CmdNotFoundModuleInterface.vcxproj new file mode 100644 index 0000000000..a7fd427c2a --- /dev/null +++ b/src/modules/cmdNotFound/CmdNotFoundModuleInterface/CmdNotFoundModuleInterface.vcxproj @@ -0,0 +1,107 @@ + + + + 17.0 + Win32Proj + {0014d652-901f-4456-8d65-06fc5f997fb0} + CmdNotFoundModuleInterface + PowerToys.CmdNotFoundModuleInterface + v143 + CmdNotFoundModuleInterface + + + + DynamicLibrary + true + Unicode + + + DynamicLibrary + false + true + Unicode + + + + + + + + + + + + ..\..\..\..\$(Platform)\$(Configuration)\ + + + + Level3 + true + WIN32;_DEBUG;CMDNOTFOUNDMODULEINTERFACE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + + + Windows + true + false + Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) + + + + + Level3 + true + true + true + WIN32;NDEBUG;CMDNOTFOUNDMODULEINTERFACE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + + + Windows + true + true + true + false + Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) + + + + + ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories) + + + + + + Header Files + + + + + + Source Files + + + + Create + + + + + {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd} + + + {6955446d-23f7-4023-9bb3-8657f904af99} + + + + + + + + + + \ No newline at end of file diff --git a/src/modules/cmdNotFound/CmdNotFoundModuleInterface/CmdNotFoundModuleInterface.vcxproj.filters b/src/modules/cmdNotFound/CmdNotFoundModuleInterface/CmdNotFoundModuleInterface.vcxproj.filters new file mode 100644 index 0000000000..1834d3ae88 --- /dev/null +++ b/src/modules/cmdNotFound/CmdNotFoundModuleInterface/CmdNotFoundModuleInterface.vcxproj.filters @@ -0,0 +1,45 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/src/modules/cmdNotFound/CmdNotFoundModuleInterface/dllmain.cpp b/src/modules/cmdNotFound/CmdNotFoundModuleInterface/dllmain.cpp new file mode 100644 index 0000000000..fed395d45d --- /dev/null +++ b/src/modules/cmdNotFound/CmdNotFoundModuleInterface/dllmain.cpp @@ -0,0 +1,161 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include "pch.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "resource.h" +#include "trace.h" + +BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*lpReserved*/) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + Trace::RegisterProvider(); + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + case DLL_PROCESS_DETACH: + Trace::UnregisterProvider(); + break; + } + return TRUE; +} + +const static wchar_t* MODULE_NAME = L"Command Not Found"; +const static wchar_t* MODULE_DESC = L"A module that detects an error thrown by a command in PowerShell and suggests a relevant WinGet package to install, if available."; + +inline const std::wstring ModuleKey = L"CmdNotFound"; + +class CmdNotFound : public PowertoyModuleIface +{ + std::wstring app_name; + std::wstring app_key; + +private: + bool m_enabled = false; + + void install_module() + { + auto module_path = get_module_folderpath(); + + std::string command = "pwsh.exe"; + command += " "; + command += "-NoProfile -NonInteractive -NoLogo -WindowStyle Hidden -ExecutionPolicy Unrestricted -File \"" + winrt::to_string(module_path) + "\\WinUI3Apps\\Assets\\Settings\\Scripts\\EnableModule.ps1" + "\"" + " -scriptPath \"" + winrt::to_string(module_path) + "\""; + + int ret = system(command.c_str()); + + if (ret != 0) + { + Logger::error("Running EnableModule.ps1 script failed."); + } + else + { + Logger::info("Module installed successfully."); + Trace::EnableCmdNotFoundGpo(true); + } + } + + void uninstall_module() + { + auto module_path = get_module_folderpath(); + + std::string command = "pwsh.exe"; + command += " "; + command += "-NoProfile -NonInteractive -NoLogo -WindowStyle Hidden -ExecutionPolicy Unrestricted -File \"" + winrt::to_string(module_path) + "\\WinUI3Apps\\Assets\\Settings\\Scripts\\DisableModule.ps1" + "\""; + + int ret = system(command.c_str()); + + if (ret != 0) + { + Logger::error("Running EnableModule.ps1 script failed."); + } + else + { + Logger::info("Module uninstalled successfully."); + Trace::EnableCmdNotFoundGpo(false); + } + } + +public: + CmdNotFound() + { + app_name = GET_RESOURCE_STRING(IDS_CMD_NOT_FOUND_NAME); + app_key = ModuleKey; + + std::filesystem::path logFilePath(PTSettingsHelper::get_module_save_folder_location(this->app_key)); + logFilePath.append(LogSettings::cmdNotFoundLogPath); + Logger::init(LogSettings::cmdNotFoundLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location()); + Logger::info("CmdNotFound object is constructing"); + + powertoys_gpo::gpo_rule_configured_t gpo_rule_configured_value = gpo_policy_enabled_configuration(); + if (gpo_rule_configured_value == powertoys_gpo::gpo_rule_configured_t::gpo_rule_configured_enabled) + { + install_module(); + m_enabled = true; + } + else if (gpo_rule_configured_value == powertoys_gpo::gpo_rule_configured_t::gpo_rule_configured_disabled) + { + uninstall_module(); + m_enabled = false; + } + } + + virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override + { + return powertoys_gpo::getConfiguredCmdNotFoundEnabledValue(); + } + + virtual void destroy() override + { + delete this; + } + + virtual const wchar_t* get_name() override + { + return MODULE_NAME; + } + + virtual const wchar_t* get_key() override + { + return app_key.c_str(); + } + + virtual bool get_config(wchar_t* /*buffer*/, int* /*buffer_size*/) override + { + return false; + } + + virtual void set_config(const wchar_t* config) override + { + } + + virtual void enable() + { + } + + virtual void disable() + { + } + + virtual bool is_enabled() override + { + return m_enabled; + } +}; + +extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create() +{ + return new CmdNotFound(); +} diff --git a/src/modules/cmdNotFound/CmdNotFoundModuleInterface/pch.cpp b/src/modules/cmdNotFound/CmdNotFoundModuleInterface/pch.cpp new file mode 100644 index 0000000000..64b7eef6d6 --- /dev/null +++ b/src/modules/cmdNotFound/CmdNotFoundModuleInterface/pch.cpp @@ -0,0 +1,5 @@ +// pch.cpp: source file corresponding to the pre-compiled header + +#include "pch.h" + +// When you are using pre-compiled headers, this source file is necessary for compilation to succeed. diff --git a/src/modules/cmdNotFound/CmdNotFoundModuleInterface/pch.h b/src/modules/cmdNotFound/CmdNotFoundModuleInterface/pch.h new file mode 100644 index 0000000000..96a774ab2a --- /dev/null +++ b/src/modules/cmdNotFound/CmdNotFoundModuleInterface/pch.h @@ -0,0 +1,16 @@ +// pch.h: This is a precompiled header file. +// Files listed below are compiled only once, improving build performance for future builds. +// This also affects IntelliSense performance, including code completion and many code browsing features. +// However, files listed here are ALL re-compiled if any one of them is updated between builds. +// Do not add files here that you will be updating frequently as this negates the performance advantage. + +#ifndef PCH_H +#define PCH_H + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files +#include + +#include + +#endif //PCH_H diff --git a/src/modules/cmdNotFound/CmdNotFoundModuleInterface/resource.h b/src/modules/cmdNotFound/CmdNotFoundModuleInterface/resource.h new file mode 100644 index 0000000000..9b16533a8a --- /dev/null +++ b/src/modules/cmdNotFound/CmdNotFoundModuleInterface/resource.h @@ -0,0 +1,21 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Awake.rc +// +#define IDS_CMD_NOT_FOUND_NAME 101 + + +#define FILE_DESCRIPTION "PowerToys Command Not Found" +#define INTERNAL_NAME "PowerToys.CmdNotFoundModuleInterface" +#define ORIGINAL_FILENAME "PowerToys.CmdNotFoundModuleInterface.dll" + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/modules/cmdNotFound/CmdNotFoundModuleInterface/trace.cpp b/src/modules/cmdNotFound/CmdNotFoundModuleInterface/trace.cpp new file mode 100644 index 0000000000..255c46ea99 --- /dev/null +++ b/src/modules/cmdNotFound/CmdNotFoundModuleInterface/trace.cpp @@ -0,0 +1,30 @@ +#include "pch.h" +#include "trace.h" + +TRACELOGGING_DEFINE_PROVIDER( + g_hProvider, + "Microsoft.PowerToys", + // {38e8889b-9731-53f5-e901-e8a7c1753074} + (0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74), + TraceLoggingOptionProjectTelemetry()); + +void Trace::RegisterProvider() +{ + TraceLoggingRegister(g_hProvider); +} + +void Trace::UnregisterProvider() +{ + TraceLoggingUnregister(g_hProvider); +} + +// Log if the user has CmdNotFound enabled or disabled +void Trace::EnableCmdNotFoundGpo(const bool enabled) noexcept +{ + TraceLoggingWrite( + g_hProvider, + "CmdNotFound_EnableCmdNotFound", + ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), + TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE), + TraceLoggingBoolean(enabled, "Enabled")); +} diff --git a/src/modules/cmdNotFound/CmdNotFoundModuleInterface/trace.h b/src/modules/cmdNotFound/CmdNotFoundModuleInterface/trace.h new file mode 100644 index 0000000000..4294c510a6 --- /dev/null +++ b/src/modules/cmdNotFound/CmdNotFoundModuleInterface/trace.h @@ -0,0 +1,11 @@ +#pragma once + +class Trace +{ +public: + static void RegisterProvider(); + static void UnregisterProvider(); + + // Log if the user has CmdNotFound enabled or disabled + static void EnableCmdNotFoundGpo(const bool enabled) noexcept; +}; diff --git a/src/runner/main.cpp b/src/runner/main.cpp index 59a455b379..a16197655e 100644 --- a/src/runner/main.cpp +++ b/src/runner/main.cpp @@ -158,6 +158,7 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow L"WinUI3Apps/PowerToys.EnvironmentVariablesModuleInterface.dll", L"PowerToys.MouseWithoutBordersModuleInterface.dll", L"PowerToys.CropAndLockModuleInterface.dll", + L"PowerToys.CmdNotFoundModuleInterface.dll", }; const auto VCM_PATH = L"PowerToys.VideoConferenceModule.dll"; if (const auto mf = LoadLibraryA("mf.dll")) diff --git a/src/settings-ui/Settings.UI.Library/CmdNotFoundSettings.cs b/src/settings-ui/Settings.UI.Library/CmdNotFoundSettings.cs new file mode 100644 index 0000000000..4353e5a188 --- /dev/null +++ b/src/settings-ui/Settings.UI.Library/CmdNotFoundSettings.cs @@ -0,0 +1,42 @@ +// 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.Text.Json; +using System.Text.Json.Serialization; +using Microsoft.PowerToys.Settings.UI.Library.Interfaces; + +namespace Microsoft.PowerToys.Settings.UI.Library +{ + public class CmdNotFoundSettings : BasePTModuleSettings, ISettingsConfig + { + private static readonly JsonSerializerOptions SerializerOptions = new() + { + WriteIndented = true, + }; + + public const string ModuleName = "CmdNotFound"; + + public CmdNotFoundSettings() + { + Version = "1"; + Name = ModuleName; + } + + public virtual void Save(ISettingsUtils settingsUtils) + { + // Save settings to file + ArgumentNullException.ThrowIfNull(settingsUtils); + + settingsUtils.SaveSettings(JsonSerializer.Serialize(this, SerializerOptions), ModuleName); + } + + public string GetModuleName() + => Name; + + // This can be utilized in the future if the settings.json file is to be modified/deleted. + public bool UpgradeSettingsConfiguration() + => false; + } +} diff --git a/src/settings-ui/Settings.UI.Library/EnabledModules.cs b/src/settings-ui/Settings.UI.Library/EnabledModules.cs index 27af49c4eb..a9ef81c1a8 100644 --- a/src/settings-ui/Settings.UI.Library/EnabledModules.cs +++ b/src/settings-ui/Settings.UI.Library/EnabledModules.cs @@ -427,6 +427,23 @@ namespace Microsoft.PowerToys.Settings.UI.Library } } + private bool cmdNotFound = true; + + [JsonPropertyName("CmdNotFound")] + public bool CmdNotFound + { + get => cmdNotFound; + set + { + if (cmdNotFound != value) + { + LogTelemetryEvent(value); + cmdNotFound = value; + NotifyChange(); + } + } + } + private bool environmentVariables = true; [JsonPropertyName("EnvironmentVariables")] diff --git a/src/settings-ui/Settings.UI.Library/Telemetry/Events/CmdNotFoundInstallEvent.cs b/src/settings-ui/Settings.UI.Library/Telemetry/Events/CmdNotFoundInstallEvent.cs new file mode 100644 index 0000000000..97d700a8e5 --- /dev/null +++ b/src/settings-ui/Settings.UI.Library/Telemetry/Events/CmdNotFoundInstallEvent.cs @@ -0,0 +1,16 @@ +// 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.Diagnostics.Tracing; +using Microsoft.PowerToys.Telemetry; +using Microsoft.PowerToys.Telemetry.Events; + +namespace Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events +{ + [EventData] + public class CmdNotFoundInstallEvent : EventBase, IEvent + { + public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage; + } +} diff --git a/src/settings-ui/Settings.UI.Library/Telemetry/Events/CmdNotFoundUninstallEvent.cs b/src/settings-ui/Settings.UI.Library/Telemetry/Events/CmdNotFoundUninstallEvent.cs new file mode 100644 index 0000000000..ae469903ee --- /dev/null +++ b/src/settings-ui/Settings.UI.Library/Telemetry/Events/CmdNotFoundUninstallEvent.cs @@ -0,0 +1,16 @@ +// 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.Diagnostics.Tracing; +using Microsoft.PowerToys.Telemetry; +using Microsoft.PowerToys.Telemetry.Events; + +namespace Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events +{ + [EventData] + public class CmdNotFoundUninstallEvent : EventBase, IEvent + { + public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage; + } +} diff --git a/src/settings-ui/Settings.UI/Assets/Settings/FluentIcons/FluentIconsCmdNotFound.png b/src/settings-ui/Settings.UI/Assets/Settings/FluentIcons/FluentIconsCmdNotFound.png new file mode 100644 index 0000000000000000000000000000000000000000..c4de6573a5683bf075aa7bf1e235ddf9823d1340 GIT binary patch literal 2009 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 literal 0 HcmV?d00001 diff --git a/src/settings-ui/Settings.UI/Assets/Settings/Scripts/DisableModule.ps1 b/src/settings-ui/Settings.UI/Assets/Settings/Scripts/DisableModule.ps1 new file mode 100644 index 0000000000..fef86f4935 --- /dev/null +++ b/src/settings-ui/Settings.UI/Assets/Settings/Scripts/DisableModule.ps1 @@ -0,0 +1,35 @@ +$profileContent = Get-Content $PROFILE + +$newContent = "" +$linesToDeleteFound = $False +$atLeastOneInstanceFound = $False + +$profileContent | ForEach-Object { + if ($_.Contains("34de4b3d-13a8-4540-b76d-b9e8d3851756") -and !$linesToDeleteFound) + { + $linesToDeleteFound = $True + $atLeastOneInstanceFound = $True + return + } + + if ($_.Contains("34de4b3d-13a8-4540-b76d-b9e8d3851756") -and $linesToDeleteFound) + { + $linesToDeleteFound = $False + return + } + + if($linesToDeleteFound) + { + return + } + + $newContent += $_ + "`r`n" +} + +if($atLeastOneInstanceFound) +{ + Set-Content -Path $PROFILE -Value $newContent + Write-Host "Removed the Command Not Found reference from the profile file." +} else { + Write-Host "No instance of Command Not Found was found in the profile file." +} diff --git a/src/settings-ui/Settings.UI/Assets/Settings/Scripts/EnableModule.ps1 b/src/settings-ui/Settings.UI/Assets/Settings/Scripts/EnableModule.ps1 new file mode 100644 index 0000000000..844613a2be --- /dev/null +++ b/src/settings-ui/Settings.UI/Assets/Settings/Scripts/EnableModule.ps1 @@ -0,0 +1,38 @@ +[CmdletBinding()] +Param( + [Parameter(Mandatory=$True,Position=1)] + [string]$scriptPath +) + +Write-Host "Enabling experimental feature: PSFeedbackProvider" +Enable-ExperimentalFeature PSFeedbackProvider +Write-Host "Enabling experimental feature: PSCommandNotFoundSuggestion" +Enable-ExperimentalFeature PSCommandNotFoundSuggestion + +if (Get-Module -ListAvailable -Name Microsoft.WinGet.Client) { + Write-Host "WinGet Client module detected" +} +else { + Write-Host "WinGet module was not found. Installation instructions can be found on https://www.powershellgallery.com/packages/Microsoft.WinGet.Client `r`n" +} + +if (!(Test-Path $PROFILE)) +{ + Write-Host "Profile file $PROFILE not found". + New-Item -Path $PROFILE -ItemType File + Write-Host "Created profile file $PROFILE". +} + +$profileContent = Get-Content -Path $PROFILE -Raw + +if ((-not [string]::IsNullOrEmpty($profileContent)) -and ($profileContent.Contains("34de4b3d-13a8-4540-b76d-b9e8d3851756"))) +{ + Write-Host "Module is already registered in the profile file." +} +else +{ + Add-Content -Path $PROFILE -Value "`r`n#34de4b3d-13a8-4540-b76d-b9e8d3851756 PowerToys CommandNotFound module" + Add-Content -Path $PROFILE -Value "`r`nImport-Module `"$scriptPath\WinGetCommandNotFound.psd1`"" + Add-Content -Path $PROFILE -Value "#34de4b3d-13a8-4540-b76d-b9e8d3851756" + Write-Host "Module was successfully registered in the profile file." +} diff --git a/src/settings-ui/Settings.UI/Helpers/ModuleHelper.cs b/src/settings-ui/Settings.UI/Helpers/ModuleHelper.cs index 25d5fb4f59..7daa62ae0d 100644 --- a/src/settings-ui/Settings.UI/Helpers/ModuleHelper.cs +++ b/src/settings-ui/Settings.UI/Helpers/ModuleHelper.cs @@ -44,6 +44,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers case ModuleType.AlwaysOnTop: return generalSettingsConfig.Enabled.AlwaysOnTop; case ModuleType.Awake: return generalSettingsConfig.Enabled.Awake; case ModuleType.ColorPicker: return generalSettingsConfig.Enabled.ColorPicker; + case ModuleType.CmdNotFound: return generalSettingsConfig.Enabled.CmdNotFound; case ModuleType.CropAndLock: return generalSettingsConfig.Enabled.CropAndLock; case ModuleType.EnvironmentVariables: return generalSettingsConfig.Enabled.EnvironmentVariables; case ModuleType.FancyZones: return generalSettingsConfig.Enabled.FancyZones; @@ -76,6 +77,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers case ModuleType.AlwaysOnTop: generalSettingsConfig.Enabled.AlwaysOnTop = isEnabled; break; case ModuleType.Awake: generalSettingsConfig.Enabled.Awake = isEnabled; break; case ModuleType.ColorPicker: generalSettingsConfig.Enabled.ColorPicker = isEnabled; break; + case ModuleType.CmdNotFound: generalSettingsConfig.Enabled.CmdNotFound = isEnabled; break; case ModuleType.CropAndLock: generalSettingsConfig.Enabled.CropAndLock = isEnabled; break; case ModuleType.EnvironmentVariables: generalSettingsConfig.Enabled.EnvironmentVariables = isEnabled; break; case ModuleType.FancyZones: generalSettingsConfig.Enabled.FancyZones = isEnabled; break; @@ -107,6 +109,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers case ModuleType.AlwaysOnTop: return GPOWrapper.GetConfiguredAlwaysOnTopEnabledValue(); case ModuleType.Awake: return GPOWrapper.GetConfiguredAwakeEnabledValue(); case ModuleType.ColorPicker: return GPOWrapper.GetConfiguredColorPickerEnabledValue(); + case ModuleType.CmdNotFound: return GPOWrapper.GetConfiguredCmdNotFoundEnabledValue(); case ModuleType.CropAndLock: return GPOWrapper.GetConfiguredCropAndLockEnabledValue(); case ModuleType.EnvironmentVariables: return GPOWrapper.GetConfiguredEnvironmentVariablesEnabledValue(); case ModuleType.FancyZones: return GPOWrapper.GetConfiguredFancyZonesEnabledValue(); @@ -139,6 +142,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers ModuleType.AlwaysOnTop => Color.FromArgb(255, 74, 196, 242), // #4ac4f2 ModuleType.Awake => Color.FromArgb(255, 40, 177, 233), // #28b1e9 ModuleType.ColorPicker => Color.FromArgb(255, 7, 129, 211), // #0781d3 + ModuleType.CmdNotFound => Color.FromArgb(255, 31, 164, 227), // #1fa4e3 ModuleType.CropAndLock => Color.FromArgb(255, 32, 166, 228), // #20a6e4 ModuleType.EnvironmentVariables => Color.FromArgb(255, 16, 132, 208), // #1084d0 ModuleType.FancyZones => Color.FromArgb(255, 65, 209, 247), // #41d1f7 @@ -171,6 +175,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers ModuleType.AlwaysOnTop => typeof(AlwaysOnTopPage), ModuleType.Awake => typeof(AwakePage), ModuleType.ColorPicker => typeof(ColorPickerPage), + ModuleType.CmdNotFound => typeof(CmdNotFoundPage), ModuleType.CropAndLock => typeof(CropAndLockPage), ModuleType.EnvironmentVariables => typeof(EnvironmentVariablesPage), ModuleType.FancyZones => typeof(FancyZonesPage), diff --git a/src/settings-ui/Settings.UI/OOBE/Enums/PowerToysModules.cs b/src/settings-ui/Settings.UI/OOBE/Enums/PowerToysModules.cs index 1a5091f5f4..111b0f669a 100644 --- a/src/settings-ui/Settings.UI/OOBE/Enums/PowerToysModules.cs +++ b/src/settings-ui/Settings.UI/OOBE/Enums/PowerToysModules.cs @@ -9,6 +9,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Enums Overview = 0, AlwaysOnTop, Awake, + CmdNotFound, ColorPicker, CropAndLock, EnvironmentVariables, diff --git a/src/settings-ui/Settings.UI/PowerToys.Settings.csproj b/src/settings-ui/Settings.UI/PowerToys.Settings.csproj index bffa7cc353..16c118872a 100644 --- a/src/settings-ui/Settings.UI/PowerToys.Settings.csproj +++ b/src/settings-ui/Settings.UI/PowerToys.Settings.csproj @@ -53,7 +53,7 @@ CA1720 true - + PowerToys.GPOWrapper @@ -61,10 +61,10 @@ false - - - https://pkgs.dev.azure.com/dotnet/CommunityToolkit/_packaging/CommunityToolkit-Labs/nuget/v3/index.json - + + + https://pkgs.dev.azure.com/dotnet/CommunityToolkit/_packaging/CommunityToolkit-Labs/nuget/v3/index.json + @@ -96,11 +96,11 @@ - + - + @@ -111,7 +111,7 @@ - + @@ -119,10 +119,19 @@ VSTHRD002;VSTHRD110;VSTHRD100;VSTHRD200;VSTHRD101 - - - Always - - - + + + Always + + + + + + Always + + + Always + + + diff --git a/src/settings-ui/Settings.UI/SettingsXAML/App.xaml.cs b/src/settings-ui/Settings.UI/SettingsXAML/App.xaml.cs index 46cd4d7e0e..9d3b030ef0 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/App.xaml.cs +++ b/src/settings-ui/Settings.UI/SettingsXAML/App.xaml.cs @@ -395,6 +395,7 @@ namespace Microsoft.PowerToys.Settings.UI case "Overview": return typeof(GeneralPage); case "AlwaysOnTop": return typeof(AlwaysOnTopPage); case "Awake": return typeof(AwakePage); + case "CmdNotFound": return typeof(CmdNotFoundPage); case "ColorPicker": return typeof(ColorPickerPage); case "FancyZones": return typeof(FancyZonesPage); case "FileLocksmith": return typeof(FileLocksmithPage); diff --git a/src/settings-ui/Settings.UI/SettingsXAML/OOBE/Views/OobeCmdNotFound.xaml b/src/settings-ui/Settings.UI/SettingsXAML/OOBE/Views/OobeCmdNotFound.xaml new file mode 100644 index 0000000000..d08cea71aa --- /dev/null +++ b/src/settings-ui/Settings.UI/SettingsXAML/OOBE/Views/OobeCmdNotFound.xaml @@ -0,0 +1,32 @@ + + + + + + + + + + + +