From bd499f44e72fc03a2d47a550e677509cf0d43c10 Mon Sep 17 00:00:00 2001
From: Kristen Schau <47155823+krschau@users.noreply.github.com>
Date: Mon, 30 Sep 2024 12:04:57 -0400
Subject: [PATCH 1/6] Add GPOHelper
---
common/Helpers/GPOHelper.cs | 82 +++++++++++++++++++++++++++++++++++++
1 file changed, 82 insertions(+)
create mode 100644 common/Helpers/GPOHelper.cs
diff --git a/common/Helpers/GPOHelper.cs b/common/Helpers/GPOHelper.cs
new file mode 100644
index 0000000000..64e7fd05dc
--- /dev/null
+++ b/common/Helpers/GPOHelper.cs
@@ -0,0 +1,82 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Microsoft.Win32;
+
+namespace DevHome.Common.Helpers;
+
+public class GPOHelper
+{
+ private enum GpoRuleConfigured
+ {
+ WrongValue = -3, // The policy is set to an unrecognized value
+ Unavailable = -2, // Couldn't access registry
+ NotConfigured = -1, // Policy is not configured
+ Disabled = 0, // Policy is disabled
+ Enabled = 1, // Policy is enabled
+ }
+
+ // Registry path where gpo policy values are stored
+ private const string PoliciesScopeMachine = "HKEY_LOCAL_MACHINE";
+ private const string PoliciesPath = @"\SOFTWARE\Policies\Microsoft\Windows\DevHome";
+
+ // Registry value names
+ private const string PolicyConfigureEnabledDevHome = "ConfigureEnabledDevHome";
+
+ private static GpoRuleConfigured GetConfiguredValue(string registryValueName)
+ {
+ try
+ {
+ var rawValue = Registry.GetValue(
+ keyName: PoliciesScopeMachine + PoliciesPath,
+ valueName: registryValueName,
+ defaultValue: GpoRuleConfigured.NotConfigured);
+
+ // Value will be null if the subkey specified by keyName does not exist.
+ if (rawValue == null)
+ {
+ return GpoRuleConfigured.NotConfigured;
+ }
+ else if (rawValue is not int)
+ {
+ return GpoRuleConfigured.WrongValue;
+ }
+ else
+ {
+ return (GpoRuleConfigured)rawValue;
+ }
+ }
+ catch (System.Security.SecurityException)
+ {
+ // The user does not have the permissions required to read from the registry key.
+ return GpoRuleConfigured.Unavailable;
+ }
+ catch (System.IO.IOException)
+ {
+ // The RegistryKey that contains the specified value has been marked for deletion.
+ return GpoRuleConfigured.Unavailable;
+ }
+ catch (System.ArgumentException)
+ {
+ // keyName does not begin with a valid registry root.
+ return GpoRuleConfigured.NotConfigured;
+ }
+ }
+
+ private static bool EvaluateConfiguredValue(string registryValueName, GpoRuleConfigured defaultValue)
+ {
+ var configuredValue = GetConfiguredValue(registryValueName);
+ if (configuredValue < 0)
+ {
+ configuredValue = defaultValue;
+ }
+
+ return configuredValue == GpoRuleConfigured.Enabled;
+ }
+
+ public static bool GetConfiguredEnabledDevHomeValue()
+ {
+ var defaultValue = GpoRuleConfigured.Enabled;
+ return EvaluateConfiguredValue(PolicyConfigureEnabledDevHome, defaultValue);
+ }
+}
From 357ac57e46829ba3ee71071a7f3b58f637686a20 Mon Sep 17 00:00:00 2001
From: Kristen Schau <47155823+krschau@users.noreply.github.com>
Date: Tue, 1 Oct 2024 15:40:53 -0400
Subject: [PATCH 2/6] Change PoliciesPath
---
common/Helpers/GPOHelper.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/common/Helpers/GPOHelper.cs b/common/Helpers/GPOHelper.cs
index 64e7fd05dc..2f89e6555d 100644
--- a/common/Helpers/GPOHelper.cs
+++ b/common/Helpers/GPOHelper.cs
@@ -18,7 +18,7 @@ private enum GpoRuleConfigured
// Registry path where gpo policy values are stored
private const string PoliciesScopeMachine = "HKEY_LOCAL_MACHINE";
- private const string PoliciesPath = @"\SOFTWARE\Policies\Microsoft\Windows\DevHome";
+ private const string PoliciesPath = @"\SOFTWARE\Policies\DevHome";
// Registry value names
private const string PolicyConfigureEnabledDevHome = "ConfigureEnabledDevHome";
From 578be73a7ee4e9deaa3082d5a789cf7e0276e68f Mon Sep 17 00:00:00 2001
From: Kristen Schau <47155823+krschau@users.noreply.github.com>
Date: Mon, 30 Sep 2024 12:28:06 -0400
Subject: [PATCH 3/6] Make all of Dev Home disablable by GPO
---
src/Strings/en-us/Resources.resw | 6 ++++++
src/ViewModels/ShellViewModel.cs | 9 +++++++++
src/Views/ShellPage.xaml | 22 +++++++++++++++++++++-
3 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/src/Strings/en-us/Resources.resw b/src/Strings/en-us/Resources.resw
index f99d469a63..d2d5a36b83 100644
--- a/src/Strings/en-us/Resources.resw
+++ b/src/Strings/en-us/Resources.resw
@@ -286,4 +286,10 @@
SSH Keychain widget preview image
+
+ Dev Home is blocked
+
+
+ Check with your IT or System Administrator for support.
+
\ No newline at end of file
diff --git a/src/ViewModels/ShellViewModel.cs b/src/ViewModels/ShellViewModel.cs
index 717ce6022c..8853a6a8fe 100644
--- a/src/ViewModels/ShellViewModel.cs
+++ b/src/ViewModels/ShellViewModel.cs
@@ -35,6 +35,9 @@ public partial class ShellViewModel : ObservableObject
[ObservableProperty]
private InfoBarModel _shellInfoBarModel = new();
+ [ObservableProperty]
+ private bool _isDevHomeGPOEnabled;
+
public ShellViewModel(
INavigationService navigationService,
INavigationViewService navigationViewService,
@@ -59,6 +62,12 @@ public void OnLoaded()
Log.Information($"Activated with kind {activationKind}");
TelemetryFactory.Get().Log("DevHome_Shell_Loaded_Event", LogLevel.Critical, new DevHomeShellLoadedEvent(activationKind));
+ IsDevHomeGPOEnabled = GPOHelper.GetConfiguredEnabledDevHomeValue();
+ if (!IsDevHomeGPOEnabled)
+ {
+ return;
+ }
+
switch (activationKind)
{
case ExtendedActivationKind.File:
diff --git a/src/Views/ShellPage.xaml b/src/Views/ShellPage.xaml
index 1775d90694..d52fe57698 100644
--- a/src/Views/ShellPage.xaml
+++ b/src/Views/ShellPage.xaml
@@ -6,7 +6,11 @@
xmlns:behaviors="using:DevHome.Common.Behaviors"
xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:windows="using:DevHome.Common.Windows"
+ xmlns:converters="using:CommunityToolkit.WinUI.Converters"
Loaded="OnLoaded">
+
+
+
@@ -30,7 +34,8 @@
OpenPaneLength="350"
ExpandedModeThresholdWidth="1280"
DisplayModeChanged="NavigationViewControl_DisplayModeChanged"
- Header="{x:Bind ((ContentControl)ViewModel.Selected).Content, Mode=OneWay}">
+ Header="{x:Bind ((ContentControl)ViewModel.Selected).Content, Mode=OneWay}"
+ Visibility="{x:Bind ViewModel.IsDevHomeGPOEnabled, Mode=OneWay}">
@@ -115,6 +120,21 @@
+
+
+
+
+
From 7619066148278b3e035c28933e556b6fedadec64 Mon Sep 17 00:00:00 2001
From: Kristen Schau <47155823+krschau@users.noreply.github.com>
Date: Fri, 18 Oct 2024 12:44:43 -0400
Subject: [PATCH 4/6] Configuration files
---
src/gpo/assets/DevHome.admx | 30 +++++++++++++++++++++++++++++
src/gpo/assets/en-US/DevHome.adml | 32 +++++++++++++++++++++++++++++++
2 files changed, 62 insertions(+)
create mode 100644 src/gpo/assets/DevHome.admx
create mode 100644 src/gpo/assets/en-US/DevHome.adml
diff --git a/src/gpo/assets/DevHome.admx b/src/gpo/assets/DevHome.admx
new file mode 100644
index 0000000000..6325fffa8a
--- /dev/null
+++ b/src/gpo/assets/DevHome.admx
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/gpo/assets/en-US/DevHome.adml b/src/gpo/assets/en-US/DevHome.adml
new file mode 100644
index 0000000000..92d7e07673
--- /dev/null
+++ b/src/gpo/assets/en-US/DevHome.adml
@@ -0,0 +1,32 @@
+
+
+
+ Dev Home
+ Dev Home
+
+
+ Microsoft Dev Home
+
+ Dev Home version 0.1900.* or later
+
+ This policy configures the enabled state for Dev Home.
+
+If you enable this setting, Dev Home will be always enabled and the user won't be able to disable it.
+
+If you disable this setting, Dev Home 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 Dev Home.
+
+This policy will override any enabled state policies for individual Dev Home features.
+
+
+ Configure Dev Home enabled state
+
+
+
+
+
+
+
+
From 8519825588107df581ae8899449812485ab049e9 Mon Sep 17 00:00:00 2001
From: Kristen Schau <47155823+krschau@users.noreply.github.com>
Date: Fri, 1 Nov 2024 11:12:55 -0400
Subject: [PATCH 5/6] fix administrative templates
---
src/gpo/assets/DevHome.admx | 2 ++
src/gpo/assets/en-US/DevHome.adml | 3 ---
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/gpo/assets/DevHome.admx b/src/gpo/assets/DevHome.admx
index 6325fffa8a..e540dc25f8 100644
--- a/src/gpo/assets/DevHome.admx
+++ b/src/gpo/assets/DevHome.admx
@@ -13,6 +13,8 @@
+
+
diff --git a/src/gpo/assets/en-US/DevHome.adml b/src/gpo/assets/en-US/DevHome.adml
index 92d7e07673..e6414b8468 100644
--- a/src/gpo/assets/en-US/DevHome.adml
+++ b/src/gpo/assets/en-US/DevHome.adml
@@ -24,9 +24,6 @@ This policy will override any enabled state policies for individual Dev Home fea
Configure Dev Home enabled state
-
-
-
From a583bab148aa6337ec2fa85cf9dd9b881c5b58c0 Mon Sep 17 00:00:00 2001
From: Kristen Schau <47155823+krschau@users.noreply.github.com>
Date: Fri, 8 Nov 2024 10:48:45 -0500
Subject: [PATCH 6/6] add logging, handle unspecified case differently
---
common/Helpers/GPOHelper.cs | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/common/Helpers/GPOHelper.cs b/common/Helpers/GPOHelper.cs
index 2f89e6555d..53aec7ed8c 100644
--- a/common/Helpers/GPOHelper.cs
+++ b/common/Helpers/GPOHelper.cs
@@ -2,11 +2,14 @@
// Licensed under the MIT License.
using Microsoft.Win32;
+using Serilog;
namespace DevHome.Common.Helpers;
public class GPOHelper
{
+ private static readonly ILogger _log = Log.ForContext("SourceContext", nameof(GPOHelper));
+
private enum GpoRuleConfigured
{
WrongValue = -3, // The policy is set to an unrecognized value
@@ -32,12 +35,14 @@ private static GpoRuleConfigured GetConfiguredValue(string registryValueName)
valueName: registryValueName,
defaultValue: GpoRuleConfigured.NotConfigured);
+ _log.Error($"Registry value {registryValueName} set to {rawValue}");
+
// Value will be null if the subkey specified by keyName does not exist.
if (rawValue == null)
{
return GpoRuleConfigured.NotConfigured;
}
- else if (rawValue is not int)
+ else if (rawValue is not int && rawValue is not GpoRuleConfigured)
{
return GpoRuleConfigured.WrongValue;
}
@@ -68,6 +73,7 @@ private static bool EvaluateConfiguredValue(string registryValueName, GpoRuleCon
var configuredValue = GetConfiguredValue(registryValueName);
if (configuredValue < 0)
{
+ _log.Error($"Registry value {registryValueName} set to {configuredValue}, using default {defaultValue} instead.");
configuredValue = defaultValue;
}