diff --git a/src/common/GPOWrapper/GPOWrapper.cpp b/src/common/GPOWrapper/GPOWrapper.cpp index 67dae7093025..25d60a7d10a3 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 8df863b9d7a7..4b0cb7af0001 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 d22ab63e0999..247e2a090088 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 d1341c63ac29..93f20692082c 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 188b92c353a7..82707dbd3e97 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 6ff31ebc51f2..bc8afc9d2b4b 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 9e3b170feb19..83128b05e999 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 6eee331171c7..fcd06e82929d 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 6a2340f8c6fb..995f864c57f7 100644 --- a/src/settings-ui/Settings.UI/ViewModels/GeneralViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/GeneralViewModel.cs @@ -121,7 +121,18 @@ public GeneralViewModel(ISettingsRepository settingsRepository, _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 @@ public GeneralViewModel(ISettingsRepository settingsRepository, 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 @@ public bool Startup 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 @@ public bool IsDataDiagnosticsGPOManaged 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 2ba84a55e481..704ec6b79280 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; }