This blog covers a custom script solution for Intune, that can be used to automatically detect, if the Entra Private Access (GSA) client is connected to the internal network – or off-site. When the client is connected to the internal network, we don’t want to send the network traffic into the GSA tunnel through Microsoft – but use direct connectivity to the servers.
Scripts can be used in Intune with the necessary scripts (detection, remediation, suspension). Scripts can serve as a workaround until Microsoft releases support for this in the Entra GSA client.
Update Aug 23, 2023 - Method #1 (Resolve_DNSName-Validate_Against_IP)
I have added a parameter $FailoverTargetIP to method #1, which solves a problem, if the EPA client gets into a wrong state, which can result in DNS lookup not working against an internal DNS server. I have seen this, when EPA client was connected to an 802.1x environment with the EPA client ON, but network was blocking DNS traffic to DNS server as it was coming through the tunnel. Ping was working, but no DNS lookup. Initially it will try to do a DNS lookup. If it fails, it will fall over to do a ping against an internal IP for example the app-proxy server.
$Mode = "Resolve_DNSName-Validate_Against_IP"
$Target = "GSA-TEST.xxxxxx"
$ExpectedResult = "172.22.0.1"
$FailoverTargetIP = "172.22.0.11"
---------
V2-Update - Entra GSA v2.0
This blog has been updated to include new features in Entra GSA v2.0 (released July 2024). My scripts has also been updated as promised and works with the new features.
The updated scripts will only work for Entra GSA client version 2.0+, which can be downloaded here.
You can always get the latest Entra GSA version using this link https://aka.ms/gsawinlatest
You can read about the changes later in this blog - click here for shortcut to section

V2 changes:
* Support for new reg-key in v2.0 ""
Background
As part of the implementation of Entra Private Access, you define your internal networks in the Entra Private Access solution. Then the agent knows which networks / FQDNs to “tunnel” through the agent. This is very cool, when you are sitting home, at guest networks, hotels, etc.
But when you are sitting onsite close to the servers (internal network), you don’t want the traffic to go through the tunnel, but directly through the local network. Your users will appreciate you for this improvement 🙂
Solution
On my Github, I have provided 3 scripts, that can be used to solve this problem.
My script will be updated according to the below mentioned steps.
| Timing | Functionality |
| June 2024 | Script (v1 script – can be found here) will stop/start Windows service for Entra GSA client (3 services), which will impact all client functionality (Private Access, Internet Access) |
| July 2024 | My current script (v2) has been adjusted. Now only Entra Private Access will be suspended/started, so Entra Internet Access functionality is not impacted. You find the current (updated) remediation script here |
| 2H- 2024 | Entra Private Access “Intelligent local access” feature built into product |
Support for Entra GSA v2.0 features (July 2024 release)
Entra GSA client v2.0+ does now support 2 new reg-keys that allows more flexibility around stop/start of Entra Private Access. My script (v2, current version) supports these features.
V2 Feature – Stop/Start Entra Private Access functionality dynamically using regkey
You can dynamically control the state of Entra Private Access functionality by setting the key IsPrivateAccessDisabledByUser in registry path HKCU\Software\Microsoft\Global Secure Access Client

| Path | Key | Value (DWORD) |
| HKCU\Software\Microsoft\Global Secure Access Client | IsPrivateAccessDisabledByUser | 0 = Private Access is Active 1 = Private Access is Suspended |
V2 Feature – Allow User to stop/start Entra Private Access functionality manually
You can allow a user to control Entra Private Access functionality by setting the key ‘HideDisablePrivateAccessButton‘ in the path HKLM\Software\Microsoft\Global Secure Access Client


| Path | Key | Value (DWORD) |
| HKLM\Software\Microsoft\Global Secure Access Client | HideDisablePrivateAccessButton | 0 = User is allowed to start/stop Entra Private Access 1 (or no key) = User is not allowed to control stop/start |
New detection features in v2 script
Thank you for the questions and feedback to extend the detection method.
v2 of my remediation script (link to Github) includes 3 methods for local network detection. . Hope the new features can support your needs.
Method #1 - Resolve_DNSName-Validate_Against_IP - Local DNS Name lookup - result should respond to IP addr
NOTE: Requires local DNS solution like Windows AD DNS, InfoBlox, Router DNS, etc.
$Mode = "Resolve_DNSName-Validate_Against_IP"
$Target = "DC1.2linkit.local"
$ExpectedResult = "10.1.0.5"
------------------------------------------------------------------------
Method #2A - Ping_DNSName-Resolve_DNSName_To_IP - IP address reverse lookup - result should respond to DNS hostname address - use specific DNS server
NOTE: This DNS domain cannot be inside Private Access tunnel. Must be an external zone used locally
Reason: Entra Private Access treats any hosts names part of Private DNS-functionality as wildcards, so it will respond with an internal tunnel IP when client is running
$Mode = "Ping_DNSName-Resolve_DNSName_To_IP"
$Target = "10.1.0.5"
$ExpectedResult = "DC1.2linkit.local"
$DNSServerIP = "10.1.0.5"
------------------------------------------------------------------------
Method #2B - Ping_DNSName-Resolve_DNSName_To_IP - IP address reverse lookup - result should respond to DNS hostname address - use DNS from IP/DHCP settings on client
NOTE: This DNS domain cannot be inside Private Access tunnel. Must be an external zone used locally
Reason: Entra Private Access treats any hosts names part of Private DNS-functionality as wildcards, so it will respond with an internal tunnel IP when client is running
$Mode = "Ping_DNSName-Resolve_DNSName_To_IP"
$Target = "10.1.0.5"
$ExpectedResult = "DC1.2linkit.local"
$DNSServerIP = $null
------------------------------------------------------------------------
Method #3 - Ping_IP-Validate_MACAddr_Against_ARP_Cache - Ping IP addr and validate MAC address matches the expected result
NOTE: Method can typically only be used when device is on same subnet as target IP device fx. router (switched
network). This method can easily be extended into an array covering all local sites, but it must be manually maintained
$Mode = "Ping_IP-Validate_MACAddr_Against_ARP_Cache"
$Target = "192.168.1.1"
$ExpectedResult = "d2-21-f9-7e-82-86"
Requirement to use V2 features
You need to update your Entra GSA client to v2.0+. You can always get the latest version using this link https://aka.ms/gsawinlatest
The updated scripts part of this blog will only work with Entra GSA client version 2.0+
Scenario: Computer is NOT connected to internal network – it can NOT do NSLOOKUP of DNS record


Result: GSA client is started

Scenario: Computer is connected to internal network – it can do NSLOOKUP of DNS record


Result: GSA is stopped

Suspension of behavior once in production
Suspension of script-behavior is built into the remediation-script, in case of rogue network detection or user wants to override.
In advance, you can prepare the suspension-script in Intune, so you quickly can activate it for a single user or multiple users. Basically it sets a reg-key.


Implementation
Using Intune Proactive Remediations, you can implement the detection and remediation scripts. Of course you want to test it before uploading to Intune 🙂
Please adjust the following parameters in the remediation script:
##################################
# VARIABLES
##################################
$Internal_DNSRecord_Name = "<put in your DNS record here>"
$Internal_DNSRecord_Expected_Response = "<put in the expected IPv4 address here>"
$RerunEveryMin = 1
$RerunNumberBeforeExiting = 59
# When it hits the number, it forces script to Exit 1. It must be less than 1 hr, as remediation job kicks off hourly
$RerunTesting = $False
# If $true it will force script to run every 2 sec. If $False, if uses $RerunEveyMin
Based on the values above, the script runs every 1 minute with 59 runs and then it terminates. The remediation script should run hourly. Feel free to fine-tune to your needs of how often you want the script to wait/run.
NOTE:
The updated V2 script must run in the context of the user, so below setting 'Run this script using the logged-on credentials' must be set to YES.

