diff --git a/src/common/GPOWrapper/GPOWrapper.cpp b/src/common/GPOWrapper/GPOWrapper.cpp index 67dae70930..25d60a7d10 100644 --- a/src/common/GPOWrapper/GPOWrapper.cpp +++ b/src/common/GPOWrapper/GPOWrapper.cpp @@ -232,4 +232,8 @@ namespace winrt::PowerToys::GPOWrapper::implementation { return static_cast(powertoys_gpo::getAllowDataDiagnosticsValue()); } + GpoRuleConfigured GPOWrapper::GetConfiguredRunAtStartupValue() + { + return static_cast(powertoys_gpo::getConfiguredRunAtStartupValue()); + } } diff --git a/src/common/GPOWrapper/GPOWrapper.h b/src/common/GPOWrapper/GPOWrapper.h index 8df863b9d7..4b0cb7af00 100644 --- a/src/common/GPOWrapper/GPOWrapper.h +++ b/src/common/GPOWrapper/GPOWrapper.h @@ -63,6 +63,7 @@ namespace winrt::PowerToys::GPOWrapper::implementation static winrt::hstring GPOWrapper::GetConfiguredMwbPolicyDefinedIpMappingRules(); static GpoRuleConfigured GetConfiguredNewPlusHideTemplateFilenameExtensionValue(); static GpoRuleConfigured GetAllowDataDiagnosticsValue(); + static GpoRuleConfigured GetConfiguredRunAtStartupValue(); }; } diff --git a/src/common/GPOWrapper/GPOWrapper.idl b/src/common/GPOWrapper/GPOWrapper.idl index d22ab63e09..247e2a0900 100644 --- a/src/common/GPOWrapper/GPOWrapper.idl +++ b/src/common/GPOWrapper/GPOWrapper.idl @@ -67,6 +67,7 @@ namespace PowerToys static String GetConfiguredMwbPolicyDefinedIpMappingRules(); static GpoRuleConfigured GetConfiguredNewPlusHideTemplateFilenameExtensionValue(); static GpoRuleConfigured GetAllowDataDiagnosticsValue(); + static GpoRuleConfigured GetConfiguredRunAtStartupValue(); } } } diff --git a/src/common/utils/gpo.h b/src/common/utils/gpo.h index d1341c63ac..93f2069208 100644 --- a/src/common/utils/gpo.h +++ b/src/common/utils/gpo.h @@ -73,6 +73,7 @@ namespace powertoys_gpo { // The registry value names for other PowerToys policies. const std::wstring POLICY_ALLOW_EXPERIMENTATION = L"AllowExperimentation"; const std::wstring POLICY_ALLOW_DATA_DIAGNOSTICS = L"AllowDataDiagnostics"; + const std::wstring POLICY_CONFIGURE_RUN_AT_STARTUP = L"ConfigureRunAtStartup"; const std::wstring POLICY_CONFIGURE_ENABLED_POWER_LAUNCHER_ALL_PLUGINS = L"PowerLauncherAllPluginsEnabledState"; const std::wstring POLICY_ALLOW_ADVANCED_PASTE_ONLINE_AI_MODELS = L"AllowPowerToysAdvancedPasteOnlineAIModels"; const std::wstring POLICY_MWB_CLIPBOARD_SHARING_ENABLED = L"MwbClipboardSharingEnabled"; @@ -494,6 +495,11 @@ namespace powertoys_gpo { return getConfiguredValue(POLICY_ALLOW_DATA_DIAGNOSTICS); } + inline gpo_rule_configured_t getConfiguredRunAtStartupValue() + { + return getConfiguredValue(POLICY_CONFIGURE_RUN_AT_STARTUP); + } + inline gpo_rule_configured_t getRunPluginEnabledValue(std::string pluginID) { if (pluginID == "" || pluginID == " ") diff --git a/src/gpo/assets/PowerToys.admx b/src/gpo/assets/PowerToys.admx index 188b92c353..82707dbd3e 100644 --- a/src/gpo/assets/PowerToys.admx +++ b/src/gpo/assets/PowerToys.admx @@ -536,6 +536,16 @@ + + + + + + + + + + diff --git a/src/gpo/assets/en-US/PowerToys.adml b/src/gpo/assets/en-US/PowerToys.adml index 6ff31ebc51..bc8afc9d2b 100644 --- a/src/gpo/assets/en-US/PowerToys.adml +++ b/src/gpo/assets/en-US/PowerToys.adml @@ -112,6 +112,16 @@ If this setting is disabled, experimentation is not allowed. If this setting is enabled or not configured, the user can control diagnostic data sending in the PowerToys settings menu. If this setting is disabled, diagnostic data sending is not allowed. + + This policy configures the "run at startup" setting of PowerToys. + +If you enable this setting, the "run at startup" setting will be always enabled and the user won't be able to disable it. + +If you disable this setting, the "run at startup" setting will be always disabled and the user won't be able to enable it. + +If you don't configure this setting, users are able to enable or disable "run at startup" at will. + +Note: This only controls the PowerToys method that creates a scheduled task to start PowerToys at login. It doesn't control other custom auto-start methods that the user might try to use outside of PowerToys or manually creating/deleting a scheduled task. This policy configures the enabled state for all PowerToys Run plugins. All plugins will have the same state. @@ -279,6 +289,7 @@ If you don't configure this policy, the user takes control over the setting and Predefined IP Address mapping rules Hide template filename extension Allow sending diagnostic data + Configure the run at startup setting diff --git a/src/runner/general_settings.cpp b/src/runner/general_settings.cpp index 9e3b170feb..83128b05e9 100644 --- a/src/runner/general_settings.cpp +++ b/src/runner/general_settings.cpp @@ -112,9 +112,21 @@ void apply_general_settings(const json::JsonObject& general_configs, bool save) enable_experimentation = general_configs.GetNamedBoolean(L"enable_experimentation", true); + // apply_general_settings is called by the runner's WinMain, so we can just force the run at startup gpo rule here. + auto gpo_run_as_startup = powertoys_gpo::getConfiguredRunAtStartupValue(); + if (json::has(general_configs, L"startup", json::JsonValueType::Boolean)) { - const bool startup = general_configs.GetNamedBoolean(L"startup"); + bool startup = general_configs.GetNamedBoolean(L"startup"); + + if (gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_enabled) + { + startup = true; + } + else if (gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_disabled) + { + startup = false; + } if (startup) { @@ -147,7 +159,9 @@ void apply_general_settings(const json::JsonObject& general_configs, bool save) else { delete_auto_start_task_for_this_user(); - create_auto_start_task_for_this_user(run_as_elevated); + if (gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_enabled || gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_not_configured) { + create_auto_start_task_for_this_user(run_as_elevated); + } } if (json::has(general_configs, L"enabled")) diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Views/GeneralPage.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Views/GeneralPage.xaml index 6eee331171..fcd06e8292 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Views/GeneralPage.xaml +++ b/src/settings-ui/Settings.UI/SettingsXAML/Views/GeneralPage.xaml @@ -263,9 +263,21 @@ - + + + + + + diff --git a/src/settings-ui/Settings.UI/ViewModels/GeneralViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/GeneralViewModel.cs index 6a2340f8c6..995f864c57 100644 --- a/src/settings-ui/Settings.UI/ViewModels/GeneralViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/GeneralViewModel.cs @@ -121,7 +121,18 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels _isDevBuild = Helper.GetProductVersion() == "v0.0.1"; - _startup = GeneralSettingsConfig.Startup; + _runAtStartupGpoRuleConfiguration = GPOWrapper.GetConfiguredRunAtStartupValue(); + if (_runAtStartupGpoRuleConfiguration == GpoRuleConfigured.Disabled || _runAtStartupGpoRuleConfiguration == GpoRuleConfigured.Enabled) + { + // Get the enabled state from GPO. + _runAtStartupIsGPOConfigured = true; + _startup = _runAtStartupGpoRuleConfiguration == GpoRuleConfigured.Enabled; + } + else + { + _startup = GeneralSettingsConfig.Startup; + } + _showNewUpdatesToastNotification = GeneralSettingsConfig.ShowNewUpdatesToastNotification; _autoDownloadUpdates = GeneralSettingsConfig.AutoDownloadUpdates; _showWhatsNewAfterUpdates = GeneralSettingsConfig.ShowWhatsNewAfterUpdates; @@ -204,6 +215,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels private static bool _isDevBuild; private bool _startup; + private GpoRuleConfigured _runAtStartupGpoRuleConfiguration; + private bool _runAtStartupIsGPOConfigured; private bool _isElevated; private bool _runElevated; private bool _isAdmin; @@ -251,6 +264,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels set { + if (_runAtStartupIsGPOConfigured) + { + // If it's GPO configured, shouldn't be able to change this state. + return; + } + if (_startup != value) { _startup = value; @@ -524,6 +543,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels get => _enableDataDiagnosticsIsGpoDisallowed; } + public bool IsRunAtStartupGPOManaged + { + get => _runAtStartupIsGPOConfigured; + } + public string SettingsBackupAndRestoreDir { get diff --git a/tools/BugReportTool/BugReportTool/ReportGPOValues.cpp b/tools/BugReportTool/BugReportTool/ReportGPOValues.cpp index 2ba84a55e4..704ec6b792 100644 --- a/tools/BugReportTool/BugReportTool/ReportGPOValues.cpp +++ b/tools/BugReportTool/BugReportTool/ReportGPOValues.cpp @@ -95,4 +95,5 @@ void ReportGPOValues(const std::filesystem::path &tmpDir) report << "getConfiguredNewPlusEnabledValue: " << gpo_rule_configured_to_string(powertoys_gpo::getConfiguredNewPlusEnabledValue()) << std::endl; report << "getConfiguredNewPlusHideTemplateFilenameExtensionValue: " << gpo_rule_configured_to_string(powertoys_gpo::getConfiguredNewPlusHideTemplateFilenameExtensionValue()) << std::endl; report << "getAllowDataDiagnosticsValue: " << gpo_rule_configured_to_string(powertoys_gpo::getAllowDataDiagnosticsValue()) << std::endl; + report << "getConfiguredRunAtStartupValue: " << gpo_rule_configured_to_string(powertoys_gpo::getConfiguredRunAtStartupValue()) << std::endl; }