Skip to content

Instantly share code, notes, and snippets.

@ayZagen
Created August 10, 2026 18:57
Show Gist options
  • Select an option

  • Save ayZagen/7c30e16c70eff577399cea08e56d49bc to your computer and use it in GitHub Desktop.

Select an option

Save ayZagen/7c30e16c70eff577399cea08e56d49bc to your computer and use it in GitHub Desktop.
Exchange Server Auth Diagnostic
#requires -Version 5.1
<#
.SYNOPSIS
Exchange environment diagnostic for Exchange / OAuth / Hybrid / ADFS discovery.
.DESCRIPTION
Collects read-only information needed to determine:
- Exchange version and CU/build
- Exchange Hybrid configuration
- Microsoft Entra / Azure AD OAuth configuration
- Exchange Modern Authentication configuration
- ADFS configuration
- Microsoft Entra Connect presence
- ActiveSync / Autodiscover / MAPI / EWS configuration
- Exchange certificates
- Accepted domains
- Federation configuration
- Mailbox protocol configuration
- IIS bindings
- Exchange namespaces
The script automatically:
1. Requests Administrator privileges.
2. Loads Exchange Management Shell.
3. Connects to the local Exchange server if necessary.
4. Collects the diagnostic information.
5. Saves the output to Exchange-Diagnostic.txt.
.NOTES
Read-only diagnostic.
No Exchange configuration is modified.
#>
$ErrorActionPreference = "Continue"
# ============================================================
# Configuration
# ============================================================
$OutputFile = Join-Path $PSScriptRoot "Exchange-Diagnostic.txt"
# ============================================================
# Helper functions
# ============================================================
function Test-IsAdministrator {
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($identity)
return $principal.IsInRole(
[Security.Principal.WindowsBuiltInRole]::Administrator
)
}
function Write-Section {
param(
[Parameter(Mandatory = $true)]
[string]$Title
)
Write-Host ""
Write-Host "============================================================" -ForegroundColor Cyan
Write-Host " $Title" -ForegroundColor Cyan
Write-Host "============================================================" -ForegroundColor Cyan
Write-Host ""
}
function Write-Value {
param(
[string]$Name,
$Value
)
if ($null -eq $Value -or $Value -eq "") {
$Value = "<not configured / not found>"
}
Write-Host ("{0,-38}: {1}" -f $Name, $Value)
}
# ============================================================
# Automatically request Administrator privileges
# ============================================================
if (-not (Test-IsAdministrator)) {
Write-Host ""
Write-Host "Administrator privileges are required." -ForegroundColor Yellow
Write-Host "Requesting elevation..." -ForegroundColor Yellow
Write-Host ""
try {
Start-Process `
-FilePath "powershell.exe" `
-ArgumentList @(
"-NoProfile"
"-ExecutionPolicy", "Bypass"
"-File", "`"$($MyInvocation.MyCommand.Path)`""
) `
-Verb RunAs
exit
}
catch {
Write-Host ""
Write-Host "Failed to obtain Administrator privileges." -ForegroundColor Red
Write-Host $_.Exception.Message -ForegroundColor Red
Write-Host ""
Read-Host "Press Enter to exit"
exit 1
}
}
# ============================================================
# Locate Exchange Management Shell
# ============================================================
$ExchangeLoaded = $false
if (Get-Command Get-ExchangeServer -ErrorAction SilentlyContinue) {
$ExchangeLoaded = $true
}
if (-not $ExchangeLoaded) {
Write-Host ""
Write-Host "Exchange Management Shell is not loaded." -ForegroundColor Yellow
Write-Host "Looking for Exchange Management Shell..." -ForegroundColor Yellow
Write-Host ""
$ExchangeShellCandidates = @(
"$env:ExchangeInstallPath\bin\RemoteExchange.ps1"
"${env:ProgramFiles}\Microsoft\Exchange Server\V15\bin\RemoteExchange.ps1"
"${env:ProgramFiles(x86)}\Microsoft\Exchange Server\V15\bin\RemoteExchange.ps1"
)
$RemoteExchangeScript = $ExchangeShellCandidates |
Where-Object {
$_ -and (Test-Path $_)
} |
Select-Object -First 1
if ($RemoteExchangeScript) {
Write-Host "Found Exchange Management Shell:" -ForegroundColor Green
Write-Host $RemoteExchangeScript
Write-Host ""
try {
. $RemoteExchangeScript
if (Get-Command Connect-ExchangeServer -ErrorAction SilentlyContinue) {
Write-Host "Connecting to local Exchange server..." -ForegroundColor Yellow
Connect-ExchangeServer `
-Auto `
-ClientApplication:ManagementShell `
-ErrorAction Stop
}
}
catch {
Write-Host ""
Write-Host "Failed to initialize Exchange Management Shell." -ForegroundColor Red
Write-Host $_.Exception.Message -ForegroundColor Red
Write-Host ""
Read-Host "Press Enter to exit"
exit 1
}
}
}
# ============================================================
# Verify Exchange cmdlets
# ============================================================
if (-not (Get-Command Get-ExchangeServer -ErrorAction SilentlyContinue)) {
Write-Host ""
Write-Host "ERROR: Exchange Management Shell could not be initialized." -ForegroundColor Red
Write-Host ""
Write-Host "Run this script directly on an Exchange server." -ForegroundColor Yellow
Write-Host ""
Read-Host "Press Enter to exit"
exit 1
}
# ============================================================
# Start transcript
# ============================================================
try {
Start-Transcript -Path $OutputFile -Force | Out-Null
}
catch {
Write-Host "WARNING: Could not create transcript file." -ForegroundColor Red
}
Clear-Host
# ============================================================
# Header
# ============================================================
Write-Host ""
Write-Host "============================================================" -ForegroundColor Green
Write-Host " Exchange Environment Diagnostic" -ForegroundColor Green
Write-Host "============================================================" -ForegroundColor Green
Write-Host ""
Write-Value "Computer" $env:COMPUTERNAME
Write-Value "User" $env:USERNAME
Write-Value "Date" (Get-Date)
# ============================================================
# Windows Server information
# ============================================================
Write-Section "WINDOWS SERVER"
Get-CimInstance Win32_OperatingSystem |
Select-Object `
Caption,
Version,
BuildNumber,
OSArchitecture,
InstallDate,
LastBootUpTime |
Format-List
# ============================================================
# Exchange servers
# ============================================================
Write-Section "EXCHANGE SERVERS"
$ExchangeServers = Get-ExchangeServer
$ExchangeServers |
Select-Object `
Name,
Fqdn,
Edition,
AdminDisplayVersion,
ServerRole,
Site,
ServerSite |
Format-List
# ============================================================
# Organization configuration
# ============================================================
Write-Section "ORGANIZATION CONFIGURATION"
Get-OrganizationConfig |
Select-Object `
Name,
DistinguishedName,
OAuth2ClientProfileEnabled,
AdfsIssuer,
AdfsAudienceUris,
AdfsSignCertificateThumbprint,
DefaultAuthenticationPolicy,
MapiHttpEnabled,
ActivityBasedAuthenticationTimeoutEnabled |
Format-List
# ============================================================
# Full OAuth configuration
# ============================================================
Write-Section "EXCHANGE OAUTH CONFIGURATION"
Get-AuthConfig |
Format-List *
# ============================================================
# Auth servers
# ============================================================
Write-Section "EXCHANGE AUTH SERVERS"
Get-AuthServer |
Format-List *
# ============================================================
# Hybrid configuration
# ============================================================
Write-Section "HYBRID CONFIGURATION"
$Hybrid = Get-HybridConfiguration -ErrorAction SilentlyContinue
if ($null -eq $Hybrid) {
Write-Host "No Hybrid Configuration found."
}
else {
$Hybrid |
Format-List *
}
# ============================================================
# Intra Organization Connectors
# ============================================================
Write-Section "INTRA ORGANIZATION CONNECTORS"
$IOC = Get-IntraOrganizationConnector -ErrorAction SilentlyContinue
if ($null -eq $IOC) {
Write-Host "No Intra Organization Connector found."
}
else {
$IOC |
Format-List *
}
# ============================================================
# Organization relationships
# ============================================================
Write-Section "ORGANIZATION RELATIONSHIPS"
$Relationships = Get-OrganizationRelationship -ErrorAction SilentlyContinue
if ($null -eq $Relationships) {
Write-Host "No Organization Relationships found."
}
else {
$Relationships |
Format-List *
}
# ============================================================
# Federation Trust
# ============================================================
Write-Section "EXCHANGE FEDERATION TRUST"
$FederationTrust = Get-FederationTrust -ErrorAction SilentlyContinue
if ($null -eq $FederationTrust) {
Write-Host "No Exchange Federation Trust found."
}
else {
$FederationTrust |
Select-Object `
Name,
TokenIssuerUri,
TokenIssuerCertificate,
OrgCertificate,
OrgNextCertificate,
TokenIssuerPrevCertificate,
TokenIssuerPrevCertificate |
Format-List
}
# ============================================================
# Accepted domains
# ============================================================
Write-Section "ACCEPTED DOMAINS"
Get-AcceptedDomain |
Select-Object `
Name,
DomainName,
DomainType,
Default,
MatchSubDomains |
Format-Table -AutoSize
# ============================================================
# Email address policies
# ============================================================
Write-Section "EMAIL ADDRESS POLICIES"
Get-EmailAddressPolicy |
Select-Object `
Name,
EnabledEmailAddressTemplates,
RecipientFilter |
Format-List
# ============================================================
# ActiveSync
# ============================================================
Write-Section "ACTIVE SYNC VIRTUAL DIRECTORIES"
Get-ActiveSyncVirtualDirectory -Server * |
Select-Object `
Server,
Identity,
InternalUrl,
ExternalUrl,
BasicAuthentication,
WindowsAuthentication,
OAuthAuthentication,
MobileClientCertificateAuthorityURL |
Format-List
# ============================================================
# Autodiscover
# ============================================================
Write-Section "AUTODISCOVER VIRTUAL DIRECTORIES"
Get-AutodiscoverVirtualDirectory -Server * |
Select-Object `
Server,
Identity,
InternalUrl,
ExternalUrl,
BasicAuthentication,
WindowsAuthentication,
OAuthAuthentication |
Format-List
# ============================================================
# Client Access / Autodiscover SCP
# ============================================================
Write-Section "CLIENT ACCESS / AUTODISCOVER SCP"
Get-ClientAccessService |
Select-Object `
Name,
Fqdn,
AutoDiscoverServiceInternalUri |
Format-List
# ============================================================
# MAPI
# ============================================================
Write-Section "MAPI VIRTUAL DIRECTORIES"
Get-MapiVirtualDirectory -Server * |
Select-Object `
Server,
Identity,
InternalUrl,
ExternalUrl,
IISAuthenticationMethods,
OAuthAuthentication,
BasicAuthentication,
WindowsAuthentication |
Format-List
# ============================================================
# EWS
# ============================================================
Write-Section "EWS VIRTUAL DIRECTORIES"
Get-WebServicesVirtualDirectory -Server * |
Select-Object `
Server,
Identity,
InternalUrl,
ExternalUrl,
BasicAuthentication,
WindowsAuthentication,
OAuthAuthentication |
Format-List
# ============================================================
# OWA
# ============================================================
Write-Section "OWA VIRTUAL DIRECTORIES"
Get-OwaVirtualDirectory -Server * |
Select-Object `
Server,
Identity,
InternalUrl,
ExternalUrl,
FormsAuthentication,
WindowsAuthentication,
BasicAuthentication |
Format-List
# ============================================================
# ECP
# ============================================================
Write-Section "ECP VIRTUAL DIRECTORIES"
Get-EcpVirtualDirectory -Server * |
Select-Object `
Server,
Identity,
InternalUrl,
ExternalUrl,
FormsAuthentication,
WindowsAuthentication,
BasicAuthentication |
Format-List
# ============================================================
# Authentication policies
# ============================================================
Write-Section "AUTHENTICATION POLICIES"
$AuthPolicies = Get-AuthenticationPolicy -ErrorAction SilentlyContinue
if ($null -eq $AuthPolicies) {
Write-Host "No Authentication Policies found."
}
else {
$AuthPolicies |
Format-List *
}
# ============================================================
# Mailbox protocol configuration
# ============================================================
Write-Section "SAMPLE MAILBOX CLIENT ACCESS"
Get-Mailbox -ResultSize 5 |
Select-Object `
DisplayName,
UserPrincipalName,
PrimarySmtpAddress,
RecipientTypeDetails,
ExchangeGuid,
ActiveSyncEnabled,
MAPIEnabled,
EWSEnabled,
OWAEnabled |
Format-List
# ============================================================
# Organization protocol configuration
# ============================================================
Write-Section "ORGANIZATION CLIENT ACCESS SETTINGS"
Get-OrganizationConfig |
Select-Object `
*ActiveSync*,
*MAPI*,
*Ews*,
*OAuth*,
*ModernAuth* |
Format-List
# ============================================================
# Sample recipients
# ============================================================
Write-Section "SAMPLE RECIPIENTS"
Get-Recipient -ResultSize 10 |
Select-Object `
Name,
RecipientType,
RecipientTypeDetails,
PrimarySmtpAddress,
RemoteRecipientType |
Format-Table -AutoSize
# ============================================================
# Exchange certificates
# ============================================================
Write-Section "EXCHANGE CERTIFICATES"
Get-ExchangeCertificate |
Select-Object `
Server,
Thumbprint,
Services,
Subject,
CertificateDomains,
NotBefore,
NotAfter,
Status,
HasPrivateKey |
Format-List
# ============================================================
# IIS bindings
# ============================================================
Write-Section "IIS BINDINGS"
try {
Import-Module WebAdministration -ErrorAction Stop
Get-WebBinding |
Select-Object `
protocol,
bindingInformation,
sslFlags |
Format-Table -AutoSize
}
catch {
Write-Host "Could not read IIS bindings."
Write-Host $_.Exception.Message
}
# ============================================================
# Exchange services
# ============================================================
Write-Section "EXCHANGE SERVICES"
Get-Service |
Where-Object {
$_.Name -like "MSExchange*"
} |
Select-Object `
Status,
StartType,
Name,
DisplayName |
Sort-Object Name |
Format-Table -AutoSize
# ============================================================
# Microsoft Entra Connect
# ============================================================
Write-Section "MICROSOFT ENTRA CONNECT"
$ADSync = Get-Service ADSync -ErrorAction SilentlyContinue
if ($null -eq $ADSync) {
Write-Host "Azure AD / Microsoft Entra Connect service not found."
}
else {
$ADSync |
Select-Object `
Status,
StartType,
Name,
DisplayName |
Format-Table -AutoSize
Write-Host ""
Write-Host "--- Entra Connect Scheduler ---"
Get-ADSyncScheduler -ErrorAction SilentlyContinue |
Format-List
}
# ============================================================
# ADFS
# ============================================================
Write-Section "ADFS SERVICE"
$ADFS = Get-Service adfssrv -ErrorAction SilentlyContinue
if ($null -eq $ADFS) {
Write-Host "ADFS service not found on this server."
}
else {
$ADFS |
Select-Object `
Status,
StartType,
Name,
DisplayName |
Format-Table -AutoSize
# --------------------------------------------------------
# ADFS properties
# --------------------------------------------------------
Write-Section "ADFS PROPERTIES"
Get-AdfsProperties -ErrorAction SilentlyContinue |
Select-Object `
FederationServiceIdentifier,
FederationServiceName,
HostName |
Format-List
# --------------------------------------------------------
# ADFS endpoints
# --------------------------------------------------------
Write-Section "ADFS ENABLED ENDPOINTS"
Get-AdfsEndpoint -ErrorAction SilentlyContinue |
Where-Object {
$_.Enabled -eq $true
} |
Select-Object `
FullUrl,
Protocol,
TokenTypes |
Format-Table -AutoSize
# --------------------------------------------------------
# ADFS relying parties
# --------------------------------------------------------
Write-Section "ADFS RELYING PARTY TRUSTS"
Get-AdfsRelyingPartyTrust -ErrorAction SilentlyContinue |
Select-Object `
Name,
Identifier,
Enabled |
Format-Table -AutoSize
}
# ============================================================
# Exchange server network configuration
# ============================================================
Write-Section "EXCHANGE SERVER NETWORK INFORMATION"
Get-ExchangeServer |
Select-Object `
Name,
Fqdn,
ServerSite,
Site |
Format-List
# ============================================================
# Environment summary
# ============================================================
Write-Section "ENVIRONMENT SUMMARY"
# ------------------------------------------------------------
# Determine basic indicators
# ------------------------------------------------------------
$Servers = @(Get-ExchangeServer)
$OrgConfig = Get-OrganizationConfig
$AuthServers = @(Get-AuthServer -ErrorAction SilentlyContinue)
$HybridConfig = Get-HybridConfiguration -ErrorAction SilentlyContinue
$EntraConnect = Get-Service ADSync -ErrorAction SilentlyContinue
$AdfsService = Get-Service adfssrv -ErrorAction SilentlyContinue
$OAuthEnabled = $OrgConfig.OAuth2ClientProfileEnabled
$AdfsIssuer = $OrgConfig.AdfsIssuer
$EvoSTS = $AuthServers |
Where-Object {
$_.Name -eq "EvoSTS" -or
$_.Type -match "AzureAD"
}
$HybridEnabled = $null -ne $HybridConfig
$EntraConnectInstalled = $null -ne $EntraConnect
$AdfsInstalled = $null -ne $AdfsService
# ------------------------------------------------------------
# Exchange
# ------------------------------------------------------------
Write-Value "Exchange detected" "YES"
if ($Servers.Count -gt 0) {
$Versions = $Servers |
Select-Object -ExpandProperty AdminDisplayVersion -Unique
Write-Value "Exchange build(s)" ($Versions -join ", ")
$Editions = $Servers |
Select-Object -ExpandProperty Edition -Unique
Write-Value "Exchange edition(s)" ($Editions -join ", ")
$ServerCount = $Servers.Count
Write-Value "Exchange server count" $ServerCount
}
# ------------------------------------------------------------
# Hybrid
# ------------------------------------------------------------
if ($HybridEnabled) {
Write-Value "Hybrid configuration" "YES"
}
else {
Write-Value "Hybrid configuration" "NO / NOT DETECTED"
}
# ------------------------------------------------------------
# OAuth
# ------------------------------------------------------------
if ($OAuthEnabled -eq $true) {
Write-Value "OAuth2ClientProfileEnabled" "TRUE"
}
else {
Write-Value "OAuth2ClientProfileEnabled" "FALSE / NOT ENABLED"
}
if ($EvoSTS) {
Write-Value "Microsoft Entra OAuth indicator" "YES (EvoSTS / AzureAD AuthServer detected)"
}
else {
Write-Value "Microsoft Entra OAuth indicator" "NOT DETECTED"
}
# ------------------------------------------------------------
# ADFS
# ------------------------------------------------------------
if ($AdfsInstalled) {
Write-Value "ADFS installed on this server" "YES"
}
else {
Write-Value "ADFS installed on this server" "NO"
}
if ($AdfsIssuer) {
Write-Value "Exchange ADFS issuer" $AdfsIssuer
}
else {
Write-Value "Exchange ADFS issuer" "NOT CONFIGURED"
}
# ------------------------------------------------------------
# Entra Connect
# ------------------------------------------------------------
if ($EntraConnectInstalled) {
Write-Value "Microsoft Entra Connect" "INSTALLED ON THIS SERVER"
}
else {
Write-Value "Microsoft Entra Connect" "NOT DETECTED ON THIS SERVER"
}
# ------------------------------------------------------------
# ActiveSync external URL
# ------------------------------------------------------------
$ActiveSyncUrls = Get-ActiveSyncVirtualDirectory -Server * |
Where-Object {
$_.ExternalUrl
} |
Select-Object -ExpandProperty ExternalUrl -Unique
if ($ActiveSyncUrls) {
Write-Value "ActiveSync external URL(s)" ($ActiveSyncUrls -join ", ")
}
else {
Write-Value "ActiveSync external URL(s)" "NOT CONFIGURED"
}
# ------------------------------------------------------------
# Autodiscover
# ------------------------------------------------------------
$AutoDiscoverUrls = Get-AutodiscoverVirtualDirectory -Server * |
Where-Object {
$_.ExternalUrl
} |
Select-Object -ExpandProperty ExternalUrl -Unique
if ($AutoDiscoverUrls) {
Write-Value "Autodiscover external URL(s)" ($AutoDiscoverUrls -join ", ")
}
else {
Write-Value "Autodiscover external URL(s)" "NOT CONFIGURED"
}
# ------------------------------------------------------------
# MAPI
# ------------------------------------------------------------
$MapiUrls = Get-MapiVirtualDirectory -Server * |
Where-Object {
$_.ExternalUrl
} |
Select-Object -ExpandProperty ExternalUrl -Unique
if ($MapiUrls) {
Write-Value "MAPI external URL(s)" ($MapiUrls -join ", ")
}
else {
Write-Value "MAPI external URL(s)" "NOT CONFIGURED"
}
# ------------------------------------------------------------
# EWS
# ------------------------------------------------------------
$EwsUrls = Get-WebServicesVirtualDirectory -Server * |
Where-Object {
$_.ExternalUrl
} |
Select-Object -ExpandProperty ExternalUrl -Unique
if ($EwsUrls) {
Write-Value "EWS external URL(s)" ($EwsUrls -join ", ")
}
else {
Write-Value "EWS external URL(s)" "NOT CONFIGURED"
}
# ============================================================
# Diagnostic completion
# ============================================================
Write-Host ""
Write-Host "============================================================" -ForegroundColor Green
Write-Host " Diagnostic complete." -ForegroundColor Green
Write-Host "============================================================" -ForegroundColor Green
Write-Host ""
Write-Host "The complete diagnostic output was saved to:" -ForegroundColor Green
Write-Host ""
Write-Host $OutputFile -ForegroundColor Green
Write-Host ""
try {
Stop-Transcript | Out-Null
}
catch {
}
Write-Host ""
Read-Host "Press Enter to close"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment