diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt
index 482d219ddbe..785ae7f40f0 100644
--- a/.github/actions/spell-check/expect.txt
+++ b/.github/actions/spell-check/expect.txt
@@ -197,6 +197,7 @@ CMock
CMONITORS
cmpgt
cne
+CNF
coclass
codeofconduct
codereview
diff --git a/Directory.Packages.props b/Directory.Packages.props
index b26458ba2de..00c6b8f96af 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -34,7 +34,6 @@
-
@@ -77,7 +76,6 @@
-
diff --git a/NOTICE.md b/NOTICE.md
index a3c40e7a65b..c62bee93f61 100644
--- a/NOTICE.md
+++ b/NOTICE.md
@@ -1323,7 +1323,6 @@ 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 8.0.0
- Microsoft.NET.Test.Sdk 17.8.0
- Microsoft.Toolkit.Uwp.Notifications 7.1.2
- Microsoft.Web.WebView2 1.0.2365.46
@@ -1358,7 +1357,6 @@ 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.Security.Cryptography.ProtectedData 8.0.0
diff --git a/PowerToys.sln b/PowerToys.sln
index 6fd164f0887..ce05c576ff6 100644
--- a/PowerToys.sln
+++ b/PowerToys.sln
@@ -538,8 +538,6 @@ 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}"
@@ -2357,18 +2355,6 @@ 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
@@ -2791,7 +2777,6 @@ 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}
diff --git a/installer/PowerToysSetup/CmdNotFound.wxs b/installer/PowerToysSetup/CmdNotFound.wxs
deleted file mode 100644
index 3ac8445d887..00000000000
--- a/installer/PowerToysSetup/CmdNotFound.wxs
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/installer/PowerToysSetup/Common.wxi b/installer/PowerToysSetup/Common.wxi
index 6e68ce19861..4a1c93fc8ea 100644
--- a/installer/PowerToysSetup/Common.wxi
+++ b/installer/PowerToysSetup/Common.wxi
@@ -18,7 +18,6 @@
-
diff --git a/installer/PowerToysSetup/PowerToysInstaller.wixproj b/installer/PowerToysSetup/PowerToysInstaller.wixproj
index 8fb186ebb64..926ba624dce 100644
--- a/installer/PowerToysSetup/PowerToysInstaller.wixproj
+++ b/installer/PowerToysSetup/PowerToysInstaller.wixproj
@@ -104,7 +104,6 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
-
diff --git a/installer/PowerToysSetup/Product.wxs b/installer/PowerToysSetup/Product.wxs
index e1e2fa8949e..1fe1c838d9b 100644
--- a/installer/PowerToysSetup/Product.wxs
+++ b/installer/PowerToysSetup/Product.wxs
@@ -72,7 +72,6 @@
-
@@ -135,6 +134,7 @@
+
@@ -164,6 +164,9 @@
Installed AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
+
+ WIX_UPGRADE_DETECTED
+
Installed AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
@@ -209,6 +212,10 @@
Property="UninstallCommandNotFound"
Value="[INSTALLFOLDER]" />
+
+
@@ -269,6 +276,14 @@
BinaryKey="PTCustomActions"
DllEntry="UninstallCommandNotFoundModuleCA"
/>
+
+
+
diff --git a/installer/PowerToysSetupCustomActions/CustomAction.cpp b/installer/PowerToysSetupCustomActions/CustomAction.cpp
index 8384d9ba7c8..7a79ab238d2 100644
--- a/installer/PowerToysSetupCustomActions/CustomAction.cpp
+++ b/installer/PowerToysSetupCustomActions/CustomAction.cpp
@@ -457,6 +457,30 @@ UINT __stdcall UninstallCommandNotFoundModuleCA(MSIHANDLE hInstall)
return WcaFinalize(er);
}
+UINT __stdcall UpgradeCommandNotFoundModuleCA(MSIHANDLE hInstall)
+{
+ HRESULT hr = S_OK;
+ UINT er = ERROR_SUCCESS;
+ std::wstring installationFolder;
+ std::string command;
+
+ hr = WcaInitialize(hInstall, "UpgradeCommandNotFoundModule");
+ 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\\UpgradeModule.ps1" + "\"";
+
+ system(command.c_str());
+
+LExit:
+ er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
+ return WcaFinalize(er);
+}
+
UINT __stdcall UninstallServicesCA(MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
diff --git a/installer/PowerToysSetupCustomActions/CustomAction.def b/installer/PowerToysSetupCustomActions/CustomAction.def
index 6a503da797c..7a4929935c3 100644
--- a/installer/PowerToysSetupCustomActions/CustomAction.def
+++ b/installer/PowerToysSetupCustomActions/CustomAction.def
@@ -23,4 +23,5 @@ EXPORTS
UnRegisterContextMenuPackagesCA
UninstallEmbeddedMSIXCA
UninstallServicesCA
- UninstallCommandNotFoundModuleCA
\ No newline at end of file
+ UninstallCommandNotFoundModuleCA
+ UpgradeCommandNotFoundModuleCA
\ No newline at end of file
diff --git a/src/modules/cmdNotFound/CmdNotFound/CmdNotFound.csproj b/src/modules/cmdNotFound/CmdNotFound/CmdNotFound.csproj
deleted file mode 100644
index 65e6a0436e4..00000000000
--- a/src/modules/cmdNotFound/CmdNotFound/CmdNotFound.csproj
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
- 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
- runtime; compile; build; native; analyzers; buildtransitive
-
-
- contentFiles
- all
-
-
- PreserveNewest
- PreserveNewest
-
-
-
-
-
-
-
-
-
diff --git a/src/modules/cmdNotFound/CmdNotFound/Init.cs b/src/modules/cmdNotFound/CmdNotFound/Init.cs
deleted file mode 100644
index 4d4ecb6d60c..00000000000
--- a/src/modules/cmdNotFound/CmdNotFound/Init.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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
deleted file mode 100644
index 75d2ba8922c..00000000000
--- a/src/modules/cmdNotFound/CmdNotFound/PooledPowerShellObjectPolicy.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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
deleted file mode 100644
index 83563bbe351..00000000000
--- a/src/modules/cmdNotFound/CmdNotFound/Telemetry/CmdNotFoundFeedbackProvidedEvent.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-// 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/CmdNotFoundFeedbackProvidedFailureEvent.cs b/src/modules/cmdNotFound/CmdNotFound/Telemetry/CmdNotFoundFeedbackProvidedFailureEvent.cs
deleted file mode 100644
index efa58bf4f14..00000000000
--- a/src/modules/cmdNotFound/CmdNotFound/Telemetry/CmdNotFoundFeedbackProvidedFailureEvent.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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 CmdNotFoundFeedbackProvidedFailureEvent : EventBase, IEvent
- {
- public string Message { get; set; } = string.Empty;
-
- public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
- }
-}
diff --git a/src/modules/cmdNotFound/CmdNotFound/Telemetry/CmdNotFoundInstanceCreatedEvent.cs b/src/modules/cmdNotFound/CmdNotFound/Telemetry/CmdNotFoundInstanceCreatedEvent.cs
deleted file mode 100644
index 0889f35f185..00000000000
--- a/src/modules/cmdNotFound/CmdNotFound/Telemetry/CmdNotFoundInstanceCreatedEvent.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-// 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 CmdNotFoundInstanceCreatedEvent : 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
deleted file mode 100644
index 2f55dbbb390..00000000000
--- a/src/modules/cmdNotFound/CmdNotFound/Telemetry/CmdNotFoundSuggestionProvidedEvent.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-// 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
deleted file mode 100644
index c7a1118eac1..00000000000
--- a/src/modules/cmdNotFound/CmdNotFound/WinGetCommandNotFound.psd1
+++ /dev/null
@@ -1,11 +0,0 @@
-@{
- 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
deleted file mode 100644
index 8a307167e96..00000000000
--- a/src/modules/cmdNotFound/CmdNotFound/WinGetCommandNotFoundFeedbackPredictor.cs
+++ /dev/null
@@ -1,221 +0,0 @@
-// 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 ManagedCommon;
-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)
- {
- Logger.InitializeLogger("\\CmdNotFound\\Logs");
-
- _guid = new Guid(guid);
-
- var provider = new DefaultObjectPoolProvider();
- _pool = provider.Create(new PooledPowerShellObjectPolicy());
- _pool.Return(_pool.Get());
- Task.Run(() => WarmUp());
-
- // Telemetry that a shell is creating an instance of CommandNotFound.
- PowerToysTelemetry.Log.WriteEvent(new Telemetry.CmdNotFoundInstanceCreatedEvent());
- }
-
- 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)
- {
- try
- {
- 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);
- }
- catch (Exception ex)
- {
- Logger.LogError("GetFeedback failed to execute", ex);
- PowerToysTelemetry.Log.WriteEvent(new Telemetry.CmdNotFoundFeedbackProvidedFailureEvent { Message = ex.Message });
- return new FeedbackItem($"Failed to execute PowerToys Command Not Found.{Environment.NewLine}This is a known issue if PowerShell 7 is installed from the Store or MSIX. If that isn't your case, please report an issue.", new List(), 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/settings-ui/Settings.UI/Assets/Settings/Scripts/CheckCmdNotFoundRequirements.ps1 b/src/settings-ui/Settings.UI/Assets/Settings/Scripts/CheckCmdNotFoundRequirements.ps1
index 260d75c5334..b8f9ceed995 100644
--- a/src/settings-ui/Settings.UI/Assets/Settings/Scripts/CheckCmdNotFoundRequirements.ps1
+++ b/src/settings-ui/Settings.UI/Assets/Settings/Scripts/CheckCmdNotFoundRequirements.ps1
@@ -10,10 +10,25 @@ else
# This message will be compared against in Command Not Found Settings page code behind. Take care when changing it.
}
-if (Get-Module -ListAvailable -Name Microsoft.WinGet.Client)
+if ($mods = Get-Module -ListAvailable -Name Microsoft.WinGet.Client)
{
Write-Host "WinGet Client module detected."
# This message will be compared against in Command Not Found Settings page code behind. Take care when changing it.
+
+ $needsUpdate = $true;
+ foreach ($mod in $mods)
+ {
+ if ($mod.Version -ge "1.8.1133")
+ {
+ $needsUpdate = $false;
+ break;
+ }
+ }
+ if ($needsUpdate)
+ {
+ Write-Host "WinGet Client module needs to be updated."
+ # This message will be compared against in Command Not Found Settings page code behind. Take care when changing it.
+ }
}
else {
Write-Host "WinGet Client module not detected. Installation instructions can be found on https://www.powershellgallery.com/packages/Microsoft.WinGet.Client `r`n"
@@ -30,6 +45,11 @@ if (!(Test-Path $PROFILE))
$profileContent = Get-Content -Path $PROFILE -Raw
if ((-not [string]::IsNullOrEmpty($profileContent)) -and ($profileContent.Contains("34de4b3d-13a8-4540-b76d-b9e8d3851756")))
+{
+ Write-Host "Outdated version of Command Not Found module found in the profile file."
+ # This message will be compared against in Command Not Found Settings page code behind. Take care when changing it.
+}
+elseif ((-not [string]::IsNullOrEmpty($profileContent)) -and ($profileContent.Contains("f45873b3-b655-43a6-b217-97c00aa0db58")))
{
Write-Host "Command Not Found module is registered in the profile file."
# This message will be compared against in Command Not Found Settings page code behind. Take care when changing it.
diff --git a/src/settings-ui/Settings.UI/Assets/Settings/Scripts/DisableModule.ps1 b/src/settings-ui/Settings.UI/Assets/Settings/Scripts/DisableModule.ps1
index 501c4c4141e..6cfd9767fc2 100644
--- a/src/settings-ui/Settings.UI/Assets/Settings/Scripts/DisableModule.ps1
+++ b/src/settings-ui/Settings.UI/Assets/Settings/Scripts/DisableModule.ps1
@@ -5,14 +5,14 @@ $linesToDeleteFound = $False
$atLeastOneInstanceFound = $False
$profileContent | ForEach-Object {
- if ($_.Contains("34de4b3d-13a8-4540-b76d-b9e8d3851756") -and !$linesToDeleteFound)
+ if (($_.Contains("34de4b3d-13a8-4540-b76d-b9e8d3851756") -or $_.Contains("f45873b3-b655-43a6-b217-97c00aa0db58")) -and !$linesToDeleteFound)
{
$linesToDeleteFound = $True
$atLeastOneInstanceFound = $True
return
}
- if ($_.Contains("34de4b3d-13a8-4540-b76d-b9e8d3851756") -and $linesToDeleteFound)
+ if (($_.Contains("34de4b3d-13a8-4540-b76d-b9e8d3851756") -or $_.Contains("f45873b3-b655-43a6-b217-97c00aa0db58")) -and $linesToDeleteFound)
{
$linesToDeleteFound = $False
return
diff --git a/src/settings-ui/Settings.UI/Assets/Settings/Scripts/EnableModule.ps1 b/src/settings-ui/Settings.UI/Assets/Settings/Scripts/EnableModule.ps1
index 3b4842dba14..a2943e4d4ea 100644
--- a/src/settings-ui/Settings.UI/Assets/Settings/Scripts/EnableModule.ps1
+++ b/src/settings-ui/Settings.UI/Assets/Settings/Scripts/EnableModule.ps1
@@ -9,13 +9,36 @@ Enable-ExperimentalFeature PSFeedbackProvider
Write-Host "Enabling experimental feature: PSCommandNotFoundSuggestion"
Enable-ExperimentalFeature PSCommandNotFoundSuggestion
-if (Get-Module -ListAvailable -Name Microsoft.WinGet.Client) {
+$wingetModules = Get-Module -ListAvailable -Name Microsoft.WinGet.Client
+if ($wingetModules) {
+
+ $moduleUpToDate = $false;
+ foreach ($mod in $wingetModules) {
+ if ($mod.Version -ge "1.8.1133") {
+ $moduleUpToDate = $true;
+ break;
+ }
+ }
+
+ if ($moduleUpToDate) {
Write-Host "WinGet Client module detected"
+ } else {
+ Write-Host "WinGet module needs to be updated. Run `"Update-Module -Name Microsoft.WinGet.Client`" to update `r`n"
+ }
}
else {
Write-Host "WinGet module was not found. Installation instructions can be found on https://www.powershellgallery.com/packages/Microsoft.WinGet.Client `r`n"
}
+$CNFModule = Get-Module -ListAvailable -Name Microsoft.WinGet.CommandNotFound
+if ($CNFModule) {
+ Write-Host "Microsoft.WinGet.CommandNotFound module detected"
+} else {
+ Write-Host "Microsoft.WinGet.CommandNotFound was not found. Installing...`r`n"
+ Install-Module -Name Microsoft.WinGet.CommandNotFound -Force
+ Write-Host "Microsoft.WinGet.CommandNotFound module installed`r`n"
+}
+
if (!(Test-Path $PROFILE))
{
Write-Host "Profile file $PROFILE not found".
@@ -26,15 +49,28 @@ if (!(Test-Path $PROFILE))
$profileContent = Get-Content -Path $PROFILE -Raw
if ((-not [string]::IsNullOrEmpty($profileContent)) -and ($profileContent.Contains("34de4b3d-13a8-4540-b76d-b9e8d3851756")))
+{
+ if ($profileContent.Contains("Import-Module `"$scriptPath\WinGetCommandNotFound.psd1`""))
+ {
+ $profileContent = $profileContent.Replace("Import-Module `"$scriptPath\WinGetCommandNotFound.psd1`"",
+ "Import-Module -Name Microsoft.WinGet.CommandNotFound")
+ $profileContent = $profileContent.Replace("34de4b3d-13a8-4540-b76d-b9e8d3851756",
+ "f45873b3-b655-43a6-b217-97c00aa0db58")
+ Set-Content -Path $PROFILE -Value $profileContent
+ Write-Host "Module was successfully upgraded in the profile file."
+ # This message will be compared against in Command Not Found Settings page code behind. Take care when changing it.
+ }
+}
+elseif ((-not [string]::IsNullOrEmpty($profileContent)) -and ($profileContent.Contains("f45873b3-b655-43a6-b217-97c00aa0db58")))
{
Write-Host "Module is already registered in the profile file."
# This message will be compared against in Command Not Found Settings page code behind. Take care when changing it.
}
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"
+ Add-Content -Path $PROFILE -Value "`r`n#f45873b3-b655-43a6-b217-97c00aa0db58 PowerToys CommandNotFound module"
+ Add-Content -Path $PROFILE -Value "`r`nImport-Module -Name Microsoft.WinGet.CommandNotFound"
+ Add-Content -Path $PROFILE -Value "#f45873b3-b655-43a6-b217-97c00aa0db58"
Write-Host "Module was successfully registered in the profile file."
# This message will be compared against in Command Not Found Settings page code behind. Take care when changing it.
}
diff --git a/src/settings-ui/Settings.UI/Assets/Settings/Scripts/InstallWinGetClientModule.ps1 b/src/settings-ui/Settings.UI/Assets/Settings/Scripts/InstallWinGetClientModule.ps1
index ed48ac84e40..1f54c620849 100644
--- a/src/settings-ui/Settings.UI/Assets/Settings/Scripts/InstallWinGetClientModule.ps1
+++ b/src/settings-ui/Settings.UI/Assets/Settings/Scripts/InstallWinGetClientModule.ps1
@@ -1,7 +1,46 @@
-if (Get-Module -ListAvailable -Name Microsoft.WinGet.Client)
+$wingetModules = Get-Module -ListAvailable -Name Microsoft.WinGet.Client
+if ($wingetModules)
{
- Write-Host "WinGet Client module detected."
- # This message will be compared against in Command Not Found Settings page code behind. Take care when changing it.
+ $needsUpdate = $true;
+ foreach ($mod in $wingetModules)
+ {
+ if ($mod.Version -ge "1.8.1133")
+ {
+ $needsUpdate = $false;
+ break;
+ }
+ }
+
+ if ($needsUpdate)
+ {
+ Update-Module -Name Microsoft.WinGet.Client -Force
+ $wingetModules = Get-Module -ListAvailable -Name Microsoft.WinGet.Client
+ $updated = $false;
+ foreach ($mod in $wingetModules)
+ {
+ if ($mod.Version -ge "1.8.1133")
+ {
+ $updated = $true;
+ break;
+ }
+ }
+
+ if ($updated)
+ {
+ Write-Host "WinGet Client module updated."
+ # This message will be compared against in Command Not Found Settings page code behind. Take care when changing it.
+ }
+ else
+ {
+ Write-Host "WinGet Client module detected."
+ # This message will be compared against in Command Not Found Settings page code behind. Take care when changing it.
+ }
+ }
+ else
+ {
+ Write-Host "WinGet Client module detected."
+ # This message will be compared against in Command Not Found Settings page code behind. Take care when changing it.
+ }
}
else {
Install-Module -Name Microsoft.WinGet.Client
diff --git a/src/settings-ui/Settings.UI/Assets/Settings/Scripts/UpgradeModule.ps1 b/src/settings-ui/Settings.UI/Assets/Settings/Scripts/UpgradeModule.ps1
new file mode 100644
index 00000000000..5bb66b55cb4
--- /dev/null
+++ b/src/settings-ui/Settings.UI/Assets/Settings/Scripts/UpgradeModule.ps1
@@ -0,0 +1,29 @@
+if (!(Test-Path $PROFILE))
+{
+ return;
+}
+
+$profileContent = Get-Content -Path $PROFILE -Raw
+$legacyGuid = "34de4b3d-13a8-4540-b76d-b9e8d3851756"
+if ((-not [string]::IsNullOrEmpty($profileContent)) -and ($profileContent.Contains($legacyGuid)))
+{
+ # Upgrade Microsoft.WinGet.Client module
+ $wingetModule = Get-Module -ListAvailable -Name Microsoft.WinGet.Client
+ if ($wingetModule -and $wingetModule.Version -lt "1.8.1133") {
+ Update-Module -Name Microsoft.WinGet.Client
+ }
+
+ # Install Microsoft.WinGet.CommandNotFound module
+ if (-Not (Get-Module -ListAvailable -Name Microsoft.WinGet.CommandNotFound)) {
+ Install-Module -Name Microsoft.WinGet.CommandNotFound -Force
+ }
+
+ # Replace old module with new one (and new GUID comment)
+ $regex = "Import-Module .*WinGetCommandNotFound.psd1`""
+ if ($profileContent -match $regex)
+ {
+ $profileContent = $profileContent -replace $regex, "Import-Module -Name Microsoft.WinGet.CommandNotFound"
+ $profileContent = $profileContent -replace $legacyGuid, "f45873b3-b655-43a6-b217-97c00aa0db58"
+ Set-Content -Path $PROFILE -Value $profileContent
+ }
+}
\ No newline at end of file
diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Views/CmdNotFoundPage.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Views/CmdNotFoundPage.xaml
index 049cfbb0ffc..649d3062261 100644
--- a/src/settings-ui/Settings.UI/SettingsXAML/Views/CmdNotFoundPage.xaml
+++ b/src/settings-ui/Settings.UI/SettingsXAML/Views/CmdNotFoundPage.xaml
@@ -17,10 +17,7 @@
TrueValue="Collapsed" />
-
+
+ IsOpen="True">
@@ -74,16 +71,10 @@
-
-
+
@@ -113,7 +104,7 @@
-
+
diff --git a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw
index 846af5dc0df..4ca8fc087e7 100644
--- a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw
+++ b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw
@@ -4046,9 +4046,6 @@ Activate by holding the key for the character you want to add an accent to, then
Show the release notes after an update
-
- Command Not Found is not supported on the ARM64 architecture currently. We are actively working on a solution.
-
Do not activate when Game Mode is on
"Game mode" is the Windows feature to prevent notification when playing a game.
diff --git a/src/settings-ui/Settings.UI/ViewModels/CmdNotFoundViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/CmdNotFoundViewModel.cs
index a861e1e7ad0..c5b8684eddf 100644
--- a/src/settings-ui/Settings.UI/ViewModels/CmdNotFoundViewModel.cs
+++ b/src/settings-ui/Settings.UI/ViewModels/CmdNotFoundViewModel.cs
@@ -129,11 +129,6 @@ public bool IsEnabledGpoConfigured
get => _enabledStateIsGPOConfigured;
}
- public bool IsArm64Arch
- {
- get => RuntimeInformation.OSArchitecture == System.Runtime.InteropServices.Architecture.Arm64;
- }
-
public string RunPowerShellOrPreviewScript(string powershellExecutable, string powershellArguments, bool hidePowerShellWindow = false)
{
if (isPowerShellPreviewDetected)
@@ -228,7 +223,7 @@ public void CheckCommandNotFoundRequirements()
{
IsWinGetClientModuleDetected = true;
}
- else if (result.Contains("WinGet Client module not detected."))
+ else if (result.Contains("WinGet Client module not detected.") || result.Contains("WinGet Client module needs to be updated."))
{
IsWinGetClientModuleDetected = false;
}
@@ -237,7 +232,7 @@ public void CheckCommandNotFoundRequirements()
{
IsCommandNotFoundModuleInstalled = true;
}
- else if (result.Contains("Command Not Found module is not registered in the profile file."))
+ 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;
}
@@ -266,7 +261,7 @@ 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."))
+ if (result.Contains("WinGet Client module detected.") || result.Contains("WinGet Client module updated."))
{
IsWinGetClientModuleDetected = true;
}
@@ -284,7 +279,9 @@ public void InstallModule()
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."))
+ 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());