Skip to content

Commit

Permalink
[GPO; Enterprise] Updater policies (#24221)
Browse files Browse the repository at this point in the history
* Implement GPO

* Add GPOs in updater

* Rename policy

* fix

* fix

* Update GPOWrapper.h

Added relative path to Generated Files folder for GPOWrapper.g.h

* fix and inactivate PeriodicUpdateCheck gpo

* Docs

* GPO name change

* Templates

* Templates: Text changes

* Templates: Text changes

* Templates: Text changes

* docs: spell fix

* settings ui

* fixes

* fixes

* fix gpo description

* EOF fix

* Fix include in UpdateUtils.cpp and remove build workaround

* UI improvements

* spell fixes

* code improvements

* Update README.md

* Update PowerToys.adml

* Update src/gpo/assets/PowerToys.admx

* Remove forbidden pattern
  • Loading branch information
htcfreek committed Feb 24, 2023
1 parent 0524a4b commit 6750442
Show file tree
Hide file tree
Showing 11 changed files with 201 additions and 15 deletions.
32 changes: 32 additions & 0 deletions doc/gpo/README.md
Expand Up @@ -39,3 +39,35 @@ This policy configures whether PowerToys experimentation is allowed. With experi
If this setting is not configured or enabled, the user can control experimentation in the PowerToys settings menu.

If this setting is disabled, experimentation is not allowed.

If this setting is not configured, experimentation is allowed.

### Installer and Updates

#### Disable automatic downloads

This policy configures whether automatic downloads of available updates are disabled or not. (On metered connections updates are never downloaded.)

If enabled, automatic downloads are disabled.

If disabled or not configured, the user is in control of automatic downloads setting.

#### Suspend Action Center notification for new updates

This policy configures whether the action center notification for new updates is suspended for 2 minor releases. (Example: if the installed version is v0.60.0, then the next notification is shown for the v0.63.* release.)

If enabled, the notification is suspended.

If disabled or not configured, the notification is shown.

Note: The notification about new major versions is always displayed.

<!-- This policy is implemented for later usage (PT v1.0 and later) and therefore inactive. (To make it working please update `src/runner/UpdateUtils.cpp`)
#### Disable automatic update checks
This policy allows you to disable automatic update checks running in the background. (The manual check in PT Settings is not affected by this policy.)
If enabled, the automatic update checks are disabled.
If disabled or not configured, the automatic update checks are enabled.
-->
4 changes: 4 additions & 0 deletions src/common/GPOWrapper/GPOWrapper.cpp
Expand Up @@ -120,6 +120,10 @@ namespace winrt::PowerToys::GPOWrapper::implementation
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredVideoConferenceMuteEnabledValue());
}
GpoRuleConfigured GPOWrapper::GetDisableAutomaticUpdateDownloadValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getDisableAutomaticUpdateDownloadValue());
}
GpoRuleConfigured GPOWrapper::GetAllowExperimentationValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowExperimentationValue());
Expand Down
1 change: 1 addition & 0 deletions src/common/GPOWrapper/GPOWrapper.h
Expand Up @@ -36,6 +36,7 @@ namespace winrt::PowerToys::GPOWrapper::implementation
static GpoRuleConfigured GetConfiguredTextExtractorEnabledValue();
static GpoRuleConfigured GetConfiguredPastePlainEnabledValue();
static GpoRuleConfigured GetConfiguredVideoConferenceMuteEnabledValue();
static GpoRuleConfigured GetDisableAutomaticUpdateDownloadValue();
static GpoRuleConfigured GetAllowExperimentationValue();
};
}
Expand Down
1 change: 1 addition & 0 deletions src/common/GPOWrapper/GPOWrapper.idl
Expand Up @@ -40,6 +40,7 @@ namespace PowerToys
static GpoRuleConfigured GetConfiguredTextExtractorEnabledValue();
static GpoRuleConfigured GetConfiguredPastePlainEnabledValue();
static GpoRuleConfigured GetConfiguredVideoConferenceMuteEnabledValue();
static GpoRuleConfigured GetDisableAutomaticUpdateDownloadValue();
static GpoRuleConfigured GetAllowExperimentationValue();
}
}
Expand Down
22 changes: 22 additions & 0 deletions src/common/utils/gpo.h
Expand Up @@ -48,6 +48,13 @@ namespace powertoys_gpo {
const std::wstring POLICY_CONFIGURE_ENABLED_TEXT_EXTRACTOR = L"ConfigureEnabledUtilityTextExtractor";
const std::wstring POLICY_CONFIGURE_ENABLED_PASTE_PLAIN = L"ConfigureEnabledUtilityPastePlain";
const std::wstring POLICY_CONFIGURE_ENABLED_VIDEO_CONFERENCE_MUTE = L"ConfigureEnabledUtilityVideoConferenceMute";

// The registry value names for PowerToys installer and update policies.
const std::wstring POLICY_DISABLE_AUTOMATIC_UPDATE_DOWNLOAD = L"AutomaticUpdateDownloadDisabled";
const std::wstring POLICY_SUSPEND_NEW_UPDATE_TOAST = L"SuspendNewUpdateAvailableToast";
const std::wstring POLICY_DISABLE_PERIODIC_UPDATE_CHECK = L"PeriodicUpdateCheckDisabled";

// The registry value names for other PowerToys policies.
const std::wstring POLICY_ALLOW_EXPERIMENTATION = L"AllowExperimentation";

inline gpo_rule_configured_t getConfiguredValue(const std::wstring& registry_value_name)
Expand Down Expand Up @@ -248,6 +255,21 @@ namespace powertoys_gpo {
return getConfiguredValue(POLICY_CONFIGURE_ENABLED_VIDEO_CONFERENCE_MUTE);
}

inline gpo_rule_configured_t getDisableAutomaticUpdateDownloadValue()
{
return getConfiguredValue(POLICY_DISABLE_AUTOMATIC_UPDATE_DOWNLOAD);
}

inline gpo_rule_configured_t getSuspendNewUpdateToastValue()
{
return getConfiguredValue(POLICY_SUSPEND_NEW_UPDATE_TOAST);
}

inline gpo_rule_configured_t getDisablePeriodicUpdateCheckValue()
{
return getConfiguredValue(POLICY_DISABLE_PERIODIC_UPDATE_CHECK);
}

inline gpo_rule_configured_t getAllowExperimentationValue()
{
return getConfiguredValue(POLICY_ALLOW_EXPERIMENTATION);
Expand Down
36 changes: 35 additions & 1 deletion src/gpo/assets/PowerToys.admx
Expand Up @@ -13,7 +13,9 @@
</definitions>
</supportedOn>
<categories>
<category name="PowerToys" displayName="$(string.PowerToys)">
<category name="PowerToys" displayName="$(string.PowerToys)" />
<category name="InstallerUpdates" displayName="$(string.InstallerUpdates)">
<parentCategory ref="PowerToys" />
</category>
</categories>
<policies>
Expand Down Expand Up @@ -307,6 +309,38 @@
<decimal value="0" />
</disabledValue>
</policy>
<policy name="DisableAutomaticUpdateDownload" class="Both" displayName="$(string.DisableAutomaticUpdateDownload)" explainText="$(string.DisableAutomaticUpdateDownloadDescription)" key="Software\Policies\PowerToys" valueName="AutomaticUpdateDownloadDisabled">
<parentCategory ref="InstallerUpdates" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_68_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="SuspendNewUpdateToast" class="Both" displayName="$(string.SuspendNewUpdateToast)" explainText="$(string.SuspendNewUpdateToastDescription)" key="Software\Policies\PowerToys" valueName="SuspendNewUpdateAvailableToast">
<parentCategory ref="InstallerUpdates" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_68_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<!-- This policy is implemented for later usage (PT v1.0 and later) and therefore inactive. (To make it working please update `src/runner/UpdateUtils.cpp`)
<policy name="DisablePeriodicUpdateCheck" class="Both" displayName="$(string.DisablePeriodicUpdateCheck)" explainText="$(string.DisablePeriodicUpdateCheckDescription)" key="Software\Policies\PowerToys" valueName="PeriodicUpdateCheckDisabled">
<parentCategory ref="InstallerUpdates" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_68_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
-->
<policy name="AllowExperimentation" class="Both" displayName="$(string.AllowExperimentation)" explainText="$(string.AllowExperimentationDescription)" key="Software\Policies\PowerToys" valueName="AllowExperimentation">
<parentCategory ref="PowerToys" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_68_0" />
Expand Down
24 changes: 24 additions & 0 deletions src/gpo/assets/en-US/PowerToys.adml
Expand Up @@ -7,6 +7,7 @@
<resources>
<stringTable>
<string id="PowerToys">Microsoft PowerToys</string>
<string id="InstallerUpdates">Installer and Updates</string>

<string id="SUPPORTED_POWERTOYS_0_64_0">PowerToys version 0.64.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_68_0">PowerToys version 0.68.0 or later</string>
Expand All @@ -28,6 +29,26 @@ If you enable this setting, the utility will be always enabled and the user won'
If you disable this setting, the utility 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 disable or enable the utility.
</string>
<string id="DisableAutomaticUpdateDownloadDescription">This policy configures whether automatic downloads of available updates are disabled or not. (On metered connections updates are never downloaded.)

If enabled, automatic downloads are disabled.

If disabled or not configured, the user is in control of automatic downloads setting.
</string>
<string id="SuspendNewUpdateToastDescription">This policy configures whether the action center notification for new updates is suspended for 2 minor releases. (Example: if the installed version is v0.60.0, then the next notification is shown for the v0.63.* release.)

If enabled, the notification is suspended.

If disabled or not configured, the notification is shown.

Note: The notification about new major versions is always displayed.
</string>
<string id="DisablePeriodicUpdateCheckDescription">This policy allows you to disable automatic update checks running in the background. (The manual check in PT Settings is not affected by this policy.)

If enabled, the automatic update checks are disabled.

If disabled or not configured, the automatic update checks are enabled.
</string>
<string id="AllowExperimentationDescription">This policy configures whether PowerToys experimentation is allowed. With experimentation allowed the user sees the new features being experimented if it gets selected as part of the test group. (Experimentation will only happen on Windows Insider builds.)

Expand Down Expand Up @@ -64,6 +85,9 @@ If this setting is disabled, experimentation is not allowed.
<string id="ConfigureEnabledUtilityShortcutGuide">Shortcut Guide: Configure enabled state</string>
<string id="ConfigureEnabledUtilityTextExtractor">Text Extractor: Configure enabled state</string>
<string id="ConfigureEnabledUtilityVideoConferenceMute">Video Conference Mute: Configure enabled state</string>
<string id="DisableAutomaticUpdateDownload">Disable automatic downloads</string>
<string id="SuspendNewUpdateToast">Suspend Action Center notification for new updates</string>
<string id="DisablePeriodicUpdateCheck">Disable automatic update checks</string>
<string id="AllowExperimentation">Allow Experimentation</string>
</stringTable>
</resources>
Expand Down
50 changes: 47 additions & 3 deletions src/runner/UpdateUtils.cpp
Expand Up @@ -6,6 +6,7 @@
#include "general_settings.h"
#include "UpdateUtils.h"

#include <common/utils/gpo.h>
#include <common/logger/logger.h>
#include <common/notifications/notifications.h>
#include <common/updating/installer.h>
Expand All @@ -21,6 +22,10 @@ namespace
{
constexpr int64_t UPDATE_CHECK_INTERVAL_MINUTES = 60 * 24;
constexpr int64_t UPDATE_CHECK_AFTER_FAILED_INTERVAL_MINUTES = 60 * 2;

// How many minor versions to suspend the toast notification (example: installed=0.60.0, suspend=2, next notification=0.63.*)
// Attention: When changing this value please update the ADML file to.
const int UPDATE_NOTIFICATION_TOAST_SUSPEND_MINOR_VERSION_COUNT = 2;
}
using namespace notifications;
using namespace updating;
Expand Down Expand Up @@ -113,7 +118,7 @@ bool IsMeteredConnection()
void ProcessNewVersionInfo(const github_version_info& version_info,
UpdateState& state,
const bool download_update,
const bool show_notifications)
bool show_notifications)
{
state.githubUpdateLastCheckedDate.emplace(timeutil::now());
if (std::holds_alternative<version_up_to_date>(version_info))
Expand All @@ -135,6 +140,22 @@ void ProcessNewVersionInfo(const github_version_info& version_info,
return;
}

// Check notification GPO.
// We check only if notifications are allowed. This is the case if we are triggered by the periodic check.
if (show_notifications && powertoys_gpo::getSuspendNewUpdateToastValue() == powertoys_gpo::gpo_rule_configured_enabled)
{
Logger::info(L"GPO to suspend new update toast notification is enabled.");
if (new_version_info.version.major <= VERSION_MAJOR && new_version_info.version.minor - VERSION_MINOR <= UPDATE_NOTIFICATION_TOAST_SUSPEND_MINOR_VERSION_COUNT)
{
Logger::info(L"The difference between the installed version and the newer version is within the allowed period. The toast notification is not shown.");
show_notifications = false;
}
else
{
Logger::info(L"The installed version is older than allowed for suspending the toast notification. The toast notification is shown.");
}
}

if (download_update)
{
Logger::trace(L"Downloading installer for a new version");
Expand Down Expand Up @@ -168,6 +189,14 @@ void ProcessNewVersionInfo(const github_version_info& version_info,

void PeriodicUpdateWorker()
{
// Check if periodic update check is disabled by GPO.
// This policy code is implemented but not active. It is for later usage in PT version after 1.0 release.
//if (powertoys_gpo::getDisablePeriodicUpdateCheckValue() == powertoys_gpo::gpo_rule_configured_enabled)
//{
// Logger::info(L"Initialization of periodic update checks stopped. Periodic update checks are disabled by GPO.");
// return;
//}

for (;;)
{
auto state = UpdateState::read();
Expand All @@ -184,7 +213,14 @@ void PeriodicUpdateWorker()

std::this_thread::sleep_for(std::chrono::minutes{ sleep_minutes_till_next_update });

const bool download_update = !IsMeteredConnection() && get_general_settings().downloadUpdatesAutomatically;
// Auto download setting.
bool download_update = !IsMeteredConnection() && get_general_settings().downloadUpdatesAutomatically;
if (powertoys_gpo::getDisableAutomaticUpdateDownloadValue() == powertoys_gpo::gpo_rule_configured_enabled)
{
Logger::info(L"Automatic download of updates is disabled by GPO.");
download_update = false;
}

bool version_info_obtained = false;
try
{
Expand Down Expand Up @@ -230,7 +266,15 @@ void CheckForUpdatesCallback()
new_version_info = version_up_to_date{};
Logger::error(L"Couldn't obtain version info from github: {}", new_version_info.error());
}
const bool download_update = !IsMeteredConnection() && get_general_settings().downloadUpdatesAutomatically;

// Auto download setting
bool download_update = !IsMeteredConnection() && get_general_settings().downloadUpdatesAutomatically;
if (powertoys_gpo::getDisableAutomaticUpdateDownloadValue() == powertoys_gpo::gpo_rule_configured_enabled)
{
Logger::info(L"Automatic download of updates is disabled by GPO.");
download_update = false;
}

ProcessNewVersionInfo(*new_version_info, state, download_update, false);
UpdateState::store([&](UpdateState& v) {
v = std::move(state);
Expand Down
3 changes: 3 additions & 0 deletions src/settings-ui/Settings.UI/Strings/en-us/Resources.resw
Expand Up @@ -3040,4 +3040,7 @@ Activate by holding the key for the character you want to add an accent to, then
<value>Enable Mouse Jump</value>
<comment>"Mouse Jump" is the name of the utility.</comment>
</data>
<data name="GPO_AutoDownloadUpdatesIsDisabled.Title" xml:space="preserve">
<value>The system administrator has disabled the automatic download of updates.</value>
</data>
</root>
35 changes: 25 additions & 10 deletions src/settings-ui/Settings.UI/ViewModels/GeneralViewModel.cs
Expand Up @@ -142,6 +142,7 @@ public GeneralViewModel(ISettingsRepository<GeneralSettings> settingsRepository,
_updateCheckedDate = UpdatingSettingsConfig.LastCheckedDateLocalized;

_experimentationIsGpoDisallowed = GPOWrapper.GetAllowExperimentationValue() == GpoRuleConfigured.Disabled;
_autoDownloadUpdatesIsGpoDisabled = GPOWrapper.GetDisableAutomaticUpdateDownloadValue() == GpoRuleConfigured.Enabled;

if (dispatcherAction != null)
{
Expand All @@ -156,6 +157,7 @@ public GeneralViewModel(ISettingsRepository<GeneralSettings> settingsRepository,
private int _themeIndex;

private bool _autoDownloadUpdates;
private bool _autoDownloadUpdatesIsGpoDisabled;
private bool _enableExperimentation;
private bool _experimentationIsGpoDisallowed;

Expand Down Expand Up @@ -272,11 +274,20 @@ public bool IsAdmin
}
}

// Are we running a dev build? (Please note that we verify this in the code that gets the newest version from GitHub too.)
public static bool AutoUpdatesDisabledOnDevBuild
{
get
{
return Helper.GetProductVersion() == "v0.0.1";
}
}

public bool AutoDownloadUpdates
{
get
{
return _autoDownloadUpdates;
return _autoDownloadUpdates && !_autoDownloadUpdatesIsGpoDisabled;
}

set
Expand All @@ -290,6 +301,18 @@ public bool AutoDownloadUpdates
}
}

public bool IsAutoDownloadUpdatesCardEnabled
{
get => !AutoUpdatesDisabledOnDevBuild && !_autoDownloadUpdatesIsGpoDisabled;
}

// The settings card is hidden for users who are not a member of the Administrators group and in this case the GPO info should be hidden too.
// We hide it, because we don't want a normal user to enable the setting. He can't install the updates.
public bool ShowAutoDownloadUpdatesGpoInformation
{
get => _isAdmin && _autoDownloadUpdatesIsGpoDisabled;
}

public bool EnableExperimentation
{
get
Expand All @@ -313,14 +336,6 @@ public bool IsExperimentationGpoDisallowed
get => _experimentationIsGpoDisallowed;
}

public static bool AutoUpdatesEnabled
{
get
{
return Helper.GetProductVersion() != "v0.0.1";
}
}

public string SettingsBackupAndRestoreDir
{
get
Expand Down Expand Up @@ -659,7 +674,7 @@ public bool IsDownloadAllowed
{
get
{
return AutoUpdatesEnabled && !IsNewVersionDownloading;
return !AutoUpdatesDisabledOnDevBuild && !IsNewVersionDownloading;
}
}

Expand Down

0 comments on commit 6750442

Please sign in to comment.