diff --git a/src/common/UITestAutomation/SettingsConfigHelper.cs b/src/common/UITestAutomation/SettingsConfigHelper.cs
new file mode 100644
index 0000000000..833ec4f19d
--- /dev/null
+++ b/src/common/UITestAutomation/SettingsConfigHelper.cs
@@ -0,0 +1,175 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Linq;
+using System.Text.Json;
+using Microsoft.PowerToys.Settings.UI.Library;
+using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
+using Microsoft.PowerToys.Settings.UI.Library.Utilities;
+
+namespace Microsoft.PowerToys.UITest
+{
+ ///
+ /// Helper class for configuring PowerToys settings for UI tests.
+ ///
+ public class SettingsConfigHelper
+ {
+ private static readonly JsonSerializerOptions IndentedJsonOptions = new() { WriteIndented = true };
+ private static readonly SettingsUtils SettingsUtils = new SettingsUtils();
+
+ ///
+ /// Configures global PowerToys settings to enable only specified modules and disable all others.
+ ///
+ /// Array of module names to enable (e.g., "Peek", "FancyZones"). All other modules will be disabled.
+ /// Thrown when modulesToEnable is null.
+ /// Thrown when settings file operations fail.
+ [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "This is test code and will not be trimmed")]
+ [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "This is test code and will not be AOT compiled")]
+ public static void ConfigureGlobalModuleSettings(params string[] modulesToEnable)
+ {
+ ArgumentNullException.ThrowIfNull(modulesToEnable);
+
+ try
+ {
+ GeneralSettings settings;
+ try
+ {
+ settings = SettingsUtils.GetSettingsOrDefault();
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Failed to load settings, creating defaults: {ex.Message}");
+ settings = new GeneralSettings();
+ }
+
+ string settingsJson = settings.ToJsonString();
+ using (JsonDocument doc = JsonDocument.Parse(settingsJson))
+ {
+ var options = new JsonSerializerOptions { WriteIndented = true };
+ var root = doc.RootElement.Clone();
+
+ if (root.TryGetProperty("enabled", out var enabledElement))
+ {
+ var enabledModules = new Dictionary();
+
+ foreach (var property in enabledElement.EnumerateObject())
+ {
+ string moduleName = property.Name;
+
+ bool shouldEnable = Array.Exists(modulesToEnable, m => string.Equals(m, moduleName, StringComparison.Ordinal));
+ enabledModules[moduleName] = shouldEnable;
+ }
+
+ var settingsDict = JsonSerializer.Deserialize>(settingsJson);
+ if (settingsDict != null)
+ {
+ settingsDict["enabled"] = enabledModules;
+ settingsJson = JsonSerializer.Serialize(settingsDict, IndentedJsonOptions);
+ }
+ }
+ }
+
+ SettingsUtils.SaveSettings(settingsJson);
+
+ string enabledList = modulesToEnable.Length > 0 ? string.Join(", ", modulesToEnable) : "none";
+ Debug.WriteLine($"Successfully updated global settings");
+ Debug.WriteLine($"Enabled modules: {enabledList}");
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"ERROR in ConfigureGlobalModuleSettings: {ex.Message}");
+ throw new InvalidOperationException($"Failed to configure global module settings: {ex.Message}", ex);
+ }
+ }
+
+ ///
+ /// Updates a module's settings file. If the file doesn't exist, creates it with default content.
+ /// If the file exists, reads it and applies the provided update function to modify the settings.
+ ///
+ /// The name of the module (e.g., "Peek", "FancyZones").
+ /// The default JSON content to use if the settings file doesn't exist.
+ ///
+ /// A callback function that modifies the settings dictionary. The function receives the deserialized settings
+ /// and should modify it in-place. The function should accept a Dictionary<string, object> and not return a value.
+ /// Example: (settings) => { ((Dictionary<string, object>)settings["properties"])["SomeSetting"] = newValue; }
+ ///
+ /// Thrown when moduleName or updateSettingsAction is null.
+ /// Thrown when settings file operations fail.
+ [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "This is test code and will not be trimmed")]
+ [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "This is test code and will not be AOT compiled")]
+ public static void UpdateModuleSettings(
+ string moduleName,
+ string defaultSettingsContent,
+ Action> updateSettingsAction)
+ {
+ ArgumentNullException.ThrowIfNull(moduleName);
+ ArgumentNullException.ThrowIfNull(updateSettingsAction);
+
+ try
+ {
+ // Build the path to the module settings file
+ string powerToysSettingsDirectory = Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+ "Microsoft",
+ "PowerToys");
+
+ string moduleDirectory = Path.Combine(powerToysSettingsDirectory, moduleName);
+ string settingsPath = Path.Combine(moduleDirectory, "settings.json");
+
+ // Ensure directory exists
+ Directory.CreateDirectory(moduleDirectory);
+
+ // Read existing settings or use default
+ string existingJson = string.Empty;
+ if (File.Exists(settingsPath))
+ {
+ existingJson = File.ReadAllText(settingsPath);
+ }
+
+ Dictionary? settings;
+
+ // If file doesn't exist or is empty, create from defaults
+ if (string.IsNullOrWhiteSpace(existingJson))
+ {
+ if (string.IsNullOrWhiteSpace(defaultSettingsContent))
+ {
+ throw new ArgumentException("Default settings content must be provided when file doesn't exist.", nameof(defaultSettingsContent));
+ }
+
+ settings = JsonSerializer.Deserialize>(defaultSettingsContent)
+ ?? throw new InvalidOperationException($"Failed to deserialize default settings for {moduleName}");
+
+ Debug.WriteLine($"Created default settings for {moduleName} at {settingsPath}");
+ }
+ else
+ {
+ // Parse existing settings
+ settings = JsonSerializer.Deserialize>(existingJson)
+ ?? throw new InvalidOperationException($"Failed to deserialize existing settings for {moduleName}");
+
+ Debug.WriteLine($"Loaded existing settings for {moduleName} from {settingsPath}");
+ }
+
+ // Apply the update action to modify settings
+ updateSettingsAction(settings);
+
+ // Serialize and save the updated settings using SettingsUtils
+ string updatedJson = JsonSerializer.Serialize(settings, IndentedJsonOptions);
+ SettingsUtils.SaveSettings(updatedJson, moduleName);
+
+ Debug.WriteLine($"Successfully updated settings for {moduleName}");
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"ERROR in UpdateModuleSettings for {moduleName}: {ex.Message}");
+ throw new InvalidOperationException($"Failed to update settings for {moduleName}: {ex.Message}", ex);
+ }
+ }
+ }
+}
diff --git a/src/common/UITestAutomation/UITestAutomation.csproj b/src/common/UITestAutomation/UITestAutomation.csproj
index add7acfeb9..549b8a430b 100644
--- a/src/common/UITestAutomation/UITestAutomation.csproj
+++ b/src/common/UITestAutomation/UITestAutomation.csproj
@@ -8,7 +8,7 @@
enable
true
true
- net9.0-windows10.0.22621.0
+ net9.0-windows10.0.26100.0
true
false
@@ -21,4 +21,8 @@
+
+
+
+
diff --git a/src/modules/peek/Peek.UITests/PeekFilePreviewTests.cs b/src/modules/peek/Peek.UITests/PeekFilePreviewTests.cs
index 36f2491fcf..fd57c444ca 100644
--- a/src/modules/peek/Peek.UITests/PeekFilePreviewTests.cs
+++ b/src/modules/peek/Peek.UITests/PeekFilePreviewTests.cs
@@ -9,6 +9,7 @@ using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
+using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.PowerToys.UITest;
@@ -35,6 +36,105 @@ public class PeekFilePreviewTests : UITestBase
{
}
+ static PeekFilePreviewTests()
+ {
+ FixSettingsFileBeforeTests();
+ }
+
+ private static readonly JsonSerializerOptions IndentedJsonOptions = new() { WriteIndented = true };
+
+ private static void FixSettingsFileBeforeTests()
+ {
+ try
+ {
+ // Default Peek settings
+ string peekSettingsContent = @"{
+ ""name"": ""Peek"",
+ ""version"": ""1.0"",
+ ""properties"": {
+ ""ActivationShortcut"": {
+ ""win"": false,
+ ""ctrl"": true,
+ ""alt"": false,
+ ""shift"": false,
+ ""code"": 32,
+ ""key"": ""Space""
+ },
+ ""AlwaysRunNotElevated"": {
+ ""value"": true
+ },
+ ""CloseAfterLosingFocus"": {
+ ""value"": false
+ },
+ ""ConfirmFileDelete"": {
+ ""value"": true
+ },
+ ""EnableSpaceToActivate"": {
+ ""value"": false
+ }
+ }
+ }";
+
+ // Update Peek module settings
+ SettingsConfigHelper.UpdateModuleSettings(
+ "Peek",
+ peekSettingsContent,
+ (settings) =>
+ {
+ // Get or ensure properties section exists
+ Dictionary properties;
+
+ if (settings.TryGetValue("properties", out var propertiesObj))
+ {
+ if (propertiesObj is Dictionary dict)
+ {
+ properties = dict;
+ }
+ else if (propertiesObj is JsonElement jsonElem)
+ {
+ properties = JsonSerializer.Deserialize>(jsonElem.GetRawText())
+ ?? throw new InvalidOperationException("Failed to deserialize properties");
+ }
+ else
+ {
+ properties = new Dictionary();
+ }
+ }
+ else
+ {
+ properties = new Dictionary();
+ }
+
+ // Update the required properties
+ properties["ActivationShortcut"] = new Dictionary
+ {
+ { "win", false },
+ { "ctrl", true },
+ { "alt", false },
+ { "shift", false },
+ { "code", 32 },
+ { "key", "Space" },
+ };
+
+ properties["EnableSpaceToActivate"] = new Dictionary
+ {
+ { "value", false },
+ };
+
+ settings["properties"] = properties;
+ });
+
+ // Disable all modules except Peek in global settings
+ SettingsConfigHelper.ConfigureGlobalModuleSettings("Peek");
+
+ Debug.WriteLine("Successfully updated all settings - Peek shortcut configured and all modules except Peek disabled");
+ }
+ catch (Exception ex)
+ {
+ Assert.Fail($"ERROR in FixSettingsFileBeforeTests: {ex.Message}");
+ }
+ }
+
[TestInitialize]
public void TestInitialize()
{