Reading Time: 4 minutes
Follow by Email

At one of my meetups, I talked about Azure Security and how you can monitor your Active Directory’s security events cheaply using Azure Security Centre and Azure Log Analytics. There are a few prerequisites to this which I have pointed out below. I have not gone into the details about them, but have provided some links to help set them up if needed. Once they are out of the way, I show you how to configure Azure Security centre to receive Security Events from your domain controllers. I then show you some queries that I find useful. Hopefully, you to do.


A log Analytics Workspace dedicated just for the Domain Controllers.

You will need to have the Azure monitor agent installed on the Domain Controllers you want to monitor. You can even monitor none Azure Domain Controllers too. You can find more about installing the agent at

The domain controllers linked to the dedicated log analytics workspace.

The Set Up

So now we have the prerequisites out of the way its time for a bit of configuration to allow you to query Security Events.

Go to Azure Security Centre and click on Security Policy. Its just under Policy & Compliance.

Then click edit settings next to your Log Analytics Workspace

Click Pricing tier.

Click on Standard. (note this will charge you $15.00 a month per node attached to this workspace. So make sure its just the ones for your domain controllers. Then click Save.

Then go back to data collection and click on Common. This will collect the common security events needed for auditing purposes. Then click Save.

Lets do some testing!

Go to your Log Analytics Workspace and then click Logs.

The query below will give you a nice table of user accounts, how many times they have attempted to log in, how many failed and how many succeeded.

| where EventID in (4625, 4624) and AccountType == 'User'
| summarize Attempts = count(), Failed = countif(EventID == 4625), Succeeded = countif(EventID == 4654) by Account

Lets explain this query a bit.

So, SecurityEvents are only available on the standard tier of Azure Security centre. That’s why we created one Log Analytics just for our domain controllers. It keeps costs down this way.

| where EventID in (4625, 4624) and AccountType == ‘User’ Looks for events with ID’s 4625 and 4624 and the account type User. This filters out all other events and machine logins.

| summarize Attempts = count(), Failed = countif(EventID == 4625), Succeeded = countif(EventID == 4654) by Account This line summarises the data we have gatherd and performs a count of the events by account name.

Once you have ran the query you should see something like the image below.

You could now pin this to a dashboard if you liked.

Lets try another query

Let’s say you want a list of your servers that have had failed logins and you also want to know the reason why it failed. Well, this query is the one you want!

| where EventID == 4625
| extend Reason = case(
SubStatus == '0xc0000064', 'User name does not exist',
SubStatus == '0xc000005e', 'No logon servers available to service the logon request',
SubStatus == '0xc0000062', 'Account name is not properly formatted',
SubStatus == '0xc0000064', 'Account name does not exist',
SubStatus == '0xc000006a', 'Incorrect password',
SubStatus == '0xc000006d', 'Bad user name or password',
SubStatus == '0xc000006f', 'User logon blocked by account restriction',
SubStatus == '0xc000006f', 'User logon outside of restricted logon hours',
SubStatus == '0xc0000070', 'User logon blocked by workstation restriction',
SubStatus == '0xc0000071', 'Password has expired',
SubStatus == '0xc0000072', 'Account is disabled',
SubStatus == '0xc0000133', 'Clocks between DC and other computer too far out of sync',
SubStatus == '0xc000015b', 'The user has not been granted the requested logon right at this machine',
SubStatus == '0xc0000193', 'Account has expirated',
SubStatus == '0xc0000224', 'User is required to change password at next logon',
SubStatus == '0xc0000234', 'Account is currently locked out', strcat('Unknown reason substatus: ', SubStatus))
| where AccountType == "User"
| summarize count() by Reason, Computer
| evaluate pivot(Reason, sum(count_))

If you run this you will get a nice list of any server that has had a failed login and the reason why.

Ok One more!

This query will give you the top 10 suspicious failed logins, by IP Address. This one comes in handy if you have left RDP open to the world!

| where AccountType == 'User'
| where EventID in (4624, 4625)
| summarize Unique_Accounts = dcount(Account), Attempts = count(), Succeeded=countif(EventID == 4624), Failed=countif(EventID == 4625) by IpAddress
| where Failed > 0
| order by Succeeded>0, todouble(Succeeded)/Attempts asc, Attempts desc
| project IP = IpAddress, Succeeded, Attempts, Unique_Accounts
| take 10

So there you go a nice cheap way to monitor your active directory security events using Azure and Log Analytics.

Let us know if you come up with any cool queries too.

I hope you found this article helpful. If you have any questions or comments please reach out.

Follow by Email

Pixel Robots.

I’m Richard Hooper aka Pixel Robots. I started this blog in 2016 for a couple reasons. The first reason was basically just a place for me to store my step by step guides, troubleshooting guides and just plain ideas about being a sysadmin. The second reason was to share what I have learned and found out with other people like me. Hopefully, you can find something useful on the site.

1 Comment

Nat · December 10, 2019 at 4:29 pm

Did Azure change something? When I try to run your first query, I get a syntax error:

Query could not be parsed at ‘SecurityEvent’ on line [5,0]

Token: SecurityEvent
Line: 5
Position: 0

Leave a Reply

Avatar placeholder

Your email address will not be published.