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

Post Users with Expiring Passwords as Microsoft Teams Message with PowerShell

Post Users with Expiring Passwords as Microsoft Teams Message with PowerShell

December 7, 2018 Brad Wyatt Comments 9 comments

Table of Contents

  • Configure Incoming Webhook
  • Configure PowerShell to Push to Webhook
  • Configure Job as Scheduled Task
  • Script / Download
  • Frequently Asked Questions

Microsoft Teams has many connectors available including Incoming Webhook. “This provides an easy solution to post notifications / messages from any scripting language through JSON formatted web service call.”1

In this post I will show you how you can gather all of your users who have passwords expiring within a specified time range, and send a notification including all relevant information to a Teams Channel. In my example I will get all users who have passwords expiring in 7 days and less and have it notify my “Help Desk” Teams Channel.  

The current script will parse only enabled users because we don’t need to report on users, ‘passwordlastset’ attribute if the account isn’t even allowed to log in. It will also sort all of our data, so the users with passwords expiring the earliest will always be at the top of the message. The top description under, “Users With Passwords Expiring – Notification” will display the total amount of users and the amount of days you originally set. 

**Update 12/10**: I have split the tables into their own messages. So you will get one message containing all of your users that are expiring, and another of all accounts that have expired. This helps keep the data separate as well as avoid HTTP error 413 which occurs when your webhook message is too large.

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.

Configure PowerShell to Push to Webhook

Now we will configure a PowerShell script to scrape Active Directory for our data, parse it, and then send over items that match our query to Teams as a message. 

  1. Download or copy the script here
  2. Put in the URL for your webhook that you save earlier, as the value for the variable, “$uri”
  3. If you want to change the number of days you want to be notified on, change the variable, “$LessThan”. Currently I have it set at 7. So PowerShell will only gather users who have passwords expiring in 7 days or less.
  4. In my notification message, the user avatar is a red haired “person”. But you can make it whatever you want by modifying the ItemImage variable.
  5. Once you have made it fit your organizations needs, run the PowerShell script.
  6. In my example I ran it in ISE. At the bottom I can see it ran without any issues
  7. Back in Teams I can see my two users that need their passwords changed.

Configure Job as Scheduled Task

  1. In my environment I saved the script at C:\Automation
  2. In Task Scheduler I am going to create a basic task
  3. In the program/script, enter “Powershell -file “FILE LOCATION AND NAME.ps1″” 
  4. Save the scheduled task. Back in general make sure it will run if you are logged in or not. Also modify the privileges to best fir your environment. 

Script / Download

You can download or copy the script below or on GitHub

$SendMessage = $null
#Get all users whose password expires in X days and less, this sets the days
$LessThan = 7
#Teams web hook URL
$uri = "[INSERT WEBHOOK URI]"

$ItemImage = 'https://img.icons8.com/color/1600/circled-user-male-skin-type-1-2.png'

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

