diff --git a/Source/NETworkManager.Localization/Resources/Strings.Designer.cs b/Source/NETworkManager.Localization/Resources/Strings.Designer.cs
index b57b12bff7..8fa04498df 100644
--- a/Source/NETworkManager.Localization/Resources/Strings.Designer.cs
+++ b/Source/NETworkManager.Localization/Resources/Strings.Designer.cs
@@ -9271,6 +9271,15 @@ public static string SettingsHaveBeenReset {
}
}
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die This setting is managed by your administrator. ähnelt.
+ ///
+ public static string SettingManagedByAdministrator {
+ get {
+ return ResourceManager.GetString("SettingManagedByAdministrator", resourceCulture);
+ }
+ }
+
///
/// Sucht eine lokalisierte Zeichenfolge, die Appearance ähnelt.
///
diff --git a/Source/NETworkManager.Localization/Resources/Strings.resx b/Source/NETworkManager.Localization/Resources/Strings.resx
index 3dd4967eaf..e4f0fef96e 100644
--- a/Source/NETworkManager.Localization/Resources/Strings.resx
+++ b/Source/NETworkManager.Localization/Resources/Strings.resx
@@ -3960,4 +3960,7 @@ If you click Cancel, the profile file will remain unencrypted.
Number of backups that are retained before the oldest one is deleted.
+
+ This setting is managed by your administrator.
+
\ No newline at end of file
diff --git a/Source/NETworkManager.Settings/NETworkManager.Settings.csproj b/Source/NETworkManager.Settings/NETworkManager.Settings.csproj
index eb78d87f4d..9d4f289bd3 100644
--- a/Source/NETworkManager.Settings/NETworkManager.Settings.csproj
+++ b/Source/NETworkManager.Settings/NETworkManager.Settings.csproj
@@ -22,6 +22,9 @@
+
+ PreserveNewest
+
PreserveNewest
Designer
diff --git a/Source/NETworkManager.Settings/PolicyInfo.cs b/Source/NETworkManager.Settings/PolicyInfo.cs
new file mode 100644
index 0000000000..a337c2e32c
--- /dev/null
+++ b/Source/NETworkManager.Settings/PolicyInfo.cs
@@ -0,0 +1,13 @@
+using System.Text.Json.Serialization;
+
+namespace NETworkManager.Settings;
+
+///
+/// Class that represents system-wide policies that override user settings.
+/// This configuration is loaded from a config.json file in the application directory.
+///
+public class PolicyInfo
+{
+ [JsonPropertyName("Update_CheckForUpdatesAtStartup")]
+ public bool? Update_CheckForUpdatesAtStartup { get; set; }
+}
diff --git a/Source/NETworkManager.Settings/PolicyManager.cs b/Source/NETworkManager.Settings/PolicyManager.cs
new file mode 100644
index 0000000000..f97aa95376
--- /dev/null
+++ b/Source/NETworkManager.Settings/PolicyManager.cs
@@ -0,0 +1,102 @@
+using log4net;
+using System;
+using System.IO;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace NETworkManager.Settings;
+
+///
+/// Manager for system-wide policies that are loaded from a config.json file
+/// in the application directory. These policies override user settings.
+///
+public static class PolicyManager
+{
+ #region Variables
+
+ ///
+ /// Logger for logging.
+ ///
+ private static readonly ILog Log = LogManager.GetLogger(typeof(PolicyManager));
+
+ ///
+ /// Config file name.
+ ///
+ private static string ConfigFileName => "config.json";
+
+ ///
+ /// System-wide policies that are currently loaded.
+ ///
+ public static PolicyInfo Current { get; private set; }
+
+ ///
+ /// JSON serializer options for consistent serialization/deserialization.
+ ///
+ private static readonly JsonSerializerOptions JsonOptions = new()
+ {
+ WriteIndented = true,
+ PropertyNameCaseInsensitive = true,
+ DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
+ Converters = { new JsonStringEnumConverter() }
+ };
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Method to get the config file path in the application directory.
+ ///
+ /// Config file path.
+ private static string GetConfigFilePath()
+ {
+ return Path.Combine(AssemblyManager.Current.Location, ConfigFileName);
+ }
+
+ ///
+ /// Method to load the system-wide policies from config.json file in the application directory.
+ ///
+ public static void Load()
+ {
+ var filePath = GetConfigFilePath();
+
+ // Check if config file exists
+ if (File.Exists(filePath))
+ {
+ try
+ {
+ Log.Info($"Loading system-wide policies from: {filePath}");
+
+ var jsonString = File.ReadAllText(filePath);
+
+ // Treat empty or JSON "null" as "no policies" instead of crashing
+ if (string.IsNullOrWhiteSpace(jsonString))
+ {
+ Current = new PolicyInfo();
+ Log.Info("Config file is empty, no system-wide policies loaded.");
+ }
+ else
+ {
+ Current = JsonSerializer.Deserialize(jsonString, JsonOptions) ?? new PolicyInfo();
+
+ Log.Info("System-wide policies loaded successfully.");
+
+ // Log enabled settings
+ Log.Info($"System-wide policy - Update_CheckForUpdatesAtStartup: {Current.Update_CheckForUpdatesAtStartup?.ToString() ?? "Not set"}");
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"Failed to load system-wide policies from: {filePath}", ex);
+ Current = new PolicyInfo();
+ }
+ }
+ else
+ {
+ Log.Debug($"No system-wide policy file found at: {filePath}");
+ Current = new PolicyInfo();
+ }
+ }
+
+ #endregion
+}
diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs
index 34ff00a850..f1b7247265 100644
--- a/Source/NETworkManager.Settings/SettingsManager.cs
+++ b/Source/NETworkManager.Settings/SettingsManager.cs
@@ -152,6 +152,9 @@ public static void Initialize()
///
public static void Load()
{
+ // Load system-wide policies first (from app directory)
+ PolicyManager.Load();
+
var filePath = GetSettingsFilePath();
var legacyFilePath = GetLegacySettingsFilePath();
diff --git a/Source/NETworkManager.Settings/config.json.example b/Source/NETworkManager.Settings/config.json.example
new file mode 100644
index 0000000000..8ca2bf05b3
--- /dev/null
+++ b/Source/NETworkManager.Settings/config.json.example
@@ -0,0 +1,3 @@
+{
+ "Update_CheckForUpdatesAtStartup": false
+}
\ No newline at end of file
diff --git a/Source/NETworkManager/MainWindow.xaml.cs b/Source/NETworkManager/MainWindow.xaml.cs
index 6546c727be..3768c69687 100644
--- a/Source/NETworkManager/MainWindow.xaml.cs
+++ b/Source/NETworkManager/MainWindow.xaml.cs
@@ -561,7 +561,8 @@ private void Load()
NetworkChange.NetworkAddressChanged += (_, _) => OnNetworkHasChanged();
// Search for updates...
- if (SettingsManager.Current.Update_CheckForUpdatesAtStartup)
+ if (PolicyManager.Current?.Update_CheckForUpdatesAtStartup
+ ?? SettingsManager.Current.Update_CheckForUpdatesAtStartup)
CheckForUpdates();
}
diff --git a/Source/NETworkManager/ViewModels/SettingsUpdateViewModel.cs b/Source/NETworkManager/ViewModels/SettingsUpdateViewModel.cs
index b760064e6f..8530469e7a 100644
--- a/Source/NETworkManager/ViewModels/SettingsUpdateViewModel.cs
+++ b/Source/NETworkManager/ViewModels/SettingsUpdateViewModel.cs
@@ -26,6 +26,11 @@ public bool CheckForUpdatesAtStartup
}
}
+ ///
+ /// Gets whether the "Check for updates at startup" setting is managed by system-wide policy.
+ ///
+ public bool IsUpdateCheckManagedByPolicy => PolicyManager.Current?.Update_CheckForUpdatesAtStartup.HasValue == true;
+
private bool _checkForPreReleases;
public bool CheckForPreReleases
@@ -78,7 +83,9 @@ public SettingsUpdateViewModel()
private void LoadSettings()
{
- CheckForUpdatesAtStartup = SettingsManager.Current.Update_CheckForUpdatesAtStartup;
+ // If policy is set, show the policy value; otherwise show the user's setting
+ CheckForUpdatesAtStartup = PolicyManager.Current?.Update_CheckForUpdatesAtStartup
+ ?? SettingsManager.Current.Update_CheckForUpdatesAtStartup;
CheckForPreReleases = SettingsManager.Current.Update_CheckForPreReleases;
EnableExperimentalFeatures = SettingsManager.Current.Experimental_EnableExperimentalFeatures;
}
diff --git a/Source/NETworkManager/Views/SettingsUpdateView.xaml b/Source/NETworkManager/Views/SettingsUpdateView.xaml
index 1b39084ef0..5f6530f909 100644
--- a/Source/NETworkManager/Views/SettingsUpdateView.xaml
+++ b/Source/NETworkManager/Views/SettingsUpdateView.xaml
@@ -6,13 +6,20 @@
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:localization="clr-namespace:NETworkManager.Localization.Resources;assembly=NETworkManager.Localization"
xmlns:viewModels="clr-namespace:NETworkManager.ViewModels"
+ xmlns:converters="clr-namespace:NETworkManager.Converters;assembly=NETworkManager.Converters"
+ xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:SettingsUpdateViewModel}">
+
+
+
+
+ IsOn="{Binding CheckForUpdatesAtStartup}"
+ IsEnabled="{Binding IsUpdateCheckManagedByPolicy, Converter={StaticResource BooleanReverseConverter}}" />
+
+
+
+
+
+
+
+
diff --git a/Website/docs/changelog/next-release.md b/Website/docs/changelog/next-release.md
index c477c766ae..6fdd01caf2 100644
--- a/Website/docs/changelog/next-release.md
+++ b/Website/docs/changelog/next-release.md
@@ -45,6 +45,7 @@ Release date: **xx.xx.2025**
- New language Ukrainian (`uk-UA`) has been added. Thanks to [@vadickkt](https://github.com/vadickkt) [#3240](https://github.com/BornToBeRoot/NETworkManager/pull/3240)
- Migrated all dialogs to child windows for improved usability and accessibility. [#3271](https://github.com/BornToBeRoot/NETworkManager/pull/3271)
+- System-wide policies can now be configured via a `config.json` file in the application directory to control settings for all users. Currently supports controlling the "Check for updates at startup" setting. This is useful for enterprise deployments where administrators need centralized control over update behavior. See [System-Wide Policies](../system-wide-policies.md) documentation for more information. [#3313](https://github.com/BornToBeRoot/NETworkManager/pull/3313)
**DNS Lookup**
diff --git a/Website/docs/img/system-wide-policy-indicator.png b/Website/docs/img/system-wide-policy-indicator.png
new file mode 100644
index 0000000000..36da34f920
Binary files /dev/null and b/Website/docs/img/system-wide-policy-indicator.png differ
diff --git a/Website/docs/settings/update.md b/Website/docs/settings/update.md
index 565a74fefe..9c006a108b 100644
--- a/Website/docs/settings/update.md
+++ b/Website/docs/settings/update.md
@@ -12,6 +12,27 @@ Check for new program versions on GitHub when the application is launched.
**Default:** `Enabled`
+:::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:** `Update_CheckForUpdatesAtStartup`
+
+**Values:**
+- `true` - Force enable automatic update checks at startup for all users
+- `false` - Force disable automatic update checks at startup for all users
+- Omit the property - Allow users to control this setting themselves
+
+**Example:**
+
+```json
+{
+ "Update_CheckForUpdatesAtStartup": false
+}
+```
+
+:::
+
:::note
The URL `https://api.github.com/` must be reachable to check for updates.
diff --git a/Website/docs/system-wide-policies.md b/Website/docs/system-wide-policies.md
new file mode 100644
index 0000000000..d8ef644453
--- /dev/null
+++ b/Website/docs/system-wide-policies.md
@@ -0,0 +1,102 @@
+---
+sidebar_position: 6
+---
+
+# System-Wide Policies
+
+System-wide policies allow administrators to enforce specific settings for all users on a machine. These policies override user-specific settings and provide centralized control over application behavior in enterprise environments.
+
+## Overview
+
+Policies are defined in a `config.json` file placed in the application installation directory (the same folder as `NETworkManager.exe`). When this file exists, the application loads the policies at startup and applies them with precedence over user settings.
+
+Users will see a visual indicator in the Settings UI when a setting is controlled by a system-wide policy, showing them the administrator-enforced value and preventing them from changing it.
+
+
+
+## Configuration File
+
+The `config.json` file uses a simple JSON structure to define policy values. An example file (`config.json.example`) is included in the application installation directory for reference.
+
+**File Location:**
+- **Installed version**: `C:\Program Files\NETworkManager\config.json` (or your custom installation path)
+- **Portable version**: Same directory as `NETworkManager.exe`
+
+**File Format:**
+
+```json
+{
+ "Policy_Name1": true,
+ "Policy_Name2": "ExampleValue"
+}
+```
+
+
+**Example:**
+
+```json
+{
+ "Update_CheckForUpdatesAtStartup": false
+}
+```
+
+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
+
+- The file must be named exactly `config.json`
+- The file must contain valid JSON syntax
+- Changes to the file require restarting the application to take effect
+- If the file doesn't exist or contains invalid JSON, it will be ignored and user settings will apply
+
+:::
+
+## Deployment
+
+For enterprise deployments:
+
+1. **Create the configuration file**:
+ - Use the `config.json.example` as a template
+ - Rename it to `config.json`
+ - Set your desired policy values (you find them in the corresponding setting's documentation)
+
+2. **Deploy to installation directory**:
+ - Place the `config.json` file in the same directory as `NETworkManager.exe`
+ - For MSI installations, this is typically `C:\Program Files\NETworkManager\`
+ - For portable installations, place it next to the executable
+
+3. **Deploy methods**:
+ - Group Policy — copy the `config.json` file to the installation directory (use Group Policy preferences or a startup script)
+ - Configuration management tools — SCCM/ConfigMgr, Microsoft Intune, Ansible, etc.
+ - Scripts and deployment toolkits — PowerShell scripts, PSAppDeployToolkit (recommended for scripted MSI/App deployments)
+ - Manual deployment — hand-copy for small-scale rollouts
+
+4. **Verification**:
+ - Launch the application
+ - Navigate to Settings > Update (e.g., "Check for updates at startup")
+ - Verify the shield icon and the administrator message appear and that the control is disabled
+ - Confirm the displayed value matches the policy
+
+:::warning
+
+Ensure the `config.json` file has appropriate permissions so that regular users cannot modify it. On standard installations in `Program Files`, this is automatically enforced by Windows file permissions.
+
+:::
+
+## Troubleshooting
+
+**Policy not being applied:**
+- Verify the file is named exactly `config.json` (not `config.json.txt`)
+- Check that the JSON syntax is valid (use a JSON validator)
+- Confirm the file is in the correct directory (same as `NETworkManager.exe`)
+- Restart the application after creating or modifying the file
+- Check the application logs for any error messages related to policy loading
+
+**Policy values not showing in UI:**
+- Ensure the property name matches exactly (see the corresponding setting's documentation for the property name)
+- 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
+
+## 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).
diff --git a/Website/src/css/custom.css b/Website/src/css/custom.css
index f55bc3482a..233f8814d9 100644
--- a/Website/src/css/custom.css
+++ b/Website/src/css/custom.css
@@ -4,6 +4,9 @@
* work well for content-centric websites.
*/
+/* Import react-image-gallery styles */
+@import 'react-image-gallery/styles/css/image-gallery.css';
+
/* You can override the default Infima variables here. */
:root {
--ifm-color-primary: #00d4aa;
diff --git a/Website/src/pages/index.js b/Website/src/pages/index.js
index 60778377f6..870d02fc96 100644
--- a/Website/src/pages/index.js
+++ b/Website/src/pages/index.js
@@ -5,7 +5,6 @@ import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
import Layout from "@theme/Layout";
import HomepageFeatures from "@site/src/components/HomepageFeatures";
import ImageGallery from "react-image-gallery";
-import "react-image-gallery/styles/css/image-gallery.css";
import ImageGalleryDashboard from "@site/docs/img/dashboard.png";
import ImageGalleryNetworkInterfaceInformation from "@site/docs/img/network-interface--information.png";
diff --git a/Website/yarn.lock b/Website/yarn.lock
index 57722cbb93..dd9a2f7d44 100644
--- a/Website/yarn.lock
+++ b/Website/yarn.lock
@@ -3238,12 +3238,7 @@ caniuse-api@^3.0.0:
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"
-caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001702, caniuse-lite@^1.0.30001718:
- version "1.0.30001721"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001721.tgz#36b90cd96901f8c98dd6698bf5c8af7d4c6872d7"
- integrity sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ==
-
-caniuse-lite@^1.0.30001759:
+caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001702, caniuse-lite@^1.0.30001718, caniuse-lite@^1.0.30001759:
version "1.0.30001769"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz#1ad91594fad7dc233777c2781879ab5409f7d9c2"
integrity sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==