Community-built Active Directory & Azure AD security audit toolkit — no third-party tools, no RSAT required.
AD-Recon is a PowerShell script that scans your Active Directory (or Azure AD) environment for security misconfigurations and generates a single self-contained HTML report — like a health check for your domain.
- No installation, no extra tools, no admin rights required
- Works with just a standard domain user account
- Report opens in any browser, works fully offline
| Script | What it audits | How it connects |
|---|---|---|
Invoke-ADRecon.ps1 |
On-premises Active Directory | LDAP (built-in .NET, no RSAT) |
Invoke-AzureADRecon.ps1 |
Entra ID / Azure AD | Microsoft Graph API |
No need to clone the repo. Run directly in PowerShell:
# One-liner: download and run immediately
irm https://raw.githubusercontent.com/MrHarshvardhan/ADRecon/master/Invoke-ADRecon.ps1 | iex# Or: download the file first, then run
Invoke-WebRequest -Uri https://raw.githubusercontent.com/MrHarshvardhan/ADRecon/master/Invoke-ADRecon.ps1 `
-OutFile Invoke-ADRecon.ps1
.\Invoke-ADRecon.ps1# One-liner: download and run with browser login popup
irm https://raw.githubusercontent.com/MrHarshvardhan/ADRecon/master/Invoke-AzureADRecon.ps1 | iex# Or: download first, then run interactively
Invoke-WebRequest -Uri https://raw.githubusercontent.com/MrHarshvardhan/ADRecon/master/Invoke-AzureADRecon.ps1 `
-OutFile Invoke-AzureADRecon.ps1
.\Invoke-AzureADRecon.ps1 -UseDeviceCode -OpenBrowserExecution policy note: If PowerShell blocks the script, run this first:
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass
Open PowerShell (not CMD). You do not need to run as Administrator.
Invoke-WebRequest -Uri https://raw.githubusercontent.com/MrHarshvardhan/ADRecon/master/Invoke-ADRecon.ps1 `
-OutFile Invoke-ADRecon.ps1Option A — Audit your current domain (simplest, no extra parameters)
.\Invoke-ADRecon.ps1Runs as your currently logged-in user against the domain your machine is joined to.
Option B — Audit with a specific user account
.\Invoke-ADRecon.ps1 -Username "CORP\auditor" -Password "P@ssw0rd!"Option C — Audit a remote domain or specific domain controller
.\Invoke-ADRecon.ps1 -Server "dc01.corp.local" -Username "CORP\auditor" -Password "P@ssw0rd!"The script generates an HTML file in the same folder:
ADRecon_corp.local_20240115_143022.html
Open it in any browser. No internet connection needed.
Invoke-WebRequest -Uri https://raw.githubusercontent.com/MrHarshvardhan/ADRecon/master/Invoke-AzureADRecon.ps1 `
-OutFile Invoke-AzureADRecon.ps1.\Invoke-AzureADRecon.ps1 -UseDeviceCode -OpenBrowserWhat happens:
- Script prints a one-time code in the terminal
- Your default browser opens automatically to
https://microsoft.com/devicelogin - Enter the code and sign in with your Azure AD account
- Come back to the terminal — the audit starts automatically
.\Invoke-AzureADRecon.ps1 -UseDeviceCodeWhat happens:
- Script prints a URL and a one-time code:
To sign in, open https://microsoft.com/devicelogin and enter the code: ABCD1234XY - Open the URL in any browser on any device
- Enter the code and sign in
- Audit starts automatically once login is complete
Create an App Registration in Azure Portal with read-only permissions, then:
.\Invoke-AzureADRecon.ps1 -TenantId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" `
-ClientId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" `
-ClientSecret "your-client-secret-here"Required Graph API permissions for the app (all read-only):
| Permission | Used for |
|---|---|
Directory.Read.All |
Users, groups, roles, devices |
Policy.Read.All |
Conditional Access policies |
AuditLog.Read.All |
Sign-in risk, audit logs |
RoleManagement.Read.All |
PIM role assignments |
Application.Read.All |
App secrets and permissions |
UserAuthenticationMethod.Read.All |
Per-user MFA status |
# If you already ran Connect-MgGraph earlier in the same session:
Connect-MgGraph -Scopes "Directory.Read.All","Policy.Read.All","AuditLog.Read.All","RoleManagement.Read.All","Application.Read.All","UserAuthenticationMethod.Read.All"
.\Invoke-AzureADRecon.ps1| Your situation | Use this |
|---|---|
| Running on your own Windows/Mac laptop | -UseDeviceCode -OpenBrowser |
| Running on a server or over SSH | -UseDeviceCode |
| Scheduling an automated scan | -TenantId + -ClientId + -ClientSecret |
| Already signed in via Connect-MgGraph | No parameters needed |
AzureADRecon_<TenantId>_20240115_143022.html
Open in any browser — no internet needed.
.\Invoke-ADRecon.ps1 -OutputPath "C:\Audits\2024"
.\Invoke-AzureADRecon.ps1 -UseDeviceCode -OutputPath "C:\Audits\2024"# Skip GPP password and PKI checks (e.g., if SYSVOL access is restricted)
.\Invoke-ADRecon.ps1 -SkipChecks "Invoke-CheckGPPPasswords","Invoke-CheckPKI".\Invoke-ADRecon.ps1 -Domain "subsidiary.corp.local"$cred = Get-Credential
.\Invoke-ADRecon.ps1 -Credential $cred.\Invoke-ADRecon.ps1 -NoColorBoth scripts generate a self-contained HTML report:
- Risk score (0–100) shown as a ring gauge — higher is better
- Stats bar — total users, computers, groups, DCs at a glance
- Findings — each issue shown as a collapsible card with:
- Risk level (Critical / High / Medium / Low / Info)
- MITRE ATT&CK technique ID (linked to attack.mitre.org)
- Affected objects listed in a table (usernames, computer names, file paths, etc.)
- Step-by-step remediation guide
- Filter bar — filter by risk level or search by keyword
- Export CSV — download all findings as a spreadsheet
| # | Module | What It Detects |
|---|---|---|
| 1 | Domain Info | Domain functional level, tombstone lifetime, recycle bin |
| 2 | Domain Controllers | Missing patches, SMB signing, LDAP signing, outdated OS |
| 3 | Krbtgt | Password age > 180 days, never-changed krbtgt |
| 4 | Users | No pre-auth (AS-REP), reversible encryption, DES-only, password never expires, stale accounts |
| 5 | Computers | Outdated OS (XP/2003/Vista/2008), old password, unconstrained delegation |
| 6 | Groups | Large groups, empty groups, non-admin members of Domain Admins |
| 7 | Delegation | Unconstrained, constrained, resource-based constrained delegation |
| 8 | DCSync | Non-DC accounts with Replicating Directory Changes All |
| 9 | AdminSDHolder | Modified AdminSDHolder ACL (backdoor persistence) |
| 10 | Trusts | External trusts, SID history enabled, SID filtering disabled |
| 11 | PKI / ADCS | ESC1–8 misconfigurations, expired CAs, weak key sizes |
| 12 | Security Settings | WDigest plaintext, NTLMv1, null sessions, WPAD, anonymous enumeration |
| 13 | FSMO | FSMO role holders, time sync, RID pool consumption |
| 14 | Sensitive Groups | Schema Admins, Account Operators, Backup Operators membership |
| 15 | Builtin Accounts | Default Administrator/Guest account status |
| 16 | GPP Passwords | MS14-025: cPassword in SYSVOL (cleartext passwords in Group Policy) |
| 17 | Kerberos Encryption | RC4-only policies, AES not required |
| 18 | GPO Security | Missing LAPS, AppLocker, Credential Guard, no screen lock GPO |
| 19 | Exchange | RBAC WriteDACL/FullControl delegation (PrivExchange) |
| 20 | ADCS Extended | Template anomalies, duplicate OIDs, manager approval bypass |
| 21 | RODC | RODC password replication policy, privileged accounts cached |
| 22 | Shadow Credentials | msDS-KeyCredentialLink on non-DC objects (persistence) |
| 23 | Azure AD Connect | Stale sync, AZUREADSSOACC account (Pass-Through Auth) |
| 24 | DNS Security | Wildcard records (WPAD), insecure dynamic update settings |
| 25 | LAPS ACL | Who can read the LAPS ms-Mcs-AdmPwd attribute |
| 26 | Display Specifiers | Malicious script hooks in display specifiers |
| 27 | Fine-Grained PSOs | Password policies weaker than domain default |
| 28 | Broad ACL | GenericAll / WriteDACL / WriteOwner on OUs and GPOs |
| 29 | Sites & Subnets | AD site topology, orphaned subnets |
| 30 | BitLocker ACL | Who can read BitLocker recovery keys from AD |
| 31 | DNS Zones | DNSSEC status, zone inventory |
| # | Module | What It Detects |
|---|---|---|
| 1 | Tenant Info | Security defaults enabled/disabled, org settings |
| 2 | Privileged Roles | >5 Global Admins, service principals / guests in privileged roles |
| 3 | MFA | Admins without MFA, tenant-wide MFA registration rate |
| 4 | Conditional Access | Missing MFA policy, legacy auth not blocked, report-only policies |
| 5 | Applications | Expired secrets, 200-year secrets, high-privilege app permissions |
| 6 | Guest Settings | Invite policy, guests as Members, stale guest accounts |
| 7 | Auth Methods | SMS still enabled, no named locations defined |
| 8 | Hybrid Identity | Connect sync staleness, password sync staleness, PTA agent health |
| 9 | PIM | No P2 license, P2 licensed but PIM not activated |
| 10 | Risky Users | Confirmed-compromised accounts, high-risk users (Identity Protection) |
| 11 | Domains | Federated domains, cloud passwords set to never expire |
- Windows PowerShell 5.1+ or PowerShell 7+
- No RSAT, no AD module, no third-party tools
- Network access to a domain controller on port 389 (LDAP)
- Standard domain user account (read-only access is enough for most checks)
- PowerShell 5.1+ or PowerShell 7+
- Internet access to
login.microsoftonline.comandgraph.microsoft.com - An Azure AD account (or app registration) with the read-only permissions listed above
| Parameter | Type | Default | Description |
|---|---|---|---|
-Domain |
String | (current domain) | Target AD domain FQDN, e.g. corp.local |
-Server |
String | (auto-detected) | DC hostname or IP to connect to |
-Username |
String | (current user) | Alternate username in DOMAIN\user format |
-Password |
String | (none) | Alternate password |
-Credential |
PSCredential | (none) | Pre-built credential object from Get-Credential |
-OutputPath |
String | (current folder) | Folder where the HTML report is saved |
-SkipChecks |
String[] | (none) | List of module names to skip |
-NoColor |
Switch | (false) | Disable colored console output |
| Parameter | Type | Default | Description |
|---|---|---|---|
-TenantId |
String | (none) | Entra ID tenant GUID |
-ClientId |
String | (none) | App registration client ID |
-ClientSecret |
String | (none) | App registration secret |
-CertificateThumbprint |
String | (none) | Certificate-based auth thumbprint |
-UseDeviceCode |
Switch | (false) | Interactive login — prints URL + code in terminal |
-OpenBrowser |
Switch | (false) | Auto-open microsoft.com/devicelogin in your browser (use with -UseDeviceCode) |
-OutputPath |
String | (current folder) | Folder where the HTML report is saved |
-SkipChecks |
String[] | (none) | List of module names to skip |
Each finding reduces the score from a starting point of 100:
| Level | Score Impact | Examples |
|---|---|---|
| Critical | −20 | DCSync rights, AS-REP Roasting, ADCS ESC1, null sessions |
| High | −10 | Unconstrained delegation, krbtgt password age > 180 days, WDigest enabled |
| Medium | −5 | Missing LAPS, password never expires, outdated OS |
| Low | −2 | Empty groups, weak PSO |
| Info | 0 | Informational findings only |
A domain with no issues scores 100. Most real environments score between 40–80.
Invoke-ADRecon.ps1
│
├── ADSI / DirectorySearcher (no RSAT — works with any domain user)
├── 31 isolated check modules (each in try/catch — one failure never stops the rest)
├── Add-Finding collector
└── HTML report generator (fully self-contained, no CDN, works offline)
Invoke-AzureADRecon.ps1
│
├── Microsoft Graph REST API
│ ├── Auth: Device code | Client credentials | MgGraph session
│ └── Auto-pagination (handles tenants with thousands of objects)
├── 11 isolated check modules
├── Add-Finding collector
└── HTML report generator (same design, Azure blue theme)
Pull requests welcome. When adding a new check module:
- Name it
Invoke-Check<Topic>(e.g.,Invoke-CheckKerberoast) - Wrap all logic in
try/catch— never throw; callAdd-Findingfor each issue found - Use
Invoke-Searcherfor LDAP queries (handles credentials and DC binding automatically) - Add the module to the
$checksarray in the main execution block - Add a MITRE ATT&CK mapping entry to
$Script:MitreTTPMapif applicable
For authorized security assessments only.
Only run this tool against domains and tenants for which you have explicit written authorization. Unauthorized use is illegal in most jurisdictions.
GitHub: github.com/MrHarshvardhan Built on BloodHound documentation, Microsoft's own security baselines, and AD attack research.
AD-Recon by Harsh P — community AD security audit toolkit