Entra Private Access/GSA – Automatic Network Detection

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.

TimingFunctionality
June 2024Script (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 2024My 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- 2024Entra 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

PathKeyValue (DWORD)
HKCU\Software\Microsoft\Global Secure Access ClientIsPrivateAccessDisabledByUser0 = 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

PathKeyValue (DWORD)
HKLM\Software\Microsoft\Global Secure Access ClientHideDisablePrivateAccessButton0 = 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

Screenshot shows script runs in testing mode every 2 sec $RerunTesting = $True. You can disable testing, by setting to $true and then it will run with the parameter you define in $RerunEveryMin

Result: GSA client is started

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

Screenshot shows script runs in testing mode every 2 sec $RerunTesting = $True. You can disable testing, by setting to $true and then it will run with the parameter you define in $RerunEveryMin

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. 

45 thoughts on “Entra Private Access/GSA – Automatic Network Detection”

  1. 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?

    Reply
        • 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.

          Reply
          • 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

  2. 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

    Reply
    • 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 😊

      Reply
  3. 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?

    Reply
  4. 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.

    Reply
    • 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

      Reply
      • 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?

        Reply
        • Sorry I should have said but the version you get from ‘https://aka.ms/gsawinlatest’ is v2.10.xx

          Reply
  5. 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

    Reply
  6. 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.

    Reply
  7. 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.

    Reply
    • 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

      Reply
      • 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

        Reply
      • 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.

        Reply
        • 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
          }
          }

          Reply
  8. 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.

    Reply
  9. 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 ?

    Reply
  10. 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?

    Reply
  11. 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?

    Reply
  12. 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

    Reply
  13. 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

    Reply
  14. 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.

    Reply
  15. 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.

    Reply

Leave a Reply