Anomalous sign-in location by user account and authenticating application - with sign-in details
Description
'This query examines Microsoft Entra ID sign-ins and identifies anomalous changes in a user's location profile. A variation joins results back onto the original sign-in data to review the location set with each identified user in tabular form.'
Query · kql
SigninLogs // Forces Log Analytics to recognize that the query should be run over full time range | extend locationString= strcat(tostring(LocationDetails["countryOrRegion"]), "/", tostring(LocationDetails["state"]), "/", tostring(LocationDetails["city"]), ";") | project TimeGenerated, AppDisplayName , UserPrincipalName, locationString // Create time series | make-series dLocationCount = dcount(locationString) on TimeGenerated step 1d by UserPrincipalName, AppDisplayName // Compute best fit line for each entry | extend (RSquare,Slope,Variance,RVariance,Interception,LineFit)=series_fit_line(dLocationCount) // Chart the 3 most interesting lines // A 0-value slope corresponds to an account being completely stable over time for a given Azure Active Directory application | top 3 by Slope desc // Extract the set of locations for each top user: | join kind=inner (SigninLogs | extend locationString= strcat(tostring(LocationDetails["countryOrRegion"]), "/", tostring(LocationDetails["state"]), "/", tostring(LocationDetails["city"]), ";") | summarize locationList = makeset(locationString), threeDayWindowLocationCount=dcount(locationString) by AppDisplayName, UserPrincipalName, timerange=bin(TimeGenerated, 3d)) on AppDisplayName, UserPrincipalName | order by UserPrincipalName, timerange asc | project timerange, AppDisplayName , UserPrincipalName, threeDayWindowLocationCount, locationList | order by AppDisplayName, UserPrincipalName, timerange asc | extend timestamp = timerange, AccountCustomEntity = UserPrincipalName