$maxPasswordAge = ((Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge).Days
#Get all users and store in a variable named $Users
get-aduser -filter { (PasswordNeverExpires -eq $false) -and (enabled -eq $true) } -properties * | ForEach-Object{
	Write-Host "Working on $($_.Name)" -ForegroundColor White
	
	
	#Get Password last set date
	$passwordSetDate = ($_.PasswordLastSet)
	
	if ($null -eq $passwordSetDate)
	{
		#0x1 = Never Logged On
		$daystoexpire = "0x1"
	}
	
	else
	{
		
		#Check for Fine Grained Passwords
		$PasswordPol = (Get-ADUserResultantPasswordPolicy -Identity $_.objectGUID -ErrorAction SilentlyContinue)
		
		if ($Null -ne ($PasswordPol))
		{
			
			$maxPasswordAge = ($PasswordPol).MaxPasswordAge
		}
		
		$expireson = $passwordsetdate.AddDays($maxPasswordAge)
		$today = (Get-Date)
		
		#Gets the count on how many days until the password expires and stores it in the $daystoexpire var
		$daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days
		If ($daystoexpire -lt ($LessThan + 1))
		{
			write-host "$($_.Name) will be added to table" -ForegroundColor red
			If ($daystoexpire -lt 0)
			{
				#0x2 = Password has been expired
				$daystoexpire = "Password is Expired"
			}
			$obj = [PSCustomObject]@{
				
				'Name' = $_.name
				'DaysUntil' = $daystoexpire
				'EmailAddress' = $_.emailaddress
				'LastSet' = $_.PasswordLastSet.ToShortDateString()
				'LockedOut' = $_.LockedOut
				'UPN'  = $_.UserPrincipalName
				'Enabled' = $_.Enabled
				'PasswordNeverExpires' = $_.PasswordNeverExpires
			}
			
			$PWExpiringTable.Add($obj)
		}
		Else
		{
			write-host "$($_.Name)'s account is compliant" -ForegroundColor Green
		}
	}
}

#Sort the table so the Teams message shows expiring soonest to latest
$PWExpiringTable = $PWExpiringTable | sort-Object DaysUntil

$PWExpiringTable | ForEach-Object{
	
	If ($_.DaysUntil -eq "Password is Expired")
	{
		write-host "$($_.name) is expired" -ForegroundColor DarkRed
		$SectionExpired = @{
			activityTitle = "$($_.Name)"
			activitySubtitle = "$($_.EmailAddress)"
			activityText  = "$($_.Name)'s password has already expired!"
			activityImage = $ItemImage
		}
		$ArrayTableExpired.add($SectionExpired)
	}
	Else
	{
		write-host "$($_.name) is expiring" -ForegroundColor DarkYellow
		$Section = @{
			activityTitle = "$($_.Name)"
			activitySubtitle = "$($_.EmailAddress)"
			activityText  = "$($_.Name) needs to change their password in $($_.DaysUntil) days"
			activityImage = $ItemImage
		}
		
		$ArrayTable.add($Section)
		
	}
}


Write-Host "Expired Accounts: $($($ArrayTableExpired).count)" -ForegroundColor Yellow
write-Host "Expiring Accounts: $($($ArrayTable).count)" -ForegroundColor Yellow




$body = ConvertTo-Json -Depth 8 @{
	title = 'Users With Password Expiring - Notification'
	text  = "There are $($ArrayTable.Count) users that have passwords expiring in $($LessThan) days or less"
	sections = $ArrayTable
	
}
Write-Host "Sending expiring users notification" -ForegroundColor Green
Invoke-RestMethod -uri $uri -Method Post -body $body -ContentType 'application/json'


$body2 = ConvertTo-Json -Depth 8 @{
	title = 'Users With Password Expired - Notification'
	text  = "There are $($ArrayTableExpired.Count) users that have passwords that have expired already"
	sections = $ArrayTableExpired
	
}
Write-Host "Sending expired users notification" -ForegroundColor Green
Invoke-RestMethod -uri $uri -Method Post -body $body2 -ContentType 'application/json'

Frequently Asked Questions

Q: What if I have a lot of users will I just get a giant Teams Message

A: No, it will cap the message which is currently set to a depth of 8

$body = ConvertTo-Json -Depth 8 @{
Since there are a lot of users, you can expand the message by click “See More” at the bottom

 

Q: What if I have a user or users who have passwords that have already expired?

A: It will display that the password is already expired instead of a number

 


Sources

  1. https://blogs.technet.microsoft.com/privatecloud/2016/11/02/post-notifications-to-microsoft-teams-using-powershell/
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.


Microsoft Teams, PowerShell
Automation, JSON, Microsoft Teams, Office 365, PowerShell

Post navigation

PREVIOUS
Create an Interactive Active Directory HTML Report With PowerShell
NEXT
Post Inactive Users as a Microsoft Teams Message with PowerShell

9 thoughts on “Post Users with Expiring Passwords as Microsoft Teams Message with PowerShell”

  1. Tim says:
    December 11, 2018 at 2:56 pm

    Very nice article appreciate you taking the time to go through this step by Step Brad!!

    Reply
  2. James says:
    December 17, 2018 at 5:26 am

    This is very useful, and I’ve been testing it in my teams environment.

    Is there anyway to attach a complete list to the post in teams? It seems to only add the first 11, when I have 24 in my report.

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

      Let me look into this, I do see it being cut around 11obj. Side note, I am surprised its even allowing 24 objects to be sent. If the message is too large you will see an error. This is on the Teams end

      Reply
      1. Joe says:
        February 14, 2019 at 10:23 am

        Brad, did you ever find a solution to the limited number of items shown? Our passwords expire in waves and it is not uncommon for us to see upwards of 40 on a given day

        Reply
        1. Brad Wyatt says:
          February 14, 2019 at 10:44 pm

          not yet, believe there is a github bug request on it

          Reply
          1. Lass says:
            October 31, 2019 at 1:05 am

            Hey Brad, any news on this? I have increased the Depth to 20 but still only receive the first 10. Got any fix? Or as mentioned above, a way to attach the log?

          2. Brad Wyatt says:
            November 5, 2019 at 3:16 pm

            there is a size limit to the webhook. at this time it cannot be changed. youll have to modify the size of the message

  3. Jim Parker says:
    August 5, 2019 at 1:55 pm

    Nice idea.

    One suggestion to allow it to scale would be to simply have the power shell add/update this information in an Excel file stored within the Files area of your MS Team, then the notification message could just serve as a heads up and provide a handy link to that file. Could also add that file as a tab within Teams channel as well.

    Reply
  4. Joe Featherstone says:
    June 13, 2024 at 5:11 am

    Hello,

    How would you modify the script to pull the expiration date from a specific OU instead of the whole of AD?

    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,356 People Reached

© 2025   All Rights Reserved.