Hello Morten, have you more information about the GSA Client API?
Thanks
Flo
Stay tuned. Very soon available. We only need to sleep max 30 days 😉
Now 30 days over and I hope you have good news for us 😉
I got my hands on the new client and are testing the new feature to suspend/start Entra Private Access without stopping GSA client entirely. It is done using regkey. I’m also extending my script right now supporting 3 ways to detect local network:
DnsHostname-to-IP
IP-to-DnsHostName
IP-to-MacAddr
I hope to release by end of this week. Stay tuned
Thanks Morten
Blog has now been updated. New v2 script has been released to support the latest v2.0 features in Entra GSA.
https://mortenknudsen.net/?p=3090#EntraGSAv2
Do you have a recommendation for when the site is Entra ID, and there is no domain controller or local dns? DNS would be a tool such as DNSFilter.com which is more of a security tool. Nslookup won’t resolve the netbios names to ip. Maybe an arp -a call and matching the mac address?
Thank you for this article.
Did you happen to try the preview to use private dns?
I use it at all my customers. But they closed it as the product GAed
When do you think it will come out for everyone?
Response from PM: hey Morten, we have upgraded UDP from private preview to public preview. the changes are under deployment for portal, which is why you need to use aka.ms link. soon you won’t even need it for UDP.
for DNS, it is still under private preview and needs whitelisting from backend side. will be good sometime in July.
Thank you very much.
Will it be possible to enable it on individual Enterprise applications opppure only at the Quick Access level?
Right now I have created for each individual service an Enterprise applications (I do not use Quick Access).
Thank you again
at the moment private DNS isn’t supported for others except the quick access. It will come !
It seems if a user disables Global Secure Access, the ‘IsPrivateAccessDisabledByUser’ key no longer changes to 1. I think Microsoft might have changed this functionality in the latest version. This means if a user disables the client themselves, your script can no longer re-enable it.
Any idea how to work around this? Thanks
I don’t enforce it – on purpose !
I wanted to make sure, that a user could manually overrule the script and manually disable it.
Feel free to modify it to your needs 😊
Hi, thanks for this blog and the scripts! When will the Entra Private Access “Intelligent local access” feature be available and how is it configurable so that we don’t need the usage of those scripts anymore?
Tentative deadline for functionality in preview is 1H-CY2025
I have the private dns preview enabled. Is there a good way to get these scripts working while also using private dns? Really looking forward to that intelligent local access.
Private dns is just split tunnel so it redirects any names or ip addr part of the scope through the tunnel. And remaining goes directly. Feature will come in preview in 1H-2025
Any idea what happened to https://aka.ms/gsawinlatest
it is working fine when I use it
Should we be using this version over the one linked by MS on the learn pages, ‘https://aka.ms/globalsecureaccess-windows’ – v2.8.xx I think it was .
Also any guidance on updating clients already in use?
Sorry I should have said but the version you get from ‘https://aka.ms/gsawinlatest’ is v2.10.xx
Hello,
Is it also possible to enter several ips for the DNS lookup?
Some of our users in the office are connected to different DNS servers.
We do not use private access, but I would like to deactivate and activate the client when the user is in the office.
fabss
How to ensure all iCloud Private Relay traffic runs as it does normally on Mac before GSA set up. Even with mask.icloud fqdns and other apple fqdns that have been recommended added to internet profile (with bypasss selected), safari uses GSA egress instead of private relay.
Hello,
I would like to use this script
EntraGSA_internal_network_intune_remediationscript_V1.ps
But now I have the problem that as soon as the GSA client is connected, the internal resolution of my host xxx.xxx.xxx no longer resolves to the actual IP address, but to that of Microsoft 6.6.13.120
So of course the script thinks that I am not in the actual internal network.
I confirm, I have seen the same behavior.
Today, I have made changes to the remediation script today, as it appears to be a bug in the GSA client.
It works if we rollback to the method #1, where we disable the GSA client, instead of just disabling GSA Private Access.
Please download the updated script
https://raw.githubusercontent.com/KnudsenMorten/EntraGSA_InternalNetworkDetection_Performance/refs/heads/main/EntraGSA_internal_network_intune_remediationscript.ps1
Hello,
thanks for updating. Now I have the issue that the detection is not working correctly
Mode : Ping_IP-Resolve-to-DNSName
Target: 192.168.10.254
IP Address (response): vlan10.xxxx.local
IP Address (expected): vlan10.xxxx.local
Computer is NOT connected to internal network
Thank you very much for the updated script.
But I have the same issue with the previous reply “Computer is NOT connected to internal network” even though I was able to ping and resolve the DNSName of a local computer.
Here is what I wrote that actually does ping
################################################
# (2) Ping_DC_IP
################################################
ElseIf ($Mode -eq “Ping_DC_IP”)
{
$PingCheck1 = Test-Connection $Target1 -Count 3 -Quiet -ErrorAction SilentlyContinue
$PingCheck2 = Test-Connection $Target2 -Count 3 -Quiet -ErrorAction SilentlyContinue
If ($PingCheck1 -or $PingCheck2) # True
{
Write-Host “”
Write-Host “Target: $Target1 : $PingCheck1”
Write-Host “Target: $Target2 : $PingCheck2”
$LocalNetworkDetected = $true
}
Else
{
$LocalNetworkDetected = $false
}
}
If somebody else is having problems with the firewall profile not switching to the domain profile when connected to SSE on an external network try to Disable Negative Cache: NegativeCachePeriod DWORD registry key under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NetLogon\Parameters
value = 0
Connect / disconnect from wifi/LAN
https://learn.microsoft.com/en-us/troubleshoot/windows-client/networking/firewall-profile-not-switch-to-domain
I also found this Microsoft GSA Known issues pages.
This describes almost all of the issues we faced, with flaky dns, and the disabled by organisation error.
https://microsoft.github.io/GlobalSecureAccess/Troubleshooting/KnownIssues/
hope it helpes someone
(Micki / FORCE Technology)
Don’t suppose there is any update on if and when the wll build local network detection in to the client? I.e. bypass the GSA tunnel when on the same LAN as the server you are speaking to.
Spoke with team last week, and it is still in the backlog.
Thanks for the reply
Hi Morten, in you remediation script v2, you are saying that modifying the registry HKCU directly to disable private doesn’t works because of DNS error. It seems that is always the case, no ?
In parallel, I tried some stuff and I found that the problem regarding the DNS is after a reboot or services GSA restart, even with the registry HKCU enable for disable private access, just because I receive the NRTP (Get-DnsClientNrtpRule). If I re-enable et re-disable the private access via registry HKCU, I do not have any NRTP anymore and then the internal DNS resolution works has expected. Are you facing the same situation ?
Hi Morten, I just wanted to check, since you’ve reverted to the v1 behaviour, does that mean the script need to be run as system rather than with user creds? If that is the case, then shouldn’t the detection script regpath be pointing to an entry in HKLM instead of HKCU? Or does it not really matter?
hi morton, great script.
I am wondering if this is still required – according to the blog post:
https://techcommunity.microsoft.com/blog/microsoft-entra-blog/microsoft-entra-private-access-for-on-prem-users/3905450
“Only authentication traffic leaves the corporate network, while application traffic remains local within the corporate network. This minimizes latency and ensures that the employee can access the information they need quickly and efficiently”
it seems that maybe MS has fixed this issue?
this is not the same functionality to my knowledge
Hi Morten,
thanks for the provided script. I deployed it in our environment but we have activated “Private DNS” in quick access. When private DNS is activated the GSAClient is using the internal DNS and this leads to a deactivation also outside of the organization. Is there any solution for this or am I missing something?
Thanks in advance.
Alex
modified:
# CONFIGURATION
$EnableLoop = $true # Set to $false to run once and exit
$LoopIntervalMinutes = 5 # Interval between checks when looping
$LogRetentionDays = 15 # Days to keep log files
$TargetFQDN = “pve1.jamie”
$ExpectedIP = “192.168.2.28”
# PATHS
$LogDir = “$env:ProgramData\EntraGSA\RemediationLogs”
$LogFile = “$LogDir\RemediationLog.txt”
$ServiceName = “GlobalSecureAccessTunnelingService”
$RegPath = “HKCU:\Software\Microsoft\Global Secure Access Client”
$RegValueName = “IsPrivateAccessDisabledByUser”
# FUNCTIONS
function Write-Log {
param ([string]$Message)
$timestamp = Get-Date -Format “yyyy-MM-dd HH:mm:ss”
$entry = “$timestamp `t $Message”
Write-Host $entry
Add-Content -Path $LogFile -Value $entry
}
function Rotate-Logs {
if (Test-Path $LogFile) {
$lastWrite = (Get-Item $LogFile).LastWriteTime
if (((Get-Date) – $lastWrite).Days -ge $LogRetentionDays) {
$archived = “$LogFile.old”
if (Test-Path $archived) { Remove-Item $archived -Force }
Rename-Item $LogFile -NewName “$archived”
Write-Log “Old log archived.”
}
}
}
# INIT
if (!(Test-Path $LogDir)) {
New-Item -Path $LogDir -ItemType Directory -Force | Out-Null
}
Rotate-Logs
do {
Write-Log “—- Script Execution Started —-”
Write-Host “Flushing DNS Cache…”
ipconfig /flushdns | Out-Null
$dnsResult = Resolve-DnsName -Name $TargetFQDN -Type A -ErrorAction SilentlyContinue
if ($dnsResult -and $dnsResult.IPAddress -eq $ExpectedIP) {
Write-Log “Match found: $TargetFQDN resolved to expected IP $ExpectedIP”
$LocalNetwork = $true
} else {
Write-Log “No match: $TargetFQDN resolved to $($dnsResult.IPAddress), expected $ExpectedIP”
$LocalNetwork = $false
}
$PingSuccess = Test-Connection -ComputerName $ExpectedIP -Count 1 -Quiet -ErrorAction SilentlyContinue
Write-Host “Ping to ${ExpectedIP}: $(if ($PingSuccess) {‘Success’} else {‘Failed’})”
Write-Log “Ping to ${ExpectedIP}: $(if ($PingSuccess) {‘Success’} else {‘Failed’})”
$ServiceStatus = (Get-Service -Name $ServiceName -ErrorAction SilentlyContinue).Status
Write-Host “Current Entra Private Access Engine Service Status: $ServiceStatus”
Write-Log “Current Entra Private Access Engine Service Status: $ServiceStatus”
$regBefore = Get-ItemPropertyValue -Path $RegPath -Name $RegValueName -ErrorAction SilentlyContinue
Write-Log “Registry BEFORE action: $RegValueName = $regBefore”
if ($LocalNetwork -and $PingSuccess) {
Write-Log “Internal network detected”
if ($regBefore -ne 1) {
Set-ItemProperty -Path $RegPath -Name $RegValueName -Value 1 -Type DWord -Force
Write-Log “Private Access disabled (set to 1)”
} else {
Write-Log “Private Access already disabled”
}
} else {
Write-Log “External network or ping failed”
if ($regBefore -ne 0) {
Set-ItemProperty -Path $RegPath -Name $RegValueName -Value 0 -Type DWord -Force
Write-Log “Private Access enabled (set to 0)”
} else {
Write-Log “Private Access already enabled”
}
}
$regAfter = Get-ItemPropertyValue -Path $RegPath -Name $RegValueName -ErrorAction SilentlyContinue
Write-Log “Registry AFTER action: $RegValueName = $regAfter”
Write-Log “—- Script Execution Completed —-”
if ($EnableLoop) {
$nextRun = (Get-Date).AddMinutes($LoopIntervalMinutes).ToString(“yyyy-MM-dd HH:mm:ss”)
Write-Host “Next check scheduled at: $nextRun”
Write-Log “Next check scheduled at: $nextRun”
Start-Sleep -Seconds ($LoopIntervalMinutes * 60)
}
} while ($EnableLoop)
Exit 0
Technical Report: Entra Private Access Detection and Auto-Remediation Script
Overview
This technical report explains the design, operation, installation, and maintenance of the Entra Private Access Detection and Auto-Remediation Script. The purpose of the script is to determine whether a device is connected to an internal (corporate) network and, based on that result, enable or disable Microsoft Entra Private Access accordingly. This logic helps to ensure efficient and appropriate routing for secure application access.
Purpose and Use Case
In environments using Microsoft Global Secure Access (GSA) for secure connectivity to private applications, the GSA tunneling service must only be active when the user is not on the internal network. If the user is already within the corporate network, there’s no need to tunnel traffic via Entra Private Access. This script achieves that determination using a DNS resolution test and a direct ping check.
Use cases include:
Hybrid work environments where users switch between home networks and corporate LANs.
Branch office deployments with split access policies.
Performance optimization by disabling unnecessary tunneling.
Script Configuration and Operation
Configuration Section
$EnableLoop = $true # Set to $false to run once and exit
$LoopIntervalMinutes = 5 # Interval between checks when looping
$LogRetentionDays = 15 # Days to keep log files
$TargetFQDN = “pve1.jamie”
$ExpectedIP = “192.168.2.28”
These variables configure the script behavior:
$EnableLoop: Controls whether the script runs in a loop (true) or just once (false).
$LoopIntervalMinutes: Frequency of network checks when in loop mode.
$LogRetentionDays: Number of days to retain log data before archiving.
$TargetFQDN and $ExpectedIP: The script tests if the given FQDN resolves to the expected internal IP.
Logging and Paths
$LogDir = “$env:ProgramData\EntraGSA\RemediationLogs”
$LogFile = “$LogDir\RemediationLog.txt”
$ServiceName = “GlobalSecureAccessTunnelingService”
$RegPath = “HKCU:\Software\Microsoft\Global Secure Access Client”
$RegValueName = “IsPrivateAccessDisabledByUser”
Logs are written to a consistent path accessible to system processes.
The script tracks GSA service status and registry key values.
Key Functions
Write-Log
Outputs timestamped entries to both console and log file.
Rotate-Logs
Checks the last modification date of the log file and archives it if older than the retention period.
Detection Logic
DNS Resolution
Flushes the DNS cache: ipconfig /flushdns
Resolves the target FQDN.
Compares the result with the expected internal IP.
Ping Check
Uses Test-Connection to verify if the target IP is reachable.
Only if both DNS match and ping is successful, it assumes the internal network is detected.
Service & Registry Check
Retrieves the current status of GlobalSecureAccessTunnelingService.
Checks the registry value IsPrivateAccessDisabledByUser in HKCU:
0 = Entra Private Access Enabled.
1 = Entra Private Access Disabled.
Action Based on Detection
If internal: disables private access (sets value to 1).
If external: enables private access (sets value to 0).
Verifies and logs registry state both before and after action.
Loop Control
If $EnableLoop is true, the script sleeps for $LoopIntervalMinutes, then re-runs.
Console and log will display when the next check will occur.
Output Example
2025-07-07 21:42:40 —- Script Execution Started —-
Flushing DNS Cache…
2025-07-07 21:42:41 Match found: pve1.jamie resolved to expected IP 192.168.2.28
2025-07-07 21:42:41 Ping to 192.168.2.28: Success
2025-07-07 21:42:41 Current Entra Private Access Engine Service Status: Stopped
2025-07-07 21:42:41 Registry BEFORE action: IsPrivateAccessDisabledByUser = 1
2025-07-07 21:42:41 Internal network detected
2025-07-07 21:42:41 Private Access already disabled
2025-07-07 21:42:41 Registry AFTER action: IsPrivateAccessDisabledByUser = 1
2025-07-07 21:42:41 —- Script Execution Completed —-
Installation Steps (Microsoft Intune)
1. Prepare Script
Save the script as a .ps1 file.
Confirm it runs correctly in PowerShell 5.1 or PowerShell Core.
2. Upload to Intune
Go to Endpoint.microsoft.com.
Navigate to Devices > Scripts > Add.
Choose Windows 10 and later.
Upload your PowerShell script.
Assign it to the appropriate group.
Set the script to run in user context (since HKCU is used).
3. Schedule with Intune Remediation
For periodic execution, use Proactive Remediation:
Create a dummy detection script that returns exit code 1.
Use this script as the remediation script.
Set the schedule (e.g., every 1 hour).
Alternatively, embed this logic into a Scheduled Task that triggers at boot or every X minutes.
Permissions and Considerations
User Context
This script modifies a registry key under HKCU, so it must run in the context of the signed-in user.
This allows per-user control of Entra Private Access.
Logging Access
Log file is saved to a common path: C:\ProgramData\EntraGSA\RemediationLogs.
Logs are readable by local admins and system processes.
Registry Safety
Script only modifies one well-documented key: IsPrivateAccessDisabledByUser.
Default value is 0 (enabled), and script confirms existing state before making changes.
Security and Auditability
Logging
Provides line-by-line logging with timestamps.
Includes detection proof (DNS IP match, ping success).
Logs before/after registry state.
Log Rotation
Automatically renames log to .old after 15 days.
Prevents disk bloat.
Fail-Safe Behavior
If DNS fails or ping fails, script assumes external network.
Script is idempotent: no unnecessary changes.
Customization and Extensibility
You can customize the following:
Monitor multiple FQDNs/IPs using an array loop.
Adjust $LogRetentionDays based on compliance policy.
Expand the script to restart GSA services when toggling.
Add alerting (e.g., Event Log write or email on status change).
Troubleshooting
Issue
Cause
Solution
Script doesn’t run
Wrong execution context
Ensure “run in user context” in Intune
Registry not changing
No DNS/IP match
Validate internal network resolution
Log not created
Permissions issue
Check that ProgramData path is writeable
Loop doesn’t trigger
$EnableLoop = $false
Set $EnableLoop = $true to run indefinitely
Summary
This script provides a clean, policy-compliant solution to dynamically manage Microsoft Entra Private Access. With real-time detection of the local network, verified by both DNS and ping responses, the logic is resilient and conservative, making no unnecessary changes. Logging, registry state capture, and loop control make it suitable for both Intune remediation and standalone scheduled task deployments.
By customizing this script to match your network design, you ensure optimal connectivity and end-user experience without compromising security.
Technical Report: Entra Private Access Detection and Auto-Remediation Script
Overview
This technical report explains the design, operation, installation, and maintenance of the Entra Private Access Detection and Auto-Remediation Script. The purpose of the script is to determine whether a device is connected to an internal (corporate) network and, based on that result, enable or disable Microsoft Entra Private Access accordingly. This logic helps to ensure efficient and appropriate routing for secure application access.
Purpose and Use Case
In environments using Microsoft Global Secure Access (GSA) for secure connectivity to private applications, the GSA tunneling service must only be active when the user is not on the internal network. If the user is already within the corporate network, there’s no need to tunnel traffic via Entra Private Access. This script achieves that determination using a DNS resolution test and a direct ping check.
Use cases include:
Hybrid work environments where users switch between home networks and corporate LANs.
Branch office deployments with split access policies.
Performance optimization by disabling unnecessary tunneling.
Script Configuration and Operation
Configuration Section
$EnableLoop = $true # Set to $false to run once and exit
$LoopIntervalMinutes = 5 # Interval between checks when looping
$LogRetentionDays = 15 # Days to keep log files
$TargetFQDN = “pve1.jamie”
$ExpectedIP = “192.168.2.28”
These variables configure the script behavior:
$EnableLoop: Controls whether the script runs in a loop (true) or just once (false).
$LoopIntervalMinutes: Frequency of network checks when in loop mode.
$LogRetentionDays: Number of days to retain log data before archiving.
$TargetFQDN and $ExpectedIP: The script tests if the given FQDN resolves to the expected internal IP.
Logging and Paths
$LogDir = “$env:ProgramData\EntraGSA\RemediationLogs”
$LogFile = “$LogDir\RemediationLog.txt”
$ServiceName = “GlobalSecureAccessTunnelingService”
$RegPath = “HKCU:\Software\Microsoft\Global Secure Access Client”
$RegValueName = “IsPrivateAccessDisabledByUser”
Logs are written to a consistent path accessible to system processes.
The script tracks GSA service status and registry key values.
Key Functions
Write-Log
Outputs timestamped entries to both console and log file.
Rotate-Logs
Checks the last modification date of the log file and archives it if older than the retention period.
Detection Logic
DNS Resolution
Flushes the DNS cache: ipconfig /flushdns
Resolves the target FQDN.
Compares the result with the expected internal IP.
Ping Check
Uses Test-Connection to verify if the target IP is reachable.
Only if both DNS match and ping is successful, it assumes the internal network is detected.
Service & Registry Check
Retrieves the current status of GlobalSecureAccessTunnelingService.
Checks the registry value IsPrivateAccessDisabledByUser in HKCU:
0 = Entra Private Access Enabled.
1 = Entra Private Access Disabled.
Action Based on Detection
If internal: disables private access (sets value to 1).
If external: enables private access (sets value to 0).
Verifies and logs registry state both before and after action.
Loop Control
If $EnableLoop is true, the script sleeps for $LoopIntervalMinutes, then re-runs.
Console and log will display when the next check will occur.
Output Example
2025-07-07 21:42:40 —- Script Execution Started —-
Flushing DNS Cache…
2025-07-07 21:42:41 Match found: pve1.jamie resolved to expected IP 192.168.2.28
2025-07-07 21:42:41 Ping to 192.168.2.28: Success
2025-07-07 21:42:41 Current Entra Private Access Engine Service Status: Stopped
2025-07-07 21:42:41 Registry BEFORE action: IsPrivateAccessDisabledByUser = 1
2025-07-07 21:42:41 Internal network detected
2025-07-07 21:42:41 Private Access already disabled
2025-07-07 21:42:41 Registry AFTER action: IsPrivateAccessDisabledByUser = 1
2025-07-07 21:42:41 —- Script Execution Completed —-
Installation Steps (Microsoft Intune)
1. Prepare Script
Save the script as a .ps1 file.
Confirm it runs correctly in PowerShell 5.1 or PowerShell Core.
2. Upload to Intune
Go to Endpoint.microsoft.com.
Navigate to Devices > Scripts > Add.
Choose Windows 10 and later.
Upload your PowerShell script.
Assign it to the appropriate group.
Set the script to run in user context (since HKCU is used).
3. Schedule with Intune Remediation
For periodic execution, use Proactive Remediation:
Create a dummy detection script that returns exit code 1.
Use this script as the remediation script.
Set the schedule (e.g., every 1 hour).
Alternatively, embed this logic into a Scheduled Task that triggers at boot or every X minutes.
Permissions and Considerations
User Context
This script modifies a registry key under HKCU, so it must run in the context of the signed-in user.
This allows per-user control of Entra Private Access.
Logging Access
Log file is saved to a common path: C:\ProgramData\EntraGSA\RemediationLogs.
Logs are readable by local admins and system processes.
Registry Safety
Script only modifies one well-documented key: IsPrivateAccessDisabledByUser.
Default value is 0 (enabled), and script confirms existing state before making changes.
Security and Auditability
Logging
Provides line-by-line logging with timestamps.
Includes detection proof (DNS IP match, ping success).
Logs before/after registry state.
Log Rotation
Automatically renames log to .old after 15 days.
Prevents disk bloat.
Fail-Safe Behavior
If DNS fails or ping fails, script assumes external network.
Script is idempotent: no unnecessary changes.
Customization and Extensibility
You can customize the following:
Monitor multiple FQDNs/IPs using an array loop.
Adjust $LogRetentionDays based on compliance policy.
Expand the script to restart GSA services when toggling.
Add alerting (e.g., Event Log write or email on status change).
Troubleshooting
Issue
Cause
Solution
Script doesn’t run
Wrong execution context
Ensure “run in user context” in Intune
Registry not changing
No DNS/IP match
Validate internal network resolution
Log not created
Permissions issue
Check that ProgramData path is writeable
Loop doesn’t trigger
$EnableLoop = $false
Set $EnableLoop = $true to run indefinitely
Summary
This script provides a clean, policy-compliant solution to dynamically manage Microsoft Entra Private Access. With real-time detection of the local network, verified by both DNS and ping responses, the logic is resilient and conservative, making no unnecessary changes. Logging, registry state capture, and loop control make it suitable for both Intune remediation and standalone scheduled task deployments.
Guessing intelligent local access is still not realeased? Seeing lots of talk about it being release in 2nd half of 2024, then 1st half of 2025, but from what I can see this still does not exist.
seems to have been integrated into entra side not the client; https://learn.microsoft.com/en-us/entra/global-secure-access/enable-intelligent-local-access
great