Skip to content
The Lazy Administrator
  • Home
  • Disclaimer
  • Contact
  • About Me
  • Search Icon

The Lazy Administrator

Finding ways to do the most work with the least effort possible

Get a Teams Notification the Moment an Active Directory User gets Locked Out with PowerShell Using Webhooks

Get a Teams Notification the Moment an Active Directory User gets Locked Out with PowerShell Using Webhooks

December 13, 2018 Brad Wyatt Comments 26 comments

Table of Contents

  • Configure Incoming Webhook
  • Set Scheduled Task
  • Script / Source Code

I have been recently using Teams as a central location for my organizations technical notifications instead of email as it provides a way for an entire Help Desk team to openly collaborate on the message and its contents. I recently got a request to get a Teams notification when a user gets locked out of their Active Directory account. By setting up a Webhook connector we can make it happen. The script will be triggered from Task Scheduler on Event ID 4740 which is created when a user gets locked out. By using “Search-ADAccount -LockedOut” we can return an array of locked out accounts, but by ordering it by lockout time we can ensure that we grab the most recent locked out user that corresponds to the security event.

I set the script and scheduled task up on my PDC because as far as I know, the actual lockout event is only logged on the DC holding PDC Emulator FSMO role. 

 

Configure Incoming Webhook

To allow PowerShell to send data to your Teams Channel you will need to configure an incoming Webhook.

  1. In your Team, click on the channel you want the messages to be sent to
  2. Click on the 3 dots underneath the chat window, and then select “Go to store”
  3. Search for Webhook and then select it to begin configuring the Webhook
  4. You can keep the settings as is and press “Install” button located at the bottom
  5. Select the channel you want the incoming webhook to use and then press “Set Up”
  6. Give you webhook a good name. This is what users will see in the Teams chat. Upload an image and then press “Create”
  7. Copy the URL and save it for later, it will be needed. Click “Done” when you have saved the URL in a safe spot.
  8. Back in the Teams channel you can see that the webhook has been created.

Set Scheduled Task

  1. Download the script from GitHub or from below
  2. Add your Teams Webhook URL
  3. Enter the name of your domain controller. I am running mine on a domain controller so 
  4. Save the script somewhere you can reference later. I save all of mine at “C:\Automation”
  5. Open Task Scheduler and create a new Task
  6. Configure the trigger to be “When a specific event is logged”
  7. Set the log to “Security” and the Event ID to “4740”
  8. Set the Action to “Start a program”
  9. The program/script will be pointed to your script that you saved earlier. Before entering the file name enter “powershell.exe -filepath” so it knows to run the file in PowerShell.
  10. When you save your newly created scheduled task, go back in and make sure you enable “Run whether user is logged on or not”

Script / Source Code

The source code is maintained on GitHub but you can download it below as well.

<#	
	.NOTES
	===========================================================================
	 Created on:   	12/13/2018 3:57 PM
	 Created by:   	Bradley Wyatt
	 Filename:     	PSPush_LockedOutUsers.ps1
	===========================================================================
	.DESCRIPTION
		Sends a Teams notification via webhook of a recently locked out user. Set up a scheduled task to trigger on event ID 4740. 
#>

#Teams webhook url
$uri = "[INSERT WEBHOOK URL]"

#Image on the left hand side, here I have a regular user picture
$ItemImage = 'https://img.icons8.com/color/1600/circled-user-male-skin-type-1-2.png'

$ArrayTable = New-Object 'System.Collections.Generic.List[System.Object]'

$Event = Get-EventLog -LogName Security -InstanceId 4740 | Select-object -First 1
[string]$Item = $Event.Message
$Item.SubString($Item.IndexOf("Caller Computer Name"))
$sMachineName = $Item.SubString($Item.IndexOf("Caller Computer Name"))
$sMachineName = $sMachineName.TrimStart("Caller Computer Name :")
$sMachineName = $sMachineName.TrimEnd("}")
$sMachineName = $sMachineName.Trim()
$sMachineName = $sMachineName.TrimStart("\\")

$RecentLockedOutUser = Search-ADAccount -server $DomainContoller -LockedOut | Get-ADUser -Properties badpwdcount, lockoutTime, lockedout, emailaddress | Select-Object badpwdcount, lockedout, Name, EmailAddress, SamAccountName, @{ Name = "LockoutTime"; Expression = { ([datetime]::FromFileTime($_.lockoutTime).ToLocalTime()) } } | Sort-Object LockoutTime -Descending | Select-Object -first 1

