diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt
index 2c780296c4..9974ab63ea 100644
--- a/.github/actions/spell-check/expect.txt
+++ b/.github/actions/spell-check/expect.txt
@@ -283,7 +283,6 @@ CLIPCHILDREN
CLIPSIBLINGS
Cloneable
clrcall
-clrcompression
Cls
CLSCTX
clsid
@@ -427,7 +426,6 @@ DCOM
dcommon
dcomp
dcompi
-DCompiler
DComposition
DCR
DCs
@@ -581,7 +579,6 @@ EFDD
EFE
EFFEFC
EFile
-egfile
ekus
emmintrin
Emoji
@@ -645,7 +642,6 @@ FAF
FAFD
fancymouse
fancyzone
-fancyzones
FANCYZONESDRAWLAYOUTTEST
FANCYZONESEDITOR
Farbraum
@@ -746,6 +742,7 @@ GNumber
google
gpedit
gpo
+GPOCA
GPT
gpu
graphql
@@ -893,7 +890,6 @@ IMAGERESIZEREXT
imageresizerinput
imageresizersettings
imagingdevices
-Imc
ime
imeutil
inetcpl
@@ -1449,7 +1445,6 @@ pinfo
pinvoke
pipename
PKBDLLHOOKSTRUCT
-Pkcs
PKEY
plib
PLK
@@ -1597,9 +1592,9 @@ REGFILTERPINS
REGISTERCLASSFAILED
REGISTRYHEADER
registrypath
-registryroot
registrypreview
REGISTRYPREVIEWEXT
+registryroot
regkey
REGPINTYPES
regroot
@@ -1851,7 +1846,6 @@ stdcpplatest
STDMETHODCALLTYPE
STDMETHODIMP
stefan
-stefansjfw
Stereolithography
STGM
STGMEDIUM
@@ -2211,7 +2205,6 @@ wox
wparam
wpf
wpfdepsjsonpath
-wpfgfx
wpftmp
wpr
wprp
diff --git a/doc/gpo/README.md b/doc/gpo/README.md
index 134679f147..351ed5a376 100644
--- a/doc/gpo/README.md
+++ b/doc/gpo/README.md
@@ -44,6 +44,15 @@ If this setting is not configured, experimentation is allowed.
### Installer and Updates
+#### Disable per-user installation
+
+This policy configures whether PowerToys per-user installation is allowed or not.
+
+If enabled, per-user installation is not allowed.
+
+If disabled or not configured, per-user installation is allowed.
+
+You can set this policy only as Computer policy.
#### Disable automatic downloads
This policy configures whether automatic downloads of available updates are disabled or not. (On metered connections updates are never downloaded.)
diff --git a/installer/PowerToysSetup/Product.wxs b/installer/PowerToysSetup/Product.wxs
index 6569f77162..8ed3729a45 100644
--- a/installer/PowerToysSetup/Product.wxs
+++ b/installer/PowerToysSetup/Product.wxs
@@ -148,6 +148,9 @@
NOT Installed and CREATESCHEDULEDTASK = 1
+
+ NOT Installed
+
NOT Installed
@@ -413,6 +416,13 @@
DllEntry="UnRegisterContextMenuPackagesCA"
/>
+
+
diff --git a/installer/PowerToysSetupCustomActions/CustomAction.cpp b/installer/PowerToysSetupCustomActions/CustomAction.cpp
index 52a22a96c8..e3faecded6 100644
--- a/installer/PowerToysSetupCustomActions/CustomAction.cpp
+++ b/installer/PowerToysSetupCustomActions/CustomAction.cpp
@@ -6,6 +6,7 @@
#include
#include "../../src/common/logger/logger.h"
+#include "../../src/common/utils/gpo.h"
#include "../../src/common/utils/MsiUtils.h"
#include "../../src/common/utils/modulesRegistry.h"
#include "../../src/common/updating/installer.h"
@@ -50,6 +51,33 @@ HRESULT getInstallFolder(MSIHANDLE hInstall, std::wstring& installationDir)
LExit:
return hr;
}
+
+UINT __stdcall CheckGPOCA(MSIHANDLE hInstall)
+{
+ HRESULT hr = S_OK;
+
+ hr = WcaInitialize(hInstall, "CheckGPOCA");
+ ExitOnFailure(hr, "Failed to initialize");
+
+ LPWSTR currentScope = nullptr;
+ hr = WcaGetProperty(L"InstallScope", ¤tScope);
+
+ if(std::wstring{ currentScope } == L"perUser")
+ {
+ if (powertoys_gpo::getDisablePerUserInstallationValue() == powertoys_gpo::gpo_rule_configured_enabled)
+ {
+ PMSIHANDLE hRecord = MsiCreateRecord(0);
+ MsiRecordSetString(hRecord, 0, TEXT("The system administrator has disabled per-user installation."));
+ MsiProcessMessage(hInstall, static_cast(INSTALLMESSAGE_ERROR + MB_OK), hRecord);
+ hr = E_ABORT;
+ }
+ }
+
+LExit:
+ UINT er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
+ return WcaFinalize(er);
+}
+
UINT __stdcall ApplyModulesRegistryChangeSetsCA(MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
diff --git a/installer/PowerToysSetupCustomActions/CustomAction.def b/installer/PowerToysSetupCustomActions/CustomAction.def
index 27d59b2fda..21f2547052 100644
--- a/installer/PowerToysSetupCustomActions/CustomAction.def
+++ b/installer/PowerToysSetupCustomActions/CustomAction.def
@@ -1,6 +1,7 @@
LIBRARY "PowerToysSetupCustomActions"
EXPORTS
+ CheckGPOCA
ApplyModulesRegistryChangeSetsCA
CreateScheduledTaskCA
CreateWinAppSDKHardlinksCA
diff --git a/src/common/utils/gpo.h b/src/common/utils/gpo.h
index 31563a2075..e105749812 100644
--- a/src/common/utils/gpo.h
+++ b/src/common/utils/gpo.h
@@ -51,6 +51,7 @@ namespace powertoys_gpo {
const std::wstring POLICY_CONFIGURE_ENABLED_REGISTRY_PREVIEW = L"ConfigureEnabledUtilityRegistryPreview";
// The registry value names for PowerToys installer and update policies.
+ const std::wstring POLICY_DISABLE_PER_USER_INSTALLATION = L"PerUserInstallationDisabled";
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";
@@ -260,6 +261,12 @@ namespace powertoys_gpo {
{
return getConfiguredValue(POLICY_CONFIGURE_ENABLED_REGISTRY_PREVIEW);
}
+
+ inline gpo_rule_configured_t getDisablePerUserInstallationValue()
+ {
+ return getConfiguredValue(POLICY_DISABLE_PER_USER_INSTALLATION);
+ }
+
inline gpo_rule_configured_t getDisableAutomaticUpdateDownloadValue()
{
return getConfiguredValue(POLICY_DISABLE_AUTOMATIC_UPDATE_DOWNLOAD);
diff --git a/src/gpo/assets/PowerToys.admx b/src/gpo/assets/PowerToys.admx
index e3f44a5118..c1b618425b 100644
--- a/src/gpo/assets/PowerToys.admx
+++ b/src/gpo/assets/PowerToys.admx
@@ -319,7 +319,17 @@
-
+
+
+
+
+
+
+
+
+
+
+
@@ -329,7 +339,7 @@
-
+
diff --git a/src/gpo/assets/en-US/PowerToys.adml b/src/gpo/assets/en-US/PowerToys.adml
index 915d61f6c9..a551c8b4ba 100644
--- a/src/gpo/assets/en-US/PowerToys.adml
+++ b/src/gpo/assets/en-US/PowerToys.adml
@@ -30,6 +30,12 @@ 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.
+
+ This policy configures whether per-user PowerToys installation is allowed or not.
+
+If enabled, per-user installation is not allowed.
+
+If disabled or not configured, per-user installation is allowed.
This policy configures whether automatic downloads of available updates are disabled or not. (On metered connections updates are never downloaded.)
@@ -87,9 +93,10 @@ If this setting is disabled, experimentation is not allowed.
Shortcut Guide: Configure enabled state
Video Conference Mute: Configure enabled state
- Disable automatic downloads
- Suspend Action Center notification for new updates
- Disable automatic update checks
+ Disable per-user installation
+ Disable automatic downloads
+ Suspend Action Center notification for new updates
+ Disable automatic update checks
Allow Experimentation