📜 ⬆️ ⬇️

Notifications about password expiration in Active Directory using PowerShell

Prehistory


The whole story began with the fact that the time came for the next IT audit. Serious uncles from Price Waterhouse Coopers came, gave us a lot of instructions and a couple of scripts that had to be run on the domain controller in order to send them logs later. After reading the texts of the scripts (and there is little, security is above all else) logs were provided to them. And then it began.

The requirements of the PWC in most cases related to security policies. One of them was to enter the password complexity policy and pasword lifetime. Naturally, this was quite easy to do, but soon we faced the resulting problem: Windows does not notify the user about the expiration of his password if the connection is made via a VPN from an external network. The problem turned out to be quite serious because simply updating the password and unlocking the account of such a user was no longer enough. It was necessary that the laptop was in the home, office network. Considering the fact that some users “live” on eternal business trips, the problem turned out to be very serious. Manually track them - that is still a headache, and not admins somehow. It was here that the idea arose to organize the distribution of automatic notifications. After a short time spent searching, a good script was found that remotely tried to perform the necessary actions. I had to finish it.

Since this was my first experience of writing a script under PowerShell - a lot of time was spent (almost full time).

Script


And that's what I got:
')
Import-Module ActiveDirectory #System globalization #$ci = New-Object System.Globalization.CultureInfo("ru-RU") #SMTP server name $smtpServer = "mail.domain.local" #Creating a Mail object $msg = new-object Net.Mail.MailMessage #Creating a Mail object for report $msgr = new-object Net.Mail.MailMessage #Creating SMTP server object $smtp = new-object Net.Mail.SmtpClient($smtpServer) #E-mail structure Function EmailStructure($to,$expiryDate,$upn) { $msg.IsBodyHtml = $true $msg.From = "notification@domain.com" $msg.To.Clear() $msg.To.Add($to) $msg.Subject = "Password expiration notice" $msg.Body =</pre><code> "<html><body><font face='Arial'>This is an automatically generated message from Exchange service.<br><br><b>Please note that the password for your account <i><u>Domain\$upn</u></i> will expire on $expiryDate.</b><br><br>Please change your password immediately or at least before this date as you will be unable to access the service without contacting your administrator.</font></body></html>"</code><pre> } Function EmailStructureReport($to) { $msgr.IsBodyHtml = $true $msgr.From = "notification@domain.com" $msgr.To.Add($to) $msgr.Subject = "Script running report" $msgr.Body = </pre><code>"<html><body><font face='Arial'><b>This is a daily report.<br><br>Script has successfully completed its work.<br>$NotificationCounter users have recieved notifications:<br><br>$ListOfAccounts<br><br></b></font></body></html>"</code><pre> } #Set the target OU that will be searched for user accounts $OU = "OU=Organisation,DC=domain,DC=local" </pre><code>$ADAccounts = Get-ADUser -LDAPFilter "(objectClass=user)" -searchbase $OU -properties PasswordExpired, extensionAttribute15, PasswordNeverExpires, PasswordLastSet, Mail, Enabled | Where-object {$_.Enabled -eq $true -and $_.PasswordNeverExpires -eq $false}</code><pre> $NotificationCounter = 0 $ListOfAccounts = "" Foreach ($ADAccount in $ADAccounts) { $accountFGPP = Get-ADUserResultantPasswordPolicy $ADAccount if ($accountFGPP -ne $null) { $maxPasswordAgeTimeSpan = $accountFGPP.MaxPasswordAge } else { $maxPasswordAgeTimeSpan</pre><code> = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge</code><pre> } #Fill in the user variables $samAccountName = $ADAccount.samAccountName $userEmailAddress = $ADAccount.ExtensionAttribute15 $userPrincipalName = $ADAccount.UserPrincipalName if ($ADAccount.PasswordExpired) { Write-host "The password for account $samAccountName has expired!" } else { $ExpiryDate = $ADAccount.PasswordLastSet + $maxPasswordAgeTimeSpan $TodaysDate = Get-Date $DaysToExpire = $ExpiryDate - $TodaysDate #Calculating DaysToExpireDD to DD format (w/o fractional part and dot) $DaysToExpireDD = $DaysToExpire.ToString() -Split ("\S{17}$") Write-host </pre><code>"The password for account $samAccountName expires on: $ExpiryDate. Days left: $DaysToExpireDD"</code><pre> if (($DaysToExpire.Days -eq 15) -or </pre><code>($DaysToExpire.Days -eq 7) -or ($DaysToExpire.Days -le 3))</code><pre> { $expiryDate = $expiryDate.ToString("d",$ci) #Generate e-mail structure and send message if ($userEmailAddress) { EmailStructure $userEmailAddress $expiryDate $samAccountName $smtp.Send($msg) Write-Host </pre><code>"NOTIFICATION - $samAccountName :: e-mail was sent to $userEmailAddress"</code><pre> $NotificationCounter = $NotificationCounter + 1 $ListOfAccounts = </pre><code>$ListOfAccounts + $samAccountName + " - $DaysToExpireDD days left. Sent to $userEmailAddress<br>"</code><pre> } } } } Write-Host "SENDING REPORT TO IT DEPARTMENT" EmailStructureReport("itdepartment@domain.com") $smtp.Send($msgr) 


Save it as text to a file with the .ps1 extension.

Launch command


Next, create a file with the .cmd extension and write the script launch parameter to it. It looks like this to me:

powershell D:\ExchangeTools\pwde.ps1


Both files are on my mail server. You can try your version.

Creating a schedule


Next, we schedule the daily launch of the .cmd file. I run it every day at 11 am.
Start> All programs> Accesories> System tools> Task scheduler.
Click Action> Create new task.

On the General tab, click the button “Change user” and select the user, on behalf of which all this will work. The user must have read access to the parameters required for the script from AD. We put "Run if user logged on or not" (run regardless of whether the user is logged in or not). When you save the task, the system will ask you to enter a user password.

Next tab Triggers. Everything is simple - set the launch time as you need.

Actions tab, click “New”, select “Start a program” and specify the path to our .cmd file. The last two tabs can not touch, but if there is a need - make changes as you see fit.

Notifications are sent for 15, 7 and 3 or less days.

ATTENTION
Exchange server needs to specify its own address as a relay if it is planned to be sent to addresses outside the domain (duplication with a personal address, for example).

Some will probably ask - “why take the address from the ExtensionAttribute if there is a standard field containing the user's e-mail?”. The answer is simple - a copy of each notification is also sent to the IT department, the user may have more than one address and some system accounts do not have mailboxes in principle, but notifications about them are needed to make life easier directly to administrators. You can enter addresses into ExtensionAttribute15 by logging into the Active Directory tree on a domain controller with administrative rights. In the account properties will be the tab «Attribute Editor». If there are several addresses in the field, they should be separated by a comma.

Source: https://habr.com/ru/post/160599/


All Articles