$RecentLockedOutUser | ForEach-Object {
	
	$Section = @{
		activityTitle = "$($_.Name)"
		activitySubtitle = "$($_.EmailAddress)"
		activityText  = "$($_.Name)'s account was locked out at $(($_.LockoutTime).ToString("hh:mm:ss tt")) and may require additional assistance"
		activityImage = $ItemImage
		facts		  = @(
			@{
				name  = 'Lockout Source:'
				value = $sMachineName
			},
			@{
				name  = 'Lock-Out Timestamp:'
				value = $_.LockoutTime.ToString()
			},
			@{
				name  = 'Locked Out:'
				value = $_.lockedout
			},
			@{
				name  = 'Bad Password Count:'
				value = $_.badpwdcount
			},
			@{
				name  = 'SamAccountName:'
				value = $_.SamAccountName
			}
		)
	}
	$ArrayTable.add($section)
}

$body = ConvertTo-Json -Depth 8 @{
	title = "Locked Out User - Notification"
	text  = "$($RecentLockedOutUser.Name)'s account got locked out at $(($RecentLockedOutUser.LockoutTime).ToString("hh:mm:ss tt"))"
	sections = $ArrayTable
	
}
Write-Host "Sending lockedout account POST" -ForegroundColor Green
Invoke-RestMethod -uri $uri -Method Post -body $body -ContentType 'application/json'

 

Brad Wyatt
Brad Wyatt

My name is Bradley Wyatt; I am a 5x Microsoft Most Valuable Professional (MVP) in Microsoft Azure and Microsoft 365. I have given talks at many different conferences, user groups, and companies throughout the United States, ranging from PowerShell to DevOps Security best practices, and I am the 2022 North American Outstanding Contribution to the Microsoft Community winner.


Active Directory, Microsoft Teams, PowerShell
Automation, Microsoft Teams, Office 365, PowerShell, WebHook

Post navigation

PREVIOUS
Post Inactive Users as a Microsoft Teams Message with PowerShell
NEXT
PowerShell Function to Connect to All Office 365 Services With Support for MFA

