diff --git a/Source/NETworkManager.Settings/PolicyInfo.cs b/Source/NETworkManager.Settings/PolicyInfo.cs
index 7b9b64a6a0..2f17ee8abf 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..76961df19b 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;
@@ -77,6 +78,50 @@ public static class SettingsManager
/// Path to the settings folder.
public static string GetSettingsFolderLocation()
{
+ // Policy override takes precedence
+ if (!string.IsNullOrWhiteSpace(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 ArgumentException, NotSupportedException, or SecurityException if the path is invalid
+ 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)
+ {
+ 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);
+ }
+ catch (SecurityException ex)
+ {
+ Log.Error($"Insufficient permissions to access policy-provided SettingsFolderLocation: {policyPath}. Falling back to default location.", ex);
+ }
+ }
+ }
+
+ // 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/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..8d20d869d5 100644
--- a/Source/NETworkManager/Views/SettingsSettingsView.xaml
+++ b/Source/NETworkManager/Views/SettingsSettingsView.xaml
@@ -7,30 +7,56 @@
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}">
+
+
+
-
+
diff --git a/Website/docs/settings/settings.md b/Website/docs/settings/settings.md
index 32342b3d6e..c08cf47f3d 100644
--- a/Website/docs/settings/settings.md
+++ b/Website/docs/settings/settings.md
@@ -17,6 +17,26 @@ Folder where the application settings are stored.
| Setup / Archiv | `%UserProfile%\Documents\NETworkManager\Settings` |
| Portable | `\Settings` |
+:::info System-Wide Policy
+
+This setting can be controlled by administrators using a system-wide policy. See [System-Wide Policies](../system-wide-policies.md) for more information.
+
+**Policy Property:** `SettingsFolderLocation`
+
+**Values:**
+- Absolute path (e.g., `C:\\CustomPath\\NETworkManager\\Settings`) - Force a custom settings folder location for all users
+- Omit the property - Allow the default location logic to apply (portable vs. non-portable)
+
+**Example:**
+
+```json
+{
+ "SettingsFolderLocation": "C:\\CustomPath\\NETworkManager\\Settings"
+}
+```
+
+:::
+
:::note
**Recommendation**
diff --git a/Website/docs/system-wide-policies.md b/Website/docs/system-wide-policies.md
index d8ef644453..d6aa0a5c9d 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:\\CustomPath\\NETworkManager\\Settings"
}
```