Active Directory - Password Security Posture Assessment
MDI Identity Password Security Posture Assessment
Query
let accountinfo = IdentityAccountInfo
| where TimeGenerated > ago(30d)
| summarize arg_max(TimeGenerated,*) by IdentityId
| extend DaysSinceLastPasswordChange =
iff(isnull(LastPasswordChangeTime), int(null),
datetime_diff('day', now(), LastPasswordChangeTime))
| extend YearsSinceLastPasswordChange =
iff(isnull(LastPasswordChangeTime), int(null),
datetime_diff('year', now(), LastPasswordChangeTime))
| extend Sensitive = array_index_of(Tags, "Sensitive") != -1
| extend SensitiveLabel = iff(Sensitive == 1, "🟥 Sensitive", "⬜ Not Sensitive")
| project IdentityId,AccountUpn, AccountStatus, LastPasswordChangeTime,DaysSinceLastPasswordChange,YearsSinceLastPasswordChange, Sid, Sensitive, SensitiveLabel;
let IdInfo = IdentityInfo
| where TimeGenerated > ago(30d)
| summarize arg_max(TimeGenerated,*) by IdentityId
| extend PasswordNeverExpires = array_index_of(UserAccountControl, "PasswordNeverExpires") != -1,
PasswordNotRequired = array_index_of(UserAccountControl, "PasswordNotRequired") != -1
| extend OUPath = extract(@"CN=[^,]+,(.*)", 1, DistinguishedName)
| project IdentityId,AccountName, AccountDomain, AccountDisplayName, OnPremSid, OnPremObjectId, AccountUpn, PasswordNeverExpires, PasswordNotRequired,Type, OUPath, IdentityEnvironment;
IdInfo
| join kind=leftouter (accountinfo)
on $left. IdentityId == $right. IdentityId
| project IdentityId, AccountName, AccountStatus,AccountDomain, AccountDisplayName,AccountUpn,Sensitive,SensitiveLabel,LastPasswordChangeTime, DaysSinceLastPasswordChange, YearsSinceLastPasswordChange, PasswordNeverExpires, PasswordNotRequired,Type, OUPath, IdentityEnvironment
| sort by DaysSinceLastPasswordChange desc
//| where AccountStatus != @"Disabled"
| where Type == @"ServiceAccount"
| where IdentityEnvironment != "Cloud"About this query
Explanation
This KQL query is designed to assess the security posture of Active Directory accounts by examining password-related attributes. Here's a simplified breakdown of what the query does:
-
Data Sources: It uses two tables,
IdentityAccountInfoandIdentityInfo, from Microsoft Defender XDR to gather information about Active Directory accounts. -
Identify Stale Passwords: The query calculates how long it has been since each account's password was last changed, both in days and years. This helps identify accounts with outdated passwords.
-
Assess Account Sensitivity: It checks if accounts are marked as sensitive or have elevated privileges, which could pose a higher security risk.
-
Review Password Policies: It identifies accounts with specific flags like
PasswordNeverExpiresorPasswordNotRequired, which might indicate weaker security settings. -
Analyze Account Status: The query focuses on enabled accounts, as these are actively used and could pose security risks if compromised.
-
Special Focus on High-Risk Accounts: A variant of the query specifically filters for high-risk accounts, such as built-in accounts (Administrator, Guest, krbtgt) and Microsoft Entra Connect synchronization accounts.
-
Visualize Password Age: The query can be extended to visualize the distribution of accounts based on the age of their passwords, categorizing them into buckets like "0-1 years", "1-2 years", etc.
-
Logon Activity: It can also be extended to include the last logon date from Active Directory or Entra ID, helping to identify accounts that haven't been used recently.
Overall, this query helps security teams identify potential vulnerabilities related to password management and account configurations in Active Directory, aiding in proactive security posture assessments.
Details

Alex Verboon
Released: June 2, 2026
Tables
Keywords
Operators