26 thoughts on “Get a Teams Notification the Moment an Active Directory User gets Locked Out with PowerShell Using Webhooks”

  1. Mark says:
    December 16, 2018 at 5:54 pm

    I’m getting an error “Invoke-RestMethod : Invalid URI: The hostname could not be parsed”, my PSVersion is 4.0 so i’m trying to update to 5.1 to see if that helps, any idea why i would be getting that error

    Reply
    1. Brad Wyatt says:
      December 17, 2018 at 2:14 pm

      I would start by testing with your webhook. Make sure you can send a simple POST message and go from there

      Reply
  2. Coen Ran says:
    December 17, 2018 at 3:58 am

    Great guide, looking to have fun with it 🙂 I did notice one thing though, under Set Scheduled Task, point 3:
    “Enter the name of your domain controller. I am running mine on a domain controller so ”
    It just cuts off there!
    Thanks, Coen

    Reply
    1. Brad Wyatt says:
      December 17, 2018 at 2:00 pm

      eventID 4740 should be only on your PDC. set up the scheduled task on your PDC

      Reply
  3. dimforest says:
    December 17, 2018 at 9:17 am

    This is awesome. Kinda makes me want to see what else I can tie into Teams now.

    Reply
  4. Robin says:
    December 18, 2018 at 1:09 am

    Thank you Brad, nice script. It encourages me to use Teams for more notifications, for example snapshots on our clusters (which need to be cleaned up, but often don’t get cleaned up).

    Keep up the good work!

    Reply
  5. Justin says:
    January 30, 2019 at 12:10 pm

    Great job! Some notes from our version of doing.

    * Run your script on the DC running the PDC emulator. Lockout events are immediately replicated to the PDC. I *think* bad password attempts are local to each source and not replicated.
    * Have the script also send the event data to syslog and/or email. We find it easier to spot patterns in lockout events when viewing them in Kibana or Outlook.

    Reply
  6. Jarn says:
    February 11, 2019 at 1:32 pm

    Experiencing the following error:

    You cannot call a method on a null-valued expression.
    At C:\Scripts\PSPush_LockOut.ps1:37 char:70
    + … ed out at $(($RecentLockedOutUser.LockoutTime).ToString(“hh:mm:ss tt” …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    Reply
    1. Brad Wyatt says:
      February 11, 2019 at 3:54 pm

      you may not have any recently locked out users, how did this trip? or was it ran manually

      Reply
  7. Trevor says:
    February 11, 2019 at 4:20 pm

    The message I receive says ” ‘s account was locked out at and may require additional assistance”

    Basically, the script isn’t getting any of the specific information just that there has been a locked account. Any ideas why this is happening? I am running the script on the domain controller.

    Reply
    1. Brad Wyatt says:
      February 12, 2019 at 10:06 am

      how are you tripping the script to run? it should be ran on the eventID thats tripped when an account is locked out, if its being tripped any other time it will return NULL because there may not be any accounts locked out

      Reply
      1. Ricky Camacho says:
        February 4, 2020 at 8:42 am

        Good Morning,

        I am getting this same issue, i have followed you guide to the T and its still giving me this same message.

        Locked Out User – Notification
        ‘s account got locked out at
        ‘s account was locked out at and may require additional assistance

        Reply
        1. Brad Wyatt says:
          February 4, 2020 at 2:43 pm

          go through the script step by step – sounds like it’s not reading the event log correctly. make sure the variables show objects or values

          Reply
  8. Webman says:
    March 4, 2019 at 8:04 am

    Thanks for this! this is really useful. any way to get a notification in teams if a user is deleted from AD?

    Reply
    1. Brad Wyatt says:
      March 6, 2019 at 11:32 am

      Yes if that event triggers an event in event viewer

      Reply
  9. Chris says:
    March 4, 2019 at 10:56 am

    Hey Brad,

    Thanks for your scripts they are super helpful.

    I am curious if you know of a way to perform the @person or @team using the webhook? Would be super helpful to get a notification pop-up in Teams when this occurs.

    Thanks!

    Reply
    1. Brad Wyatt says:
      March 6, 2019 at 11:31 am

      not to my knowledge

      Reply
  10. Pingback: MS Teams notification for AD user lockout | randomtecharticles.com
  11. Neil says:
    October 23, 2020 at 3:18 pm

    Hey, Brad.

    I’ve been searching far and wide across the internet.. I used to run a script that does almost exactly what yours does, but it monitors all changes, like lock-outs, disabled/enabled events, password expires, etc and pumps them all to Teams.

    It ran great in my environment for a while until it got encrypted by baddies and I lost it. I thought I got it from your site, but not sure.. did you ever post anything like that?

    Here’s a screenshot of it as well:
    https://i.imgur.com/2hj7yst.png

    Reply
    1. Brad Wyatt says:
      October 23, 2020 at 8:04 pm

      I have several posts that send alerts to teams via webhooks using PS – that should be the same with what you had

      Reply
    2. Phenix51 says:
      October 12, 2021 at 7:05 am

      @Neil, would you be able to provide the event ID code for enable/disabling of the account or which event ID is used when an account has been created?

      Reply
  12. Bradley says:
    August 30, 2021 at 11:33 pm

    I got the script working after a bit of stuffing about, and it was step 3 that was tripping me up.

    it looks like you’ve made a variable for the script (line 29 $DomainContoller), but haven’t given the user a spot to define it, so glancing over the script you miss it.

    If its not defined it will “work” but the notifications will be

    ” ‘s account was locked out at and may require additional assistance”

    Reply
  13. Pingback: Chatting about Chatbots with Mike Kanakos, Microsoft MVP – PowerShell.org
  14. Jarad Morgan says:
    July 2, 2023 at 5:31 pm

    Is it possible to make this work in a network that uses Azure AD as a Service?

    Reply
  15. Gaetan Meister says:
    October 19, 2023 at 9:54 am

    is it possible to notify the user directly ? I know how to notify via email but unsure how to do it via teams

    Reply
  16. Ricky Camacho says:
    December 6, 2024 at 12:10 pm

    Hello All,

    Is there an update to this script? looks like it just broke and stopped working for me.

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Subscribe

Email


Categories

  • Active Directory (8)
  • AI (3)
  • API (1)
  • AutoPilot (2)
  • Azure (15)
  • Bicep (4)
  • Connectwise (1)
  • Defender for Cloud Apps (1)
  • Delegated Admin (1)
  • DevOps (6)
  • Graph (6)
  • Intune (15)
  • LabTech (1)
  • Microsoft Teams (6)
  • Office 365 (19)
  • Permissions (2)
  • PowerShell (50)
  • Security (1)
  • SharePoint (3)
  • Skype for Business (1)
  • Terraform (1)
  • Uncategorized (2)
  • Yammer (1)

Recent Comments

  • Kristopher Gates on Getting Started with GitHub Copilot in the CLI
  • MD SHARIQUE AKHTAR on Modern Active Directory – An update to PSHTML-AD-Report
  • TommyBoich on How The ConnectWise Manage API Handles Pagination with PowerShell
  • LOTTERY 365 LOGIN on Windows LAPS Management, Configuration and Troubleshooting Using Microsoft Intune
  • SPRUNKI PHASE 6 on Get a New Computer’s Auto Pilot Hash Without Going Through the Out of Box Experience (OOBE)

1,739,429 People Reached

© 2025   All Rights Reserved.