Skip to content

feat: add TrustedHosts policy config option to allow whitelisting of UNC paths - #26688

Open
Antti (Antvirf) wants to merge 6 commits into
PowerShell:masterfrom
Antvirf:fix-allowed-hosts
Open

Antti (Antvirf) wants to merge 6 commits into
PowerShell:masterfrom
Antvirf:fix-allowed-hosts

Conversation

@Antvirf

@Antvirf Antti (Antvirf) commented Jan 14, 2026 •

Copy link
Copy Markdown

PR Summary

Add a configuration option in both registry and config JSON to whitelist server names to be marked as "local intranet zones" as far as script execution is concerned. Otherwise, PS7 cannot execute scripts from remote locations with a . in the name, breaking e.g. the loading of powershell profiles when the user's Documents directory is redirected to a server referred to via an FQDN.

Resolves #12336

PR Context

The default behaviour of assuming any hostname with a . in it being insecure is not usable in environments where one wishes to refer to a path via FQDN, for example when using DFS to refer to file servers. The configuration option added here allows a group-policy as well as a config-file based approach to whitelisting hosts.

PR Checklist

TBC

  • Testing requirements? Happy to extend here as needed
  • Documentation changes?

Tests

# without any configs set
& "D:\PowerShell\src\powershell-win-core\bin\release\net10.0\win7-x64\pwsh.exe" -NoExit -File "\\company.domain\files\profile.ps1"
PowerShell 7.6.0-preview.5-159-g5858bfd7960c703d53a70e834dd685661077164f
Cannot load PSReadline module.  Console is running without PSReadline.
.: File \\company.domain\files\profile.ps1 cannot be loaded because running scripts is disabled on this system. For more information, see about_Execution_Policies at https://go.microsoft.com/fwlink/?LinkID=135170.


# set an execution policy (ALREADY SUPPORTED BY POWERSHELL)
$basePath = "HKLM:\Software\Policies\Microsoft\PowerShellCore"
$trustedHostsPath = "$basePath\TrustedHosts"
$patternsPath = "$trustedHostsPath\Patterns"
New-Item -Path $basePath -Force | Out-Null
New-ItemProperty -Path $basePath -Name "EnableScripts" -Value 1 -PropertyType DWord -Force | Out-Null
New-ItemProperty -Path $basePath -Name "ExecutionPolicy" -Value "RemoteSigned" -PropertyType String -Force | Out-Null


# try again, still does not work as execution policy itself is not enough, hence why this PR is needed
& "D:\PowerShell\src\powershell-win-core\bin\release\net10.0\win7-x64\pwsh.exe" -NoExit -File "\\company.domain\files\profile.ps1"
PowerShell 7.6.0-preview.5-159-g5858bfd7960c703d53a70e834dd685661077164f
.: File \\company.domain\files\profile.ps1 cannot be loaded. The file \\company.domain\files\profile.ps1 is not digitally signed. You cannot run this script on the current system. For more information about running scripts and setting execution policy, see about_Execution_Policies at https://go.microsoft.com/fwlink/?LinkID=135170.


# set the new options whitelisting the company domain
New-Item -Path $patternsPath -Force | Out-Null
New-ItemProperty -Path $patternsPath -Name "company.domain" -Value "company.domain" -PropertyType String -Force | Out-Null
New-ItemProperty -Path $patternsPath -Name "*.company.domain" -Value "*.company.domain" -PropertyType String -Force | Out-Null


# works fine now
& "D:\PowerShell\src\powershell-win-core\bin\release\net10.0\win7-x64\pwsh.exe" -NoExit -File "\\company.domain\files\profile.ps1"
PowerShell 7.6.0-preview.5-159-g5858bfd7960c703d53a70e834dd685661077164f
Profile loaded successfully!

…f UNC paths

The default behaviour of assuming any hostname with a `.` in it is not usable in environments where one wishes to refer to a path via FQDN, for example when using DFS to refer to file servers. The configuration option added here allows a group-policy as well as a config-file based approach to whitelisting hosts.
@Antvirf
Antti (Antvirf) marked this pull request as ready for review January 16, 2026 10:41
@Antvirf
Antti (Antvirf) requested a review from a team as a code owner January 16, 2026 10:41
Copilot AI review requested due to automatic review settings January 16, 2026 10:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a configuration option to whitelist UNC server hostnames/paths that should be treated as "Intranet" security zone instead of "Internet" zone during script execution policy checks. This addresses an issue where PowerShell Core treats any UNC path with a period (.) in the hostname as originating from the Internet security zone, which prevents script execution from FQDN UNC paths even with RemoteSigned execution policy.

