My name is Helmut Wagensonner. I'm a Cloud Solution Architect at Microsoft. This blog post is about understanding and using ms-settings URIs in Windows to control and customize the Settings experience in enterprise environments. It explains what these URIs are, why they matter for IT administrators, and how they can be leveraged with Group Policy or MDM to restrict, simplify, and standardize Windows device configurations. The post also introduces a practical PowerShell script that helps administrators discover and manage Settings URIs across different Windows versions.
Understanding Windows Settings URIs and How to Use Them in Enterprise Environments
Windows provides a powerful and flexible management framework that enables organizations to configure, restrict, or simplify the Settings experience for their users. One of the key mechanisms behind this framework is the ms-settings: URI scheme — a consistent, internal navigation system that defines how each Settings page in Windows is accessed.
If you have ever opened Windows Settings and navigated to Privacy → Camera, you were effectively visiting a page identified by a specific internal URI:
ms-settings:privacy-webcam
These URIs exist for virtually every part of the modern Settings interface — from Windows Update to Bluetooth, Accounts, and Accessibility. Administrators and automation tools can call these URIs directly to open pages, but they can also use them for more advanced purposes, such as controlling which pages are available to users through Group Policy or MDM.
What Are ms-settings URIs?
Each page within Windows Settings has an internal URI (Uniform Resource Identifier) that begins with the prefix ms-settings: followed by a descriptive identifier. For example:
- ms-settings:windowsupdate – Windows Update
- ms-settings:bluetooth – Bluetooth settings
- ms-settings:privacy-microphone – Microphone permissions
- ms-settings:network-wifi – Wi-Fi configuration
Typing any of these URIs into Win + R or a command prompt immediately opens the corresponding Settings page. To open the camera settings, for example:
The corresponding Powershell command would be:
Start-Process "ms-settings:privacy-webcam"
These same URIs are also what Group Policy and Intune use when defining visibility rules for Settings. Over time, new pages and features are added to Windows, and therefore new URIs are introduced. Most of the available URIs are documented here:
Having a reliable way to extract these URIs directly from Windows helps administrators maintain accurate and consistent configuration policies across versions.
Why ms-settings URIs Matter to Enterprises
In enterprise environments, Windows devices are rarely unmanaged. Organizations typically enforce baseline configurations to meet security, usability, and compliance requirements. Control over the Settings experience can be a crucial part of that strategy. Common scenarios include:
- Kiosk and shared PCs – where users should not modify system or network settings.
- Education or classroom devices – limiting what students can access or change.
- Corporate desktops – ensuring consistent, compliant configurations across all departments.
- Call center terminals or point-of-sale systems – providing only task-relevant options.
- High-security workstations – preventing changes to privacy, update, or device settings.
By controlling access to specific Settings pages, IT administrators can:
- Reduce accidental misconfiguration.
- Lower support costs.
- Improve compliance posture.
- Simplify user experience for task-focused roles.
- Prevent exposure of system areas that are centrally managed or locked down.
Managing Settings Visibility with Group Policy
Windows includes a built-in Group Policy setting that allows administrators to control which pages in the Settings app are visible to users.
Policy location:
Computer/User Configuration → Administrative Templates → Control Panel → Settings Page Visibility
This policy uses a semicolon-separated list of rules that reference Settings pages by their ms-settings identifiers. The part after the colon is what the policy recognizes. For example:
Hide selected pages
hide:privacy-webcam;bluetooth;display
Show only selected pages
showonly:windowsupdate;about
Administrators can combine these directives to tailor the Settings experience precisely to the needs of their organization. This approach is particularly useful in locked-down environments where users have a limited set of configuration options, or where privacy and security policies mandate restricted access to certain features. Find more information about managing Settings URIs here: https://learn.microsoft.com/en-us/windows/client-management/client-tools/manage-settings-app-with-group-policy
The Challenge: Keeping Visibility Rules Current
The Windows Settings app evolves continuously. With each new feature update or release, new categories, pages, and URIs may appear. For administrators maintaining long-term device configurations, that means GPO lists need to be reviewed and updated regularly.
While Microsoft provides extensive documentation for the most common pages, enterprise administrators often need a complete and current list of all URIs available on the system they are managing. This ensures that policies remain accurate and compatible, even when upgrading from one Windows build to another.
Introducing Get-MSSettingsURIs.ps1
To simplify this process, I created a small PowerShell script called Get-MSSettingsURIs.ps1.
This script scans the system’s SystemSettings.dll file — the core component behind the modern Settings interface — and extracts every ms-settings: URI it contains. Because it reads directly from the operating system, it always reflects exactly what that Windows build supports.
You can use the script to:
- Discover all current Settings URIs on any Windows device.
- Compare differences between Windows versions (e.g., 23H2 → 25H2).
- Build or update your Group Policy “Settings Page Visibility” configuration.
- Validate that newly introduced Settings pages are correctly managed.
param(
[string]$Path = "C:\Windows\ImmersiveControlPanel\SystemSettings.dll",
[string]$OutFile,
[switch]$GpoKeysOnly
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
if (-not (Test-Path -LiteralPath $Path)) {
throw "Datei nicht gefunden: $Path"
}
# --- High-performance Scanner in C# (compiled on-the-fly) ---
$cs = @"
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
public static class MsSettingsScanner
{
static readonly byte[] AsciiPrefix = Encoding.ASCII.GetBytes("ms-settings:");
static readonly byte[] Utf16Prefix = Encoding.Unicode.GetBytes("ms-settings:");
public static List<string> ExtractAll(string filePath)
{
byte[] data = File.ReadAllBytes(filePath); // fast read
var set = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var s in FindAscii(data))
set.Add(s);
foreach (var s in FindUtf16(data))
set.Add(s);
var list = new List<string>(set);
list.Sort(StringComparer.OrdinalIgnoreCase);
return list;
}
// ---- ASCII ----
static IEnumerable<string> FindAscii(byte[] data)
{
foreach (int idx in FindAll(data, AsciiPrefix))
{
int i = idx + AsciiPrefix.Length;
var sb = new StringBuilder("ms-settings:");
while (i < data.Length)
{
char c = (char)data[i];
if (!IsValidUriChar(c)) break;
sb.Append(c);
i++;
}
yield return sb.ToString();
}
}
// ---- UTF-16LE ----
static IEnumerable<string> FindUtf16(byte[] data)
{
foreach (int idx in FindAll(data, Utf16Prefix))
{
int pos = idx + Utf16Prefix.Length;
var sb = new StringBuilder("ms-settings:");
// 2-Byte-Steps after the prefix (LE). Accept only ASCII (hi=0).
while (pos + 1 < data.Length)
{
byte lo = data[pos];
byte hi = data[pos + 1];
if (hi != 0) break; // only ASCII characters
char c = (char)lo;
if (!IsValidUriChar(c)) break;
sb.Append(c);
pos += 2;
}
yield return sb.ToString();
}
}
// Boyer–Moore–Horspool over Bytes (fast)
static IEnumerable<int> FindAll(byte[] haystack, byte[] needle)
{
int n = haystack.Length, m = needle.Length;
if (m == 0 || n < m) yield break;
int[] skip = new int[256];
for (int i = 0; i < skip.Length; i++) skip[i] = m;
for (int i = 0; i < m - 1; i++) skip[needle[i]] = m - 1 - i;
int pos = 0;
int last = m - 1;
while (pos <= n - m)
{
int j = last;
while (j >= 0 && haystack[pos + j] == needle[j]) j--;
if (j < 0)
{
yield return pos;
pos += m; // next possible start
}
else
{
pos += skip[haystack[pos + last]];
}
}
}
// valid characters after "ms-settings:"
static bool IsValidUriChar(char c)
{
if ((c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9'))
return true;
switch (c)
{
case '-': case '_': case '.': case ':':
case '/': case ';': case '?': case '&':
case '=': case '#': case '%': case '+':
case ',': case '@':
return true;
default:
return false;
}
}
}
"@
# Make sure to only compile once per session
$loaded = [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetTypes() -as [type] } | Where-Object { $_.GetType("MsSettingsScanner") }
if (-not $loaded) {
Add-Type -TypeDefinition $cs -Language CSharp -IgnoreWarnings
}
$uris = [MsSettingsScanner]::ExtractAll($Path)
if ($GpoKeysOnly) {
$uris = $uris | ForEach-Object {
if ($_ -like 'ms-settings:*') { $_.Substring(12) } else { $_ }
} | Where-Object { $_ }
}
if ($OutFile) {
$uris | Set-Content -LiteralPath $OutFile -Encoding UTF8
Write-Host ("Fertig. {0} Einträge → {1}" -f $uris.Count, $OutFile)
} else {
$uris
Write-Host ("`nTotal: {0}" -f $uris.Count)
}
How the Script Works
At a high level, Get-MSSettingsURIs.ps1 reads binary data from C:\Windows\ImmersiveControlPanel\SystemSettings.dll and searches for all strings that match the ms-settings: pattern. It supports both ASCII and Unicode encodings to ensure no identifiers are missed.
It then sorts and outputs the unique list of URIs. You can optionally format the results to make them directly usable in a Group Policy setting. Because the script runs locally and reads system files, it does not require any administrative privileges beyond read access to the Windows directory.
Example Usage
To run the script with default settings:
.\Get-MSSettingsURIs.ps1
This outputs a complete list of all ms-settings: URIs found in the current Windows installation. If you want the results formatted for direct use in Group Policy (without the ms-settings: prefix):
.\Get-MSSettingsURIs.ps1 -GpoStyle
To scan a copy of SystemSettings.dll from another Windows build (for testing or preparation):
.\Get-MSSettingsURIs.ps1 -Binary "C:\Temp\SystemSettings.dll"
Example Output
Standard output might look like this:
ms-settings:privacy-webcam
ms-settings:privacy-microphone
ms-settings:windowsupdate
ms-settings:network-proxy
ms-settings:bluetooth
ms-settings:display
...
When using the -GpoStyle parameter, the output is trimmed for direct use in Group Policy:
privacy-webcam
privacy-microphone
windowsupdate
network-proxy
bluetooth
display
...
Integrating the Script Into IT Operations
Once you have the list of Settings URIs, you can automate several key tasks:
- Baseline validation – Ensure the same visibility configuration applies across device groups.
- Upgrade preparation – Before deploying a new Windows release, compare URI lists to identify new or renamed pages.
- Compliance auditing – Verify that restricted settings remain hidden as expected.
- Kiosk image building – Generate a minimal set of allowed pages for kiosk or shared devices.
- Automation – Integrate the PowerShell output into configuration pipelines, Intune scripts, or Group Policy templates.
Because the script runs without external dependencies, it can easily be distributed as part of enterprise configuration management or imaging workflows.
Example Workflow for Administrators:
- Run the PowerShell script on a reference Windows build.
- Save the resulting URI list to a text file, such as MSSettings_URIs_23H2.txt.
- Use the -GpoStyle option to generate a GPO-ready list.
- Configure the Settings Page Visibility policy in Group Policy or Intune.
- Optionally rerun the script after major OS updates to check for new entries.
By incorporating this simple step into your management process, you ensure that every system in your environment reflects the intended configuration and that new Settings pages introduced by future Windows versions are quickly identified.
Conclusion
The ms-settings: URI system is one of Windows’ most useful yet under-appreciated administrative capabilities. For enterprises that depend on configuration consistency, compliance, or controlled user experiences, understanding and managing these URIs is key.
The Get-MSSettingsURIs.ps1 script gives administrators an easy way to extract, review, and apply these identifiers directly from any Windows installation. Combined with Group Policy or MDM, it provides a fast and reliable method to shape the Settings experience for users — ensuring that each system remains secure, focused, and predictable.
Disclaimer
This Sample Code is provided for the purpose of illustration only
and is not intended to be used in a production environment. THIS
SAMPLE CODE AND ANY RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT
WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS
FOR A PARTICULAR PURPOSE. We grant You a nonexclusive, royalty-free
right to use and modify the Sample Code and to reproduce and distribute
the object code form of the Sample Code, provided that You agree:
(i) to not use Our name, logo, or trademarks to market Your software
product in which the Sample Code is embedded; (ii) to include a valid
copyright notice on Your software product in which the Sample Code is
embedded; and (iii) to indemnify, hold harmless, and defend Us and
Our suppliers from and against any claims or lawsuits, including
attorneys' fees, that arise or result from the use or distribution
of the Sample Code.
This sample script is not supported under any Microsoft standard
support program or service. The sample script is provided AS IS
without warranty of any kind. Microsoft further disclaims all implied
warranties including, without limitation, any implied warranties of
merchantability or of fitness for a particular purpose. The entire
risk arising out of the use or performance of the sample scripts and
documentation remains with you. In no event shall Microsoft, its
authors, or anyone else involved in the creation, production, or
delivery of the scripts be liable for any damages whatsoever
(including, without limitation, damages for loss of business
profits, business interruption, loss of business information, or
other pecuniary loss) arising out of the use of or inability to
use the sample scripts or documentation, even if Microsoft has
been advised of the possibility of such damages.