Azure AD Sign-In and Audit Log Collection
IR AnalystSwitch roles in the top navigation to see different perspectives.
Collect comprehensive Azure Active Directory sign-in logs, audit logs, and provisioning logs for the investigation window. These logs reveal authentication events, privilege changes, application consent grants, and directory modifications.
Actions
- 1.Export Azure AD sign-in logs via Microsoft Graph: `Get-MgAuditLogSignIn -Filter "createdDateTime ge T_START and createdDateTime le T_END" -All | Export-Csv signins.csv -NoTypeInformation`. Include both interactive and non-interactive sign-ins.
- 2.Export Azure AD audit logs: `Get-MgAuditLogDirectoryAudit -Filter "activityDateTime ge T_START" -All | Export-Csv audit_logs.csv`. Focus on user management, application management, and role management categories.
- 3.Collect risky sign-ins and risk detections (requires AAD P2): `Get-MgRiskyUser -Filter "riskLevel eq 'high'" | Export-Csv risky_users.csv` and `Get-MgRiskDetection -Filter "detectedDateTime ge T_START" | Export-Csv risk_detections.csv`.
- 4.Export service principal sign-in logs for app-based access: `Get-MgAuditLogSignIn -Filter "signInEventTypes/any(t: t eq 'servicePrincipal')" -All | Export-Csv sp_signins.csv`.
- 5.Check Conditional Access policy evaluation logs to identify bypasses: filter sign-in logs where `ConditionalAccessStatus != "success"` or where legacy authentication protocols were used.
Queries
SigninLogs | where TimeGenerated between (datetime(T_START) .. datetime(T_END)) | where ResultType == 0 | summarize SignInCount=count(), DistinctIPs=dcount(IPAddress), DistinctApps=dcount(AppDisplayName) by UserPrincipalName, UserType | where DistinctIPs > 3 | order by DistinctIPs desc
AuditLogs | where TimeGenerated between (datetime(T_START) .. datetime(T_END)) | where OperationName in ("Add member to role","Add owner to application","Add app role assignment to service principal","Consent to application","Add delegated permission grant") | project TimeGenerated, OperationName, InitiatedBy, TargetResources | order by TimeGenerated ascAADNonInteractiveUserSignInLogs | where TimeGenerated between (datetime(T_START) .. datetime(T_END)) | where ResultType == 0 | summarize TokenCount=count() by UserPrincipalName, AppDisplayName, IPAddress, ResourceDisplayName | order by TokenCount desc | take 50
Notes
- Azure AD free tier retains sign-in logs for only 7 days. P1 retains 30 days. If you need older logs, check if they were forwarded to a SIEM or Log Analytics workspace.
- Non-interactive sign-in logs are often overlooked but critical -- they show OAuth token refreshes and app-based access that bypass MFA.
Where to Go Next
Related Artifacts
Azure AD (Entra ID) Sign-in Logs
Azure Portal > Entra ID > Monitoring > Sign-in logs (or Microsoft Graph API /auditLogs/signIns)
Azure AD (Entra ID) Audit Logs
Azure Portal > Entra ID > Monitoring > Audit logs (or Microsoft Graph API /auditLogs/directoryAudits)
Entra ID (Azure AD) Risk Events
Azure Portal > Entra ID > Security > Risk detections (or Microsoft Graph API /identityProtection/riskDetections)