Changes:

  • Added TrustedHosts policy configuration class with wildcard pattern support for trusted hostnames/paths
  • Implemented trusted host checking in security zone evaluation logic with Group Policy and config file support
  • Added Group Policy template definitions (ADMX/ADML) for TrustedHosts configuration

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/System.Management.Automation/utils/ClrFacade.cs Adds IsTrustedHost method to check UNC paths against trusted host patterns and integrates it into security zone mapping logic
src/System.Management.Automation/engine/Utils.cs Registers TrustedHosts policy type in policy retrieval infrastructure and adds registry key mapping
src/System.Management.Automation/engine/PSConfiguration.cs Defines TrustedHosts policy class with Patterns property for storing trusted host patterns
assets/GroupPolicy/PowerShellCoreExecutionPolicy.admx Adds Group Policy definition for TrustedHosts with list-based pattern configuration
assets/GroupPolicy/PowerShellCoreExecutionPolicy.adml Adds UI strings and help text for TrustedHosts Group Policy setting

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +150 to +157
#if !UNIX
/// <summary>
/// Check if a UNC path matches any trusted host pattern.
/// </summary>
/// <param name="uncPath">The full UNC path to check.</param>
/// <param name="hostname">The hostname from the UNC path.</param>
/// <returns>True if the path matches a trusted host pattern, false otherwise.</returns>
private static bool IsTrustedHost(string uncPath, string hostname)

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method is wrapped in #if !UNIX directive at line 150, but it's already inside a #if !UNIX block that starts at line 137 (#region Security). This creates a redundant nested preprocessor directive. Remove the inner #if !UNIX directive at line 150 and its corresponding #endif at line 196.

Copilot uses AI. Check for mistakes.
Comment on lines +187 to +191
catch (Exception)
{
// Invalid pattern - skip it silently
continue;
}

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exception handler catches all exceptions without any logging or diagnostic information. This could make it difficult to troubleshoot configuration issues where a pattern is invalid. Consider catching only specific exceptions like WildcardPatternException or ArgumentException, or at minimum add diagnostic logging to help administrators identify invalid patterns.

Suggested change
catch (Exception)
{
// Invalid pattern - skip it silently
continue;
}
catch (WildcardPatternException)
{
// Invalid pattern - skip it silently
continue;
}
catch (ArgumentException)
{
// Invalid pattern - skip it silently
continue;
}

Copilot uses AI. Check for mistakes.
- *.corp.internal (matches any hostname in corp.internal domain)
- \\server.domain.com\Users\*\Documents\* (matches specific UNC path pattern)

Wildcard syntax supports: * (zero or more chars), ? (one char), [abc] (character set), ` (escape char)

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation states that the backtick () is the escape character, but in the context of wildcard patterns in PowerShell, the backtick is specifically used to escape wildcards in the pattern string itself. This might be confusing since the backtick is also PowerShell's general escape character. Consider clarifying this by adding an example or rephrasing to: 'Wildcard syntax supports: * (zero or more chars), ? (one char), [abc] (character set), (escape char to treat wildcards as literals)'.

Suggested change
Wildcard syntax supports: * (zero or more chars), ? (one char), [abc] (character set), ` (escape char)
Wildcard syntax supports: * (zero or more chars), ? (one char), [abc] (character set), ` (escape char to treat wildcards as literals).

Copilot uses AI. Check for mistakes.
@microsoft-github-policy-service microsoft-github-policy-service Bot added the Review - Needed The PR is being reviewed label Jan 31, 2026
@Antvirf

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree company="Marshall Wace"

@Antvirf

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree company="MarshallWace"

@SteveL-MSFT
Steve Lee (SteveL-MSFT) requested a balanced review from Copilot August 6, 2026 17:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

src/System.Management.Automation/utils/ClrFacade.cs:161

  • IsTrustedHost reads policy/config via Utils.GetPolicySetting<TrustedHosts>(...) on every security-zone evaluation, which can be invoked frequently during script/module loading. Consider caching the resolved patterns (or the resolved TrustedHosts object) in a static, thread-safe cache and refreshing only when configuration is reloaded (or at least once per process start) to avoid repeated registry/config reads and allocations.
            TrustedHosts trustedHostsPolicy = Utils.GetPolicySetting<TrustedHosts>(Utils.SystemWideThenCurrentUserConfig);
            string[] patterns = trustedHostsPolicy?.Patterns;

Comment on lines +745 to +748
internal sealed class TrustedHosts : PolicyBase
{
public string[] Patterns { get; set; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Review - Needed The PR is being reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add ability to configure internet zone server names for execution policy in PS v7

2 participants