From 24ad9e15c681cc25236d7e45e06e1abf65f041f5 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 9 Feb 2026 20:08:29 +0000
Subject: [PATCH 01/10] Initial plan
From 122558723af9a278b7e7cf33f6dc6696e1802c62 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 9 Feb 2026 20:11:14 +0000
Subject: [PATCH 02/10] Add policy to override SettingsFolder Location
Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com>
---
Source/NETworkManager.Settings/PolicyInfo.cs | 3 ++
.../NETworkManager.Settings/PolicyManager.cs | 1 +
.../SettingsManager.cs | 5 ++
.../config.json.example | 3 +-
Website/docs/settings/settings.md | 4 ++
Website/docs/system-wide-policies.md | 49 ++++++++++++++++++-
6 files changed, 63 insertions(+), 2 deletions(-)
diff --git a/Source/NETworkManager.Settings/PolicyInfo.cs b/Source/NETworkManager.Settings/PolicyInfo.cs
index 7b9b64a6a0..0a7f512ba3 100644
--- a/Source/NETworkManager.Settings/PolicyInfo.cs
+++ b/Source/NETworkManager.Settings/PolicyInfo.cs
@@ -10,4 +10,7 @@ public class PolicyInfo
{
[JsonPropertyName("Update_CheckForUpdatesAtStartup")]
public bool? Update_CheckForUpdatesAtStartup { get; set; }
+
+ [JsonPropertyName("SettingsFolderLocation")]
+ public string SettingsFolderLocation { get; set; }
}
diff --git a/Source/NETworkManager.Settings/PolicyManager.cs b/Source/NETworkManager.Settings/PolicyManager.cs
index 7dd762c8de..fc946620bc 100644
--- a/Source/NETworkManager.Settings/PolicyManager.cs
+++ b/Source/NETworkManager.Settings/PolicyManager.cs
@@ -83,6 +83,7 @@ public static void Load()
// Log enabled settings
Log.Info($"System-wide policy - Update_CheckForUpdatesAtStartup: {Current.Update_CheckForUpdatesAtStartup?.ToString() ?? "Not set"}");
+ Log.Info($"System-wide policy - SettingsFolderLocation: {Current.SettingsFolderLocation ?? "Not set"}");
}
}
catch (Exception ex)
diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs
index 29a140218e..83241bde51 100644
--- a/Source/NETworkManager.Settings/SettingsManager.cs
+++ b/Source/NETworkManager.Settings/SettingsManager.cs
@@ -77,6 +77,11 @@ public static class SettingsManager
/// Path to the settings folder.
public static string GetSettingsFolderLocation()
{
+ // Policy override takes precedence
+ if (!string.IsNullOrWhiteSpace(PolicyManager.Current?.SettingsFolderLocation))
+ return PolicyManager.Current.SettingsFolderLocation;
+
+ // Fall back to existing logic
return ConfigurationManager.Current.IsPortable
? Path.Combine(AssemblyManager.Current.Location, SettingsFolderName)
: Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
diff --git a/Source/NETworkManager.Settings/config.json.example b/Source/NETworkManager.Settings/config.json.example
index 8ca2bf05b3..0a47ffa700 100644
--- a/Source/NETworkManager.Settings/config.json.example
+++ b/Source/NETworkManager.Settings/config.json.example
@@ -1,3 +1,4 @@
{
- "Update_CheckForUpdatesAtStartup": false
+ "Update_CheckForUpdatesAtStartup": false,
+ "SettingsFolderLocation": "C:\\CustomPath\\NETworkManager\\Settings"
}
\ No newline at end of file
diff --git a/Website/docs/settings/settings.md b/Website/docs/settings/settings.md
index 32342b3d6e..f4404603c2 100644
--- a/Website/docs/settings/settings.md
+++ b/Website/docs/settings/settings.md
@@ -17,6 +17,10 @@ Folder where the application settings are stored.
| Setup / Archiv | `%UserProfile%\Documents\NETworkManager\Settings` |
| Portable | `\Settings` |
+**Policy Override**: `SettingsFolderLocation`
+
+This setting can be overridden by a [system-wide policy](../system-wide-policies.md). When a policy is configured, it takes precedence over the default location, allowing administrators to specify a custom settings folder path for all users.
+
:::note
**Recommendation**
diff --git a/Website/docs/system-wide-policies.md b/Website/docs/system-wide-policies.md
index d8ef644453..56e85d6b5d 100644
--- a/Website/docs/system-wide-policies.md
+++ b/Website/docs/system-wide-policies.md
@@ -36,7 +36,8 @@ The `config.json` file uses a simple JSON structure to define policy values. An
```json
{
- "Update_CheckForUpdatesAtStartup": false
+ "Update_CheckForUpdatesAtStartup": false,
+ "SettingsFolderLocation": "C:\\ProgramData\\NETworkManager\\Settings"
}
```
@@ -97,6 +98,52 @@ Ensure the `config.json` file has appropriate permissions so that regular users
- Verify the value is a boolean (`true` or `false`), not a string (`"true"` or `"false"`)
- Check that there are no syntax errors in the JSON file
+## Available Policies
+
+### Update_CheckForUpdatesAtStartup
+
+Control whether the application checks for updates at startup.
+
+**Type**: `Boolean` (true/false)
+
+**Default**: User setting applies
+
+**Example**:
+```json
+{
+ "Update_CheckForUpdatesAtStartup": false
+}
+```
+
+See [Check for updates at startup](./settings/update.md#check-for-updates-at-startup) for more details.
+
+### SettingsFolderLocation
+
+Override the default location where application settings are stored.
+
+**Type**: `String` (absolute path)
+
+**Default**: User Documents folder or portable location
+
+**Example**:
+```json
+{
+ "SettingsFolderLocation": "C:\\ProgramData\\NETworkManager\\Settings"
+}
+```
+
+See [Location](./settings/settings.md#location) for more details.
+
+:::warning
+
+When configuring a custom settings folder location, ensure:
+- The path uses double backslashes (`\\`) in JSON format
+- The application has read/write permissions to the specified directory
+- The directory exists or the application has permissions to create it
+- All users have appropriate access to the folder if using a shared location
+
+:::
+
## Future Policies
Additional policy options will be added in future releases to provide more granular control over application behavior. If you have specific requirements for system-wide policies in your organization, please submit a feature request via the [GitHub issue tracker](https://github.com/BornToBeRoot/NETworkManager/issues/new/choose).
From bf0c78e8df2ec8d14ab38a4e760ef18d194b3419 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 9 Feb 2026 20:13:00 +0000
Subject: [PATCH 03/10] Add validation for policy-provided
SettingsFolderLocation
Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com>
---
Source/NETworkManager.Settings/PolicyInfo.cs | 2 +-
.../SettingsManager.cs | 24 ++++++++++++++++++-
Website/docs/system-wide-policies.md | 4 ++++
3 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/Source/NETworkManager.Settings/PolicyInfo.cs b/Source/NETworkManager.Settings/PolicyInfo.cs
index 0a7f512ba3..2f17ee8abf 100644
--- a/Source/NETworkManager.Settings/PolicyInfo.cs
+++ b/Source/NETworkManager.Settings/PolicyInfo.cs
@@ -12,5 +12,5 @@ public class PolicyInfo
public bool? Update_CheckForUpdatesAtStartup { get; set; }
[JsonPropertyName("SettingsFolderLocation")]
- public string SettingsFolderLocation { get; set; }
+ public string? SettingsFolderLocation { get; set; }
}
diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs
index 83241bde51..1343bf2c81 100644
--- a/Source/NETworkManager.Settings/SettingsManager.cs
+++ b/Source/NETworkManager.Settings/SettingsManager.cs
@@ -79,7 +79,29 @@ public static string GetSettingsFolderLocation()
{
// Policy override takes precedence
if (!string.IsNullOrWhiteSpace(PolicyManager.Current?.SettingsFolderLocation))
- return PolicyManager.Current.SettingsFolderLocation;
+ {
+ var policyPath = PolicyManager.Current.SettingsFolderLocation;
+
+ // Validate that the policy-provided path is rooted (absolute)
+ if (!Path.IsPathRooted(policyPath))
+ {
+ Log.Error($"Policy-provided SettingsFolderLocation is not an absolute path: {policyPath}. Falling back to default location.");
+ }
+ else
+ {
+ // Validate that the path doesn't contain invalid characters
+ try
+ {
+ // This will throw if the path contains invalid characters
+ _ = Path.GetFullPath(policyPath);
+ return policyPath;
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"Policy-provided SettingsFolderLocation contains invalid characters: {policyPath}. Falling back to default location.", ex);
+ }
+ }
+ }
// Fall back to existing logic
return ConfigurationManager.Current.IsPortable
diff --git a/Website/docs/system-wide-policies.md b/Website/docs/system-wide-policies.md
index 56e85d6b5d..af3427efbe 100644
--- a/Website/docs/system-wide-policies.md
+++ b/Website/docs/system-wide-policies.md
@@ -137,11 +137,15 @@ See [Location](./settings/settings.md#location) for more details.
:::warning
When configuring a custom settings folder location, ensure:
+- The path **must be an absolute path** (e.g., `C:\\Path\\To\\Folder`, not `.\\RelativePath`)
- The path uses double backslashes (`\\`) in JSON format
+- The path does not contain invalid characters for the file system
- The application has read/write permissions to the specified directory
- The directory exists or the application has permissions to create it
- All users have appropriate access to the folder if using a shared location
+If the policy-provided path is invalid (not absolute or contains invalid characters), the application will log an error and fall back to the default location.
+
:::
## Future Policies
From 65e973245c5279bf8b68830adc75afb0a060df30 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 9 Feb 2026 20:13:45 +0000
Subject: [PATCH 04/10] Improve exception handling and documentation structure
Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com>
---
Source/NETworkManager.Settings/SettingsManager.cs | 8 ++++++--
Website/docs/system-wide-policies.md | 4 +++-
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs
index 1343bf2c81..f220b24587 100644
--- a/Source/NETworkManager.Settings/SettingsManager.cs
+++ b/Source/NETworkManager.Settings/SettingsManager.cs
@@ -92,14 +92,18 @@ public static string GetSettingsFolderLocation()
// Validate that the path doesn't contain invalid characters
try
{
- // This will throw if the path contains invalid characters
+ // This will throw ArgumentException or NotSupportedException if the path contains invalid characters
_ = Path.GetFullPath(policyPath);
return policyPath;
}
- catch (Exception ex)
+ catch (ArgumentException ex)
{
Log.Error($"Policy-provided SettingsFolderLocation contains invalid characters: {policyPath}. Falling back to default location.", ex);
}
+ catch (NotSupportedException ex)
+ {
+ Log.Error($"Policy-provided SettingsFolderLocation format is not supported: {policyPath}. Falling back to default location.", ex);
+ }
}
}
diff --git a/Website/docs/system-wide-policies.md b/Website/docs/system-wide-policies.md
index af3427efbe..c9126a5d51 100644
--- a/Website/docs/system-wide-policies.md
+++ b/Website/docs/system-wide-policies.md
@@ -32,7 +32,7 @@ The `config.json` file uses a simple JSON structure to define policy values. An
```
-**Example:**
+**Example with available policies:**
```json
{
@@ -41,6 +41,8 @@ The `config.json` file uses a simple JSON structure to define policy values. An
}
```
+For a complete list of available policies, see the [Available Policies](#available-policies) section below.
+
Property names generally follow the pattern `Section_SettingName` (see each setting's documentation). Ensure values use the correct JSON type (boolean, string, number, etc.).
:::note
From 114f86ce82bdeac838d65bfb6e846f19af996768 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 9 Feb 2026 20:14:31 +0000
Subject: [PATCH 05/10] Add SecurityException handling and fix documentation
formatting
Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com>
---
Source/NETworkManager.Settings/SettingsManager.cs | 6 +++++-
Website/docs/system-wide-policies.md | 2 +-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs
index f220b24587..6a8c399a9a 100644
--- a/Source/NETworkManager.Settings/SettingsManager.cs
+++ b/Source/NETworkManager.Settings/SettingsManager.cs
@@ -92,7 +92,7 @@ public static string GetSettingsFolderLocation()
// Validate that the path doesn't contain invalid characters
try
{
- // This will throw ArgumentException or NotSupportedException if the path contains invalid characters
+ // This will throw ArgumentException, NotSupportedException, or SecurityException if the path is invalid
_ = Path.GetFullPath(policyPath);
return policyPath;
}
@@ -104,6 +104,10 @@ public static string GetSettingsFolderLocation()
{
Log.Error($"Policy-provided SettingsFolderLocation format is not supported: {policyPath}. Falling back to default location.", ex);
}
+ catch (System.Security.SecurityException ex)
+ {
+ Log.Error($"Insufficient permissions to access policy-provided SettingsFolderLocation: {policyPath}. Falling back to default location.", ex);
+ }
}
}
diff --git a/Website/docs/system-wide-policies.md b/Website/docs/system-wide-policies.md
index c9126a5d51..be39de8f05 100644
--- a/Website/docs/system-wide-policies.md
+++ b/Website/docs/system-wide-policies.md
@@ -32,7 +32,7 @@ The `config.json` file uses a simple JSON structure to define policy values. An
```
-**Example with available policies:**
+**Example:**
```json
{
From 92530c7e71484a91f8580b9bb9171a230ad95ae7 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 9 Feb 2026 20:15:20 +0000
Subject: [PATCH 06/10] Fix using statement and clarify path format
documentation
Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com>
---
Source/NETworkManager.Settings/SettingsManager.cs | 3 ++-
Website/docs/system-wide-policies.md | 4 ++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs
index 6a8c399a9a..343eac7ec2 100644
--- a/Source/NETworkManager.Settings/SettingsManager.cs
+++ b/Source/NETworkManager.Settings/SettingsManager.cs
@@ -5,6 +5,7 @@
using System;
using System.IO;
using System.Linq;
+using System.Security;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Xml.Serialization;
@@ -104,7 +105,7 @@ public static string GetSettingsFolderLocation()
{
Log.Error($"Policy-provided SettingsFolderLocation format is not supported: {policyPath}. Falling back to default location.", ex);
}
- catch (System.Security.SecurityException ex)
+ catch (SecurityException ex)
{
Log.Error($"Insufficient permissions to access policy-provided SettingsFolderLocation: {policyPath}. Falling back to default location.", ex);
}
diff --git a/Website/docs/system-wide-policies.md b/Website/docs/system-wide-policies.md
index be39de8f05..87aa09f229 100644
--- a/Website/docs/system-wide-policies.md
+++ b/Website/docs/system-wide-policies.md
@@ -139,8 +139,8 @@ See [Location](./settings/settings.md#location) for more details.
:::warning
When configuring a custom settings folder location, ensure:
-- The path **must be an absolute path** (e.g., `C:\\Path\\To\\Folder`, not `.\\RelativePath`)
-- The path uses double backslashes (`\\`) in JSON format
+- The path **must be an absolute path** (e.g., `C:\\Path\\To\\Folder` or `C:/Path/To/Folder`, not `.\\RelativePath`)
+- For Windows paths, use either double backslashes (`\\`) or forward slashes (`/`) in JSON format (both `C:\\Path\\Folder` and `C:/Path/Folder` are valid)
- The path does not contain invalid characters for the file system
- The application has read/write permissions to the specified directory
- The directory exists or the application has permissions to create it
From 41633bf1066accc33231f47e72e12b78f692d218 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 9 Feb 2026 20:16:04 +0000
Subject: [PATCH 07/10] Use consistent example path in documentation
Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com>
---
Website/docs/system-wide-policies.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Website/docs/system-wide-policies.md b/Website/docs/system-wide-policies.md
index 87aa09f229..c8c2861010 100644
--- a/Website/docs/system-wide-policies.md
+++ b/Website/docs/system-wide-policies.md
@@ -37,7 +37,7 @@ The `config.json` file uses a simple JSON structure to define policy values. An
```json
{
"Update_CheckForUpdatesAtStartup": false,
- "SettingsFolderLocation": "C:\\ProgramData\\NETworkManager\\Settings"
+ "SettingsFolderLocation": "C:\\CustomPath\\NETworkManager\\Settings"
}
```
From a58b7e091e6cbb75f4e2c31a87937b16c44388f4 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 9 Feb 2026 20:35:06 +0000
Subject: [PATCH 08/10] Address review feedback: validate directory, update
docs, add admin indicator
Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com>
---
.../SettingsManager.cs | 13 ++++-
.../ViewModels/SettingsSettingsViewModel.cs | 5 ++
.../Views/SettingsSettingsView.xaml | 15 ++++++
Website/docs/settings/settings.md | 20 +++++++-
Website/docs/system-wide-policies.md | 50 -------------------
5 files changed, 49 insertions(+), 54 deletions(-)
diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs
index 343eac7ec2..76961df19b 100644
--- a/Source/NETworkManager.Settings/SettingsManager.cs
+++ b/Source/NETworkManager.Settings/SettingsManager.cs
@@ -94,8 +94,17 @@ public static string GetSettingsFolderLocation()
try
{
// This will throw ArgumentException, NotSupportedException, or SecurityException if the path is invalid
- _ = Path.GetFullPath(policyPath);
- return policyPath;
+ var fullPath = Path.GetFullPath(policyPath);
+
+ // Check if the path is a directory (not a file)
+ if (File.Exists(fullPath))
+ {
+ Log.Error($"Policy-provided SettingsFolderLocation is a file, not a directory: {policyPath}. Falling back to default location.");
+ }
+ else
+ {
+ return fullPath;
+ }
}
catch (ArgumentException ex)
{
diff --git a/Source/NETworkManager/ViewModels/SettingsSettingsViewModel.cs b/Source/NETworkManager/ViewModels/SettingsSettingsViewModel.cs
index 330f98e21e..aa41762eb5 100644
--- a/Source/NETworkManager/ViewModels/SettingsSettingsViewModel.cs
+++ b/Source/NETworkManager/ViewModels/SettingsSettingsViewModel.cs
@@ -31,6 +31,11 @@ public string Location
}
}
+ ///
+ /// Gets whether the settings folder location is managed by system-wide policy.
+ ///
+ public bool IsLocationManagedByPolicy => !string.IsNullOrWhiteSpace(PolicyManager.Current?.SettingsFolderLocation);
+
private bool _isDailyBackupEnabled;
public bool IsDailyBackupEnabled
diff --git a/Source/NETworkManager/Views/SettingsSettingsView.xaml b/Source/NETworkManager/Views/SettingsSettingsView.xaml
index b51f7fe9e6..769491d08d 100644
--- a/Source/NETworkManager/Views/SettingsSettingsView.xaml
+++ b/Source/NETworkManager/Views/SettingsSettingsView.xaml
@@ -7,12 +7,27 @@
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:viewModels="clr-namespace:NETworkManager.ViewModels"
xmlns:localization="clr-namespace:NETworkManager.Localization.Resources;assembly=NETworkManager.Localization"
+ xmlns:converters="clr-namespace:NETworkManager.Converters;assembly=NETworkManager.Converters"
mc:Ignorable="d" Loaded="UserControl_Loaded"
d:DataContext="{d:DesignInstance viewModels:SettingsSettingsViewModel}">
+
+
+
+
+
+
+
+
+
+
+