<# .SYNOPSIS Displays Exchange Client Access URLs and optional authentication settings. .DESCRIPTION Displays Exchange Client Access URLs and namespaces for Microsoft Exchange Server 2016, Exchange Server 2019, and Exchange Server Subscription Edition. By default, all Exchange Mailbox servers are queried and results are grouped by server. Use -Server to query specific servers. Use -Service to display only selected Client Access services. Use -GroupBy Service to compare the same service across multiple servers. Use -IncludeAuthentication to include authentication settings. Use -OutputFile to save the same formatted output to a text file. N/A = The property is not applicable or is not exposed by that component. Not Configured = The property exists, but the value is empty or null. .PARAMETER Server Optional. Exchange Mailbox server(s) to query. If omitted, all Exchange Mailbox servers in the organization are queried. .PARAMETER Service Optional. Displays only the selected Client Access services. Valid values: Autodiscover ECP EWS MAPI ActiveSync OAB OWA PowerShell OutlookAnywhere .PARAMETER GroupBy Controls the output layout. Server = Show all selected services under each server. This is the default. Service = Show all selected servers under each service. .PARAMETER IncludeAuthentication Optional. Includes authentication settings for each Client Access component. .PARAMETER OutputFile Optional. Saves the same formatted output shown on screen to a text file. If the parent folder does not exist, the script creates it. .EXAMPLE .\Get-ExchangeURLs-v2.ps1 Queries all Exchange Mailbox servers and groups the results by server. .EXAMPLE .\Get-ExchangeURLs-v2.ps1 -Server EX601 Queries only EX601. .EXAMPLE .\Get-ExchangeURLs-v2.ps1 -Server EX601,EX602 Queries EX601 and EX602 and groups the results by server. .EXAMPLE .\Get-ExchangeURLs-v2.ps1 -Server EX601,EX602 -GroupBy Service Compares the same Client Access services across EX601 and EX602. .EXAMPLE .\Get-ExchangeURLs-v2.ps1 -Service MAPI,EWS Queries all Exchange Mailbox servers but displays only MAPI and EWS. .EXAMPLE .\Get-ExchangeURLs-v2.ps1 -Server EX601 -Service MAPI,EWS Queries only MAPI and EWS on EX601. .EXAMPLE .\Get-ExchangeURLs-v2.ps1 -Server EX601 -IncludeAuthentication Displays URLs and authentication settings for EX601. .EXAMPLE .\Get-ExchangeURLs-v2.ps1 -GroupBy Service -IncludeAuthentication Queries all Exchange Mailbox servers, groups the output by service, and includes authentication settings. .EXAMPLE .\Get-ExchangeURLs-v2.ps1 -Server EX601 -OutputFile C:\Temp\ExchangeURLs.txt Queries EX601 and saves the formatted output to C:\Temp\ExchangeURLs.txt. .EXAMPLE .\Get-ExchangeURLs-v2.ps1 -Server EX601,EX602 -Service MAPI,EWS -GroupBy Service -IncludeAuthentication -OutputFile C:\Temp\ExchangeURLs-Auth.txt Compares MAPI and EWS across EX601 and EX602, includes authentication settings, and saves the formatted output to a text file. .NOTES Originally written by: Paul Cunningham Edited by: Ali Tajran Further updated by: Ceyhun Kirmizitas Change Log: V1.00, 27/08/2015 - Initial version by Paul Cunningham. V1.10, 18/04/2020 - Added PowerShell virtual directory and reordered output to match the EAC virtual directory list. Updated by Ali Tajran. V2, 25/08/2026 - Updated Get-ClientAccessServer to Get-ClientAccessService. Added Autodiscover virtual directory details. Added optional authentication output with -IncludeAuthentication. Added optional text-file output with -OutputFile. Added N/A and Not Configured output. Removed -ADPropertiesOnly so AD and IIS-backed properties can be returned where available. Made -Server optional; if omitted, all Exchange Mailbox servers in the organization are queried. Added -Service filtering (for example: -Service MAPI,EWS). Added -GroupBy Server and -GroupBy Service output modes (for example: -GroupBy Service). Added combined filtering/grouping support (for example: -Service MAPI,EWS -GroupBy Service). Expanded built-in examples and parameter documentation. Updated by Ceyhun Kirmizitas. #> #requires -version 5.1 [CmdletBinding()] param( [Parameter(Position=0)] [string[]]$Server, [ValidateSet( "Autodiscover", "ECP", "EWS", "MAPI", "ActiveSync", "OAB", "OWA", "PowerShell", "OutlookAnywhere" )] [string[]]$Service, [ValidateSet("Server","Service")] [string]$GroupBy = "Server", [switch]$IncludeAuthentication, [string]$OutputFile ) # ------------------------------------------------------------ # Load Exchange Management Shell if required # ------------------------------------------------------------ if (-not (Get-Command Get-ExchangeServer -ErrorAction SilentlyContinue)) { if ([string]::IsNullOrWhiteSpace($env:ExchangeInstallPath)) { Write-Error "Exchange Server management tools are not installed on this computer." exit 1 } $RemoteExchange = Join-Path $env:ExchangeInstallPath "bin\RemoteExchange.ps1" if (Test-Path $RemoteExchange) { . $RemoteExchange Connect-ExchangeServer -Auto -AllowClobber } else { Write-Error "Exchange Server management tools are not installed on this computer." exit 1 } } # ------------------------------------------------------------ # Optional output file # ------------------------------------------------------------ $script:OutputFilePath = $null if ($OutputFile) { $OutputDirectory = Split-Path -Path $OutputFile -Parent if ($OutputDirectory -and -not (Test-Path $OutputDirectory)) { New-Item -Path $OutputDirectory -ItemType Directory -Force | Out-Null } if (Test-Path $OutputFile) { Remove-Item $OutputFile -Force } $script:OutputFilePath = $OutputFile } # ------------------------------------------------------------ # Service definitions # ------------------------------------------------------------ $AllServices = @( "Autodiscover", "ECP", "EWS", "MAPI", "ActiveSync", "OAB", "OWA", "PowerShell", "OutlookAnywhere" ) $ServiceTitles = @{ Autodiscover = "Autodiscover" ECP = "Exchange Control Panel" EWS = "Exchange Web Services" MAPI = "MAPI" ActiveSync = "ActiveSync" OAB = "Offline Address Book" OWA = "Outlook on the web" PowerShell = "PowerShell" OutlookAnywhere = "Outlook Anywhere" } if ($Service) { $SelectedServices = @($AllServices | Where-Object { $Service -contains $_ }) } else { $SelectedServices = $AllServices } # ------------------------------------------------------------ # Helper functions # ------------------------------------------------------------ function Write-Result { param( [string]$Text = "", [ConsoleColor]$Color ) if ($PSBoundParameters.ContainsKey("Color")) { Write-Host $Text -ForegroundColor $Color } else { Write-Host $Text } if ($script:OutputFilePath) { Add-Content -Path $script:OutputFilePath -Value $Text -Encoding UTF8 } } function Format-ExchangeValue { param( [object]$Value ) if ($null -eq $Value) { return "Not Configured" } if ($Value -is [string]) { if ([string]::IsNullOrWhiteSpace($Value)) { return "Not Configured" } return $Value } if ($Value -is [System.Collections.IEnumerable] -and -not ($Value -is [string])) { $Items = @($Value | ForEach-Object { "$_" }) if ($Items.Count -eq 0) { return "Not Configured" } return ($Items -join ", ") } return "$Value" } function Get-ExchangePropertyValue { param( [object]$Object, [string[]]$PropertyNames ) if ($null -eq $Object) { return "N/A" } foreach ($PropertyName in $PropertyNames) { $Property = $Object.PSObject.Properties[$PropertyName] if ($null -ne $Property) { return (Format-ExchangeValue -Value $Property.Value) } } return "N/A" } function Write-ExchangeField { param( [string]$Label, [string]$Value ) Write-Result (" - {0,-34}: {1}" -f $Label, $Value) } function Write-AuthenticationSettings { param( [object]$Object ) Write-Result " Authentication" Write-ExchangeField "Basic Authentication" ` (Get-ExchangePropertyValue $Object @("BasicAuthentication","BasicAuthEnabled")) Write-ExchangeField "Windows Authentication" ` (Get-ExchangePropertyValue $Object @("WindowsAuthentication","WindowsAuthEnabled")) Write-ExchangeField "Forms Authentication" ` (Get-ExchangePropertyValue $Object @("FormsAuthentication")) Write-ExchangeField "Digest Authentication" ` (Get-ExchangePropertyValue $Object @("DigestAuthentication")) Write-ExchangeField "OAuth Authentication" ` (Get-ExchangePropertyValue $Object @("OAuthAuthentication")) Write-ExchangeField "ADFS Authentication" ` (Get-ExchangePropertyValue $Object @("AdfsAuthentication")) Write-ExchangeField "WS-Security Authentication" ` (Get-ExchangePropertyValue $Object @("WSSecurityAuthentication")) Write-ExchangeField "Certificate Authentication" ` (Get-ExchangePropertyValue $Object @("CertificateAuthentication")) Write-ExchangeField "Client Certificate Authentication" ` (Get-ExchangePropertyValue $Object @("ClientCertAuth")) Write-ExchangeField "IIS Authentication Methods" ` (Get-ExchangePropertyValue $Object @("IISAuthenticationMethods")) Write-ExchangeField "Internal Authentication Methods" ` (Get-ExchangePropertyValue $Object @("InternalAuthenticationMethods")) Write-ExchangeField "External Authentication Methods" ` (Get-ExchangePropertyValue $Object @("ExternalAuthenticationMethods")) } function Get-SafeExchangeData { param( [string]$Label, [scriptblock]$Query ) try { & $Query } catch { Write-Result "WARNING: $Label query failed: $($_.Exception.Message)" Yellow return $null } } function Get-ServiceData { param( [string]$ServerName, [string]$ServiceName ) switch ($ServiceName) { "Autodiscover" { $ClientAccessService = Get-SafeExchangeData "Client Access Service on $ServerName" { Get-ClientAccessService -Identity $ServerName -ErrorAction Stop } $Objects = @(Get-SafeExchangeData "Autodiscover on $ServerName" { Get-AutodiscoverVirtualDirectory -Server $ServerName -ErrorAction Stop }) return [PSCustomObject]@{ ClientAccessService = $ClientAccessService Objects = $Objects } } "ECP" { return @(Get-SafeExchangeData "ECP on $ServerName" { Get-EcpVirtualDirectory -Server $ServerName -ErrorAction Stop }) } "EWS" { return @(Get-SafeExchangeData "EWS on $ServerName" { Get-WebServicesVirtualDirectory -Server $ServerName -ErrorAction Stop }) } "MAPI" { return @(Get-SafeExchangeData "MAPI on $ServerName" { Get-MapiVirtualDirectory -Server $ServerName -ErrorAction Stop }) } "ActiveSync" { return @(Get-SafeExchangeData "ActiveSync on $ServerName" { Get-ActiveSyncVirtualDirectory -Server $ServerName -ErrorAction Stop }) } "OAB" { return @(Get-SafeExchangeData "OAB on $ServerName" { Get-OabVirtualDirectory -Server $ServerName -ErrorAction Stop }) } "OWA" { return @(Get-SafeExchangeData "OWA on $ServerName" { Get-OwaVirtualDirectory -Server $ServerName -ErrorAction Stop }) } "PowerShell" { return @(Get-SafeExchangeData "PowerShell on $ServerName" { Get-PowerShellVirtualDirectory -Server $ServerName -ErrorAction Stop }) } "OutlookAnywhere" { return @(Get-SafeExchangeData "Outlook Anywhere on $ServerName" { Get-OutlookAnywhere -Server $ServerName -ErrorAction Stop }) } } } function Write-StandardVirtualDirectory { param( [object[]]$Objects ) if ($null -eq $Objects -or $Objects.Count -eq 0) { Write-ExchangeField "Identity" "N/A" Write-ExchangeField "Internal URL" "N/A" Write-ExchangeField "External URL" "N/A" Write-ExchangeField "Require SSL" "N/A" if ($IncludeAuthentication) { Write-AuthenticationSettings $null } return } foreach ($Object in $Objects) { Write-ExchangeField "Identity" ` (Get-ExchangePropertyValue $Object @("Identity")) Write-ExchangeField "Internal URL" ` (Get-ExchangePropertyValue $Object @("InternalUrl")) Write-ExchangeField "External URL" ` (Get-ExchangePropertyValue $Object @("ExternalUrl")) Write-ExchangeField "Require SSL" ` (Get-ExchangePropertyValue $Object @("RequireSSL")) if ($IncludeAuthentication) { Write-AuthenticationSettings $Object } } } function Write-Autodiscover { param( [object]$Data ) $ClientAccessService = $Data.ClientAccessService $Objects = @($Data.Objects) if ($Objects.Count -eq 0) { Write-ExchangeField "Identity" "N/A" Write-ExchangeField "Internal SCP" ` (Get-ExchangePropertyValue $ClientAccessService @("AutoDiscoverServiceInternalUri")) Write-ExchangeField "Internal URL" "N/A (Exchange 2013+)" Write-ExchangeField "External URL" "N/A (Exchange 2013+)" Write-ExchangeField "Require SSL" "N/A" if ($IncludeAuthentication) { Write-AuthenticationSettings $null } return } foreach ($Object in $Objects) { Write-ExchangeField "Identity" ` (Get-ExchangePropertyValue $Object @("Identity")) Write-ExchangeField "Internal SCP" ` (Get-ExchangePropertyValue $ClientAccessService @("AutoDiscoverServiceInternalUri")) Write-ExchangeField "Internal URL" "N/A (Exchange 2013+)" Write-ExchangeField "External URL" "N/A (Exchange 2013+)" Write-ExchangeField "Require SSL" ` (Get-ExchangePropertyValue $Object @("RequireSSL")) if ($IncludeAuthentication) { Write-AuthenticationSettings $Object } } } function Write-OutlookAnywhere { param( [object[]]$Objects ) if ($null -eq $Objects -or $Objects.Count -eq 0) { Write-ExchangeField "Identity" "N/A" Write-ExchangeField "Internal Hostname" "N/A" Write-ExchangeField "External Hostname" "N/A" Write-ExchangeField "Internal URL" "N/A" Write-ExchangeField "External URL" "N/A" if ($IncludeAuthentication) { Write-AuthenticationSettings $null Write-ExchangeField "Internal Client Authentication" "N/A" Write-ExchangeField "External Client Authentication" "N/A" } Write-ExchangeField "Internal Clients Require SSL" "N/A" Write-ExchangeField "External Clients Require SSL" "N/A" Write-ExchangeField "SSL Offloading" "N/A" return } foreach ($Object in $Objects) { Write-ExchangeField "Identity" ` (Get-ExchangePropertyValue $Object @("Identity")) Write-ExchangeField "Internal Hostname" ` (Get-ExchangePropertyValue $Object @("InternalHostname")) Write-ExchangeField "External Hostname" ` (Get-ExchangePropertyValue $Object @("ExternalHostname")) Write-ExchangeField "Internal URL" "N/A" Write-ExchangeField "External URL" "N/A" if ($IncludeAuthentication) { Write-AuthenticationSettings $Object Write-ExchangeField "Internal Client Authentication" ` (Get-ExchangePropertyValue $Object @("InternalClientAuthenticationMethod")) Write-ExchangeField "External Client Authentication" ` (Get-ExchangePropertyValue $Object @("ExternalClientAuthenticationMethod")) } Write-ExchangeField "Internal Clients Require SSL" ` (Get-ExchangePropertyValue $Object @("InternalClientsRequireSsl")) Write-ExchangeField "External Clients Require SSL" ` (Get-ExchangePropertyValue $Object @("ExternalClientsRequireSsl")) Write-ExchangeField "SSL Offloading" ` (Get-ExchangePropertyValue $Object @("SSLOffloading")) } } function Write-ServiceDetails { param( [string]$ServiceName, [object]$Data ) switch ($ServiceName) { "Autodiscover" { Write-Autodiscover $Data } "OutlookAnywhere" { Write-OutlookAnywhere @($Data) } default { Write-StandardVirtualDirectory @($Data) } } } # ------------------------------------------------------------ # Resolve servers # ------------------------------------------------------------ if (-not $Server) { $Server = @( Get-ExchangeServer | Where-Object { "$($_.ServerRole)" -match "Mailbox|ClientAccess" } | Sort-Object Name | Select-Object -ExpandProperty Name ) } if (-not $Server -or $Server.Count -eq 0) { Write-Error "No Exchange Mailbox servers were found." exit 1 } $ServerInfo = [ordered]@{} $Results = [ordered]@{} foreach ($ServerName in $Server) { try { $ExchangeServer = Get-ExchangeServer -Identity $ServerName -ErrorAction Stop } catch { Write-Result "WARNING: Exchange server '$ServerName' was not found." Yellow continue } if ("$($ExchangeServer.ServerRole)" -notmatch "Mailbox|ClientAccess") { Write-Result "WARNING: $ServerName does not host Exchange Client Access services." Yellow continue } $ServerInfo[$ExchangeServer.Name] = $ExchangeServer $Results[$ExchangeServer.Name] = [ordered]@{} foreach ($ServiceName in $SelectedServices) { $Results[$ExchangeServer.Name][$ServiceName] = Get-ServiceData ` -ServerName $ExchangeServer.Name ` -ServiceName $ServiceName } } if ($ServerInfo.Count -eq 0) { Write-Error "No valid Exchange Mailbox servers were available to query." exit 1 } # ------------------------------------------------------------ # Output # ------------------------------------------------------------ Write-Result "" Write-Result "Get-ExchangeURLs.ps1 - Version 2" Yellow Write-ExchangeField "Group By" $GroupBy Write-ExchangeField "Services" ($SelectedServices -join ", ") if ($IncludeAuthentication) { Write-ExchangeField "Authentication Details" "Enabled" } Write-Result "" if ($GroupBy -eq "Server") { foreach ($ServerName in $ServerInfo.Keys) { $ExchangeServer = $ServerInfo[$ServerName] Write-Result "======================================================================" Green Write-Result " Server: $ServerName" Green Write-Result "======================================================================" Green Write-ExchangeField "FQDN" "$($ExchangeServer.Fqdn)" Write-ExchangeField "Version" "$($ExchangeServer.AdminDisplayVersion)" Write-ExchangeField "Edition" "$($ExchangeServer.Edition)" Write-Result "" foreach ($ServiceName in $SelectedServices) { Write-Result $ServiceTitles[$ServiceName] Cyan Write-ServiceDetails ` -ServiceName $ServiceName ` -Data $Results[$ServerName][$ServiceName] Write-Result "" } } } else { foreach ($ServiceName in $SelectedServices) { Write-Result "======================================================================" Cyan Write-Result " $($ServiceTitles[$ServiceName])" Cyan Write-Result "======================================================================" Cyan foreach ($ServerName in $ServerInfo.Keys) { $ExchangeServer = $ServerInfo[$ServerName] Write-Result "Server: $ServerName ($($ExchangeServer.Fqdn))" Green Write-ServiceDetails ` -ServiceName $ServiceName ` -Data $Results[$ServerName][$ServiceName] Write-Result "" } } } Write-Result "Finished querying all selected servers." Green if ($script:OutputFilePath) { Write-Host "" Write-Host "Output saved to: $script:OutputFilePath" -ForegroundColor Yellow }