Password expiration e-mail
-
martedì 21 aprile 2009 08:34Hello,
i would like my users to be notified bij e-mail (exchange 2007) when there password is about to expire. Does someone have a script i can use for that ?
thanks Dave
Tutte le risposte
-
martedì 21 aprile 2009 15:50Moderatore
I did something similar in PowerShell and Quest cmdlets:
function Send-Mail{param($smtpServer,$from,$to,$subject,$body)
$smtp = new-object system.net.mail.smtpClient($SmtpServer)
$mail = new-object System.Net.Mail.MailMessage$mail.from = $from
$mail.to.add($to)
$mail.subject = $subject
$mail.body = $body
#$mail.IsBodyHtml = $true$smtp.send($mail)
}# get domain maxPassAge password policy
$maxPassAge = (Get-QADObject (Get-QADRootDSE).defaultNamingContextDN).maximumPasswordAge.value.daysif(!$maxPassAge){
throw "Domain 'MaximumPasswordAge'password policy is not configured (set to 0)."
}# exclude users that cannot change password
#$ldap = "(&(!userAccountControl:1.2.840.113556.1.4.803:=64)(mailNickName=*))"# create calculated property to display days until password expire
$daysUntilExpire = @{n="daysUntilExpire";e={$maxPassAge-$_.passwordAge.value.days}}$expireIn = 10
$smtpServer="smtpServerName"# get enabled users that meet the above criteria
$enabledUsers = Get-QADUser -enabled -passwordNeverExpires $false -size 0 -ldap "(mailNickName=*)"# exclude users that cannot change password
#$enabledUsers = $enabledUsers | where { Get-QADPermission $_ -deny -Account self,everyone}
$enabledUsers = $enabledUsers | where { Get-QADPermission $_ -deny -Account everyone}
$expiredUsers = $enabledUsers | where {$_.passwordAge.value -gt 0 -AND ($maxPassAge-$_.passwordAge.value.days) -gt $expireIn}$expiredUsers | foreach {
$subject="Your password will expire in $expireIn days"
$body="Your password will expire in $expireIn days"
Send-Mail -smtpServer $smtpServer -from "you@domain.com" -to $_.email -subject $subject -body $body
}
HTH
Shay Levy [MVP]
http://blogs.microsoft.co.il/blogs/ScriptFanatic
PowerShell Toolbar- Proposto come risposta Salvador Manaois IIIModerator giovedì 23 aprile 2009 03:04
- Modificato Shay LeviMVP, Moderator giovedì 4 giugno 2009 07:48
- Contrassegnato come risposta IamMredMicrosoft Employee, Owner venerdì 8 gennaio 2010 06:11
-
martedì 21 aprile 2009 16:55oke, so who can i use this. should i run your script on the exchange powershell ?
thanks Dave -
martedì 21 aprile 2009 17:58ModeratoreThe script works against AD. You need to downlod and install Quest AD cmdlets, change some values in the script to match your own and execute the script. You can download Quest AD cmdlets for free here:Test it in your lab before you run it in production.
Shay Levy [MVP]
http://blogs.microsoft.co.il/blogs/ScriptFanatic
PowerShell Toolbar -
mercoledì 3 giugno 2009 17:02Shay,The line that determines the domain policy should be updated as shown in bold:$maxPassAge = (Get-QADObject (Get-QADRootDSE).defaultNamingContextDN).maximumPasswordAge.value.daysThis is using the latest PS and QAD cmdlets.
-
giovedì 4 giugno 2009 07:50ModeratoreThanks! I did a find/replace and mistakanely replaced the property name too (updated the thread).
Shay Levy [MVP]
http://blogs.microsoft.co.il/blogs/ScriptFanatic
PowerShell Toolbar -
martedì 9 giugno 2009 06:57
HiAgo some weeks i write one, the diference with the Shay Levi script is that to do not need to use another tools.Sort descriptin:1. Calculating the Max Password Age2. Getting the all user from AD with password age expire in less 10 days3. Send email for USERS4. Send Report for AdminsPlease change the following:1. All mydomain.local to your local AD, of course the smtp servers and the mail adress2. $max_pwd_life can you change if you have another password age policy (by ex: $max_pwd_life = 70)3. $max_alert with your date before password expiration.Another tips:Can you add this script to your Scheduler, but befor this do you need to sign your script. Or type this command before run:Set-ExecutionPolicy UnRestrictedFor signin se this: http://www.hanselman.com/blog/SigningPowerShellScripts.aspxGood lookcls ############################################################################# # Created by Levente Veres (bergermanus) # Contact: http://my.bergersoft.net # Description: The current script send Alert for users before they password # expires. You can set some values to configure this script. ############################################################################ ############################################################################### # Get The max Password age from AD ############################################################################### function Get-maxPwdAge{ $root = [ADSI]"LDAP://mydomain.local" $filter = "(&(objectcategory=domainDNS)(distinguishedName=DC=codespring,DC=local))" $ds = New-Object system.DirectoryServices.DirectorySearcher($root,$filter) $dc = $ds.findone() $dc.Properties | fl [int64]$mpa = ($dc.Properties[‘maxpwdage’][0]).ToString().Trim("-") #$mpa*(.000000100)/86400 } ############################################################################### # Function to send email to each user ############################################################################### function send_email_user ($remaining_day, $email, $name ) { $today = Get-Date $date_expire = [DateTime]::Now.AddDays($remaining_day) ; $SmtpClient = new-object system.net.mail.smtpClient $mailmessage = New-Object system.net.mail.mailmessage $SmtpClient.Host = "smtp.mydomain.local" $mailmessage.from = "it@mydomain.local" $mailmessage.To.add($email) $mailmessage.Bcc.add("it-reports@mydomain.local") $mailmessage.Subject = “$name, your password expires on mydomain.local ” $mailmessage.IsBodyHtml = $true $mailmessage.Body = "<h1>Dear $name </h1>" $mailmessage.Body +="<h5> Your password for account <font color=red>$email</font> will be expirend in <font color=red><strong>$remaining_day</strong></font> days on <strong>$date_expire</strong></h5>" $mailmessage.Body +="For other question please ask the Administrators !<br /><br />" $mailmessage.Body += " Generated on : $today<br /><br />" $mailmessage.Body += "================================== <br />" $mailmessage.Body += "mydomain.local <br />" $smtpclient.Send($mailmessage) } ############################################################################### # Send REPORT for Admins ############################################################################### function sendmail($body) { $today = Get-Date $SmtpClient = new-object system.net.mail.smtpClient $mailmessage = New-Object system.net.mail.mailmessage $SmtpClient.Host = "smtp.mydomain.local" $mailmessage.from = "it@mydomain.local" $mailmessage.To.add("it-reports@mydomain.local") $mailmessage.Subject = “[Report] mydomain.local password expires” $mailmessage.IsBodyHtml = $true $mailmessage.Body = "<h4>Generated on : $today `n</h4>" + $body $mailmessage.Body += "`n" + $body1 $smtpclient.Send($mailmessage) } ############################################################################### # Search for the active directory users with following conditions # 1. Is in USER category # 2. Is loged in more that 1 times - for eliminate the system accounts # 3. Eliminate the Disbaled Accounts ############################################################################### $strFilter = "(&(objectCategory=User)(logonCount>=1)(!userAccountControl:1.2.840.113556.1.4.803:=2))" $objDomain = New-Object System.DirectoryServices.DirectoryEntry $objSearcher = New-Object System.DirectoryServices.DirectorySearcher $objSearcher.SearchRoot = $objDomain $objSearcher.PageSize = 1000 $objSearcher.Filter = $strFilter $colResults = $objSearcher.FindAll(); #SET the max day before expiration alert $max_alert = 10 ############################################################################### #SET the max password lifetime # In the future i rewrite to ask teh GP for the group. ############################################################################### $max_pwd_life= get-maxPwdAge; $userlist = @() foreach ($objResult in $colResults) {$objItem = $objResult.Properties; if ( $objItem.mail.gettype.IsInstance -eq $True) { $user_name = $objItem.name $user_email = $objItem.email #Transform the DateTime readable $user_logon = [datetime]::FromFileTime($objItem.lastlogon[0]) $result = $objItem.pwdlastset $user_pwd_last_set = [datetime]::FromFileTime($result[0]) #calculate the difference in Day $diff_date = [INT]([DateTime]::Now - $user_pwd_last_set).TotalDays; if (($max_pwd_life - $diff_date) -le $max_alert) { $selected_user = New-Object psobject $selected_user | Add-Member NoteProperty -Name "Name" -Value $objItem.name[0] $selected_user | Add-Member NoteProperty -Name "Email" -Value $objItem.mail[0] $selected_user | Add-Member NoteProperty -Name "LastLogon" -Value $user_logon $selected_user | Add-Member NoteProperty -Name "LastPwdSet" -Value $user_pwd_last_set $selected_user | Add-Member NoteProperty -Name "EllapsedDay" -Value $diff_date $selected_user | Add-Member NoteProperty -Name "RemainingDay" -Value ($max_pwd_life-$diff_date) $userlist+=$selected_user } } } ############################################################################### # Send email for each user ############################################################################### foreach ($userItem in $userlist ) { send_email_user $userItem.RemainingDay $userItem.Email $userItem.Name } ############################################################################### # Sedn email for Admins in reporting format ############################################################################### $bodyme = $userlist| Sort-Object "RemainingDay" | ConvertTo-Html -Title "AD password Status" -Body "<H2>Ad password expiration Status</H2> " -head "<style>td{font-size:smaller;padding:0 0 0 5px;border: 1px solid #003366;}table{border: 1px solid #003366;margin:0;padding:0}tr{margin:0;padding:0;}h2{color:red};th{font-size:smaller;text-align:left;border: 1px solid #003366;background-color:#aaa;}</style>" | foreach {$_ -replace "<table>", "<table cellspacing=0>"} sendmail $bodyme ############################################################################### # END ###############################################################################
.:: bergermanus ::. ======================== http://my.bergersoft.net -
lunedì 15 giugno 2009 23:49Just a quick question to be 100% sure "This is using the latest PS and QAD cmdlets." Do you mean upgrade to V2 CTP3 if I want this script to work ? Can you confirm please ?
$maxPassAge = (Get-QADObject (Get-QADRootDSE).defaultNamingContextDN).maximumPasswordAge.value.days
This line doesn't return anything on PS 1.0.0.0 but this one works:
$maximumPasswordAge = (Get-QADObject (Get-QADRootDSE).defaultNamingContextDN).maximumPasswordAge.days
If someone is interested I did update this script to make it works with Powershell 1.0
-
martedì 16 giugno 2009 06:58ModeratoreIt should run on v1 as well. The diffrenece stems from the last QAD version, in previous versions 'days' was nested inside the value property.
Shay Levy [MVP]
http://blogs.microsoft.co.il/blogs/ScriptFanatic
PowerShell Toolbar -
martedì 16 giugno 2009 17:23FYI
$maxPassAge = (Get-QADObject (Get-QADRootDSE).defaultNamingContextDN).maximumPasswordAge.value.days
All the ".value.days" do not work with QAD version 1.2.2 (Jun 4 2009)
-
mercoledì 17 giugno 2009 08:11ModeratoreRight, as I said, in v1.2 and above there is no value property we should do:
(Get-QADObject (Get-QADRootDSE).defaultNamingContextDN).maximumPasswordAge.Days
Shay Levy [MVP]
http://blogs.microsoft.co.il/blogs/ScriptFanatic
PowerShell Toolbar -
lunedì 13 luglio 2009 09:10If some one got this working on PS1 I would love to have it.
-
lunedì 24 agosto 2009 23:29How about vb?
http://compulsived.com/wordpress/2009/07/18/automated-domain-password-expiration-notifications-through-email/ -
giovedì 15 ottobre 2009 18:51Nisso,
I have two instances of this working. One server has PS 1 and QAD tools 1.1.2.761. The other has a newer QAD (1.1.2.1254) and PS 2.
For the PS1 system, the correct object value reference is: myObject.passwordAge.value.days
On PS2 and newer QAD I had to use: myObject.passwordAge.days
You need to determine what functions are available in your version of PS and QAD.
-Gfuss -
lunedì 23 novembre 2009 14:40
Hi
Thanks alot for the script.Ago some weeks i write one, the diference with the Shay Levi script is that to do not need to use another tools.Sort descriptin:1. Calculating the Max Password Age2. Getting the all user from AD with password age expire in less 10 days3. Send email for USERS4. Send Report for AdminsPlease change the following:1. All mydomain.local to your local AD, of course the smtp servers and the mail adress2. $max_pwd_life can you change if you have another password age policy (by ex: $max_pwd_life = 70)3. $max_alert with your date before password expiration.Another tips:Can you add this script to your Scheduler, but befor this do you need to sign your script. Or type this command before run:Set-ExecutionPolicy UnRestrictedFor signin se this: http://www.hanselman.com/blog/SigningPowerShellScripts.aspxGood lookcls ############################################################################# # Created by Levente Veres (bergermanus) # Contact: http://my.bergersoft.net # Description: The current script send Alert for users before they password # expires. You can set some values to configure this script. ############################################################################ ############################################################################### # Get The max Password age from AD ############################################################################### function Get-maxPwdAge{ $root = [ADSI]"LDAP://mydomain.local" $filter = "(&(objectcategory=domainDNS)(distinguishedName=DC=codespring,DC=local))" $ds = New-Object system.DirectoryServices.DirectorySearcher($root,$filter) $dc = $ds.findone() $dc.Properties | fl [int64]$mpa = ($dc.Properties[‘maxpwdage’][0]).ToString().Trim("-") #$mpa*(.000000100)/86400 } ############################################################################### # Function to send email to each user ############################################################################### function send_email_user ($remaining_day, $email, $name ) { $today = Get-Date $date_expire = [DateTime]::Now.AddDays($remaining_day) ; $SmtpClient = new-object system.net.mail.smtpClient $mailmessage = New-Object system.net.mail.mailmessage $SmtpClient.Host = "smtp.mydomain.local" $mailmessage.from = "it@mydomain.local" $mailmessage.To.add($email) $mailmessage.Bcc.add("it-reports@mydomain.local") $mailmessage.Subject = “$name, your password expires on mydomain.local ” $mailmessage.IsBodyHtml = $true $mailmessage.Body = "<h1>Dear $name </h1>" $mailmessage.Body +="<h5> Your password for account <font color=red>$email</font> will be expirend in <font color=red><strong>$remaining_day</strong></font> days on <strong>$date_expire</strong></h5>" $mailmessage.Body +="For other question please ask the Administrators !<br /><br />" $mailmessage.Body += " Generated on : $today<br /><br />" $mailmessage.Body += "================================== <br />" $mailmessage.Body += "mydomain.local <br />" $smtpclient.Send($mailmessage) } ############################################################################### # Send REPORT for Admins ############################################################################### function sendmail($body) { $today = Get-Date $SmtpClient = new-object system.net.mail.smtpClient $mailmessage = New-Object system.net.mail.mailmessage $SmtpClient.Host = "smtp.mydomain.local" $mailmessage.from = "it@mydomain.local" $mailmessage.To.add("it-reports@mydomain.local") $mailmessage.Subject = “[Report] mydomain.local password expires” $mailmessage.IsBodyHtml = $true $mailmessage.Body = "<h4>Generated on : $today `n</h4>" + $body $mailmessage.Body += "`n" + $body1 $smtpclient.Send($mailmessage) } ############################################################################### # Search for the active directory users with following conditions # 1. Is in USER category # 2. Is loged in more that 1 times - for eliminate the system accounts # 3. Eliminate the Disbaled Accounts ############################################################################### $strFilter = "(&(objectCategory=User)(logonCount>=1)(!userAccountControl:1.2.840.113556.1.4.803:=2))" $objDomain = New-Object System.DirectoryServices.DirectoryEntry $objSearcher = New-Object System.DirectoryServices.DirectorySearcher $objSearcher.SearchRoot = $objDomain $objSearcher.PageSize = 1000 $objSearcher.Filter = $strFilter $colResults = $objSearcher.FindAll(); #SET the max day before expiration alert $max_alert = 10 ############################################################################### #SET the max password lifetime # In the future i rewrite to ask teh GP for the group. ############################################################################### $max_pwd_life= get-maxPwdAge; $userlist = @() foreach ($objResult in $colResults) {$objItem = $objResult.Properties; if ( $objItem.mail.gettype.IsInstance -eq $True) { $user_name = $objItem.name $user_email = $objItem.email #Transform the DateTime readable $user_logon = [datetime]::FromFileTime($objItem.lastlogon[0]) $result = $objItem.pwdlastset $user_pwd_last_set = [datetime]::FromFileTime($result[0]) #calculate the difference in Day $diff_date = [INT]([DateTime]::Now - $user_pwd_last_set).TotalDays; if (($max_pwd_life - $diff_date) -le $max_alert) { $selected_user = New-Object psobject $selected_user | Add-Member NoteProperty -Name "Name" -Value $objItem.name[0] $selected_user | Add-Member NoteProperty -Name "Email" -Value $objItem.mail[0] $selected_user | Add-Member NoteProperty -Name "LastLogon" -Value $user_logon $selected_user | Add-Member NoteProperty -Name "LastPwdSet" -Value $user_pwd_last_set $selected_user | Add-Member NoteProperty -Name "EllapsedDay" -Value $diff_date $selected_user | Add-Member NoteProperty -Name "RemainingDay" -Value ($max_pwd_life-$diff_date) $userlist+=$selected_user } } } ############################################################################### # Send email for each user ############################################################################### foreach ($userItem in $userlist ) { send_email_user $userItem.RemainingDay $userItem.Email $userItem.Name } ############################################################################### # Sedn email for Admins in reporting format ############################################################################### $bodyme = $userlist| Sort-Object "RemainingDay" | ConvertTo-Html -Title "AD password Status" -Body "<H2>Ad password expiration Status</H2> " -head "<style>td{font-size:smaller;padding:0 0 0 5px;border: 1px solid #003366;}table{border: 1px solid #003366;margin:0;padding:0}tr{margin:0;padding:0;}h2{color:red};th{font-size:smaller;text-align:left;border: 1px solid #003366;background-color:#aaa;}</style>" | foreach {$_ -replace "<table>", "<table cellspacing=0>"} sendmail $bodyme ############################################################################### # END ###############################################################################
How should i "test-run" it before i run it live on my prod server?
Any help would be thankfull...
And one more question...
The script reports all the users whos password is set to "never expire". How can i exclude them from the list?
Regards
B -
lunedì 23 novembre 2009 17:42ModeratoreI don't want to complicate the discussion too much, but here is a VBScript solution prompted by a thread in the newsgroups. This requires no cmdlets or specific version of Windows Server. It does require CDO to send the email messages, but you can replace the email function. The program is linked here:
http://www.rlmueller.net/PasswordExpires.htm
The script excludes users with "Password never expires" set.
Richard Mueller
MVP ADSI -
giovedì 16 dicembre 2010 23:14
This is an old thread, but it seems like Shay's solution might not deal with users with fine grain password controls in place.
Rich
-
venerdì 17 dicembre 2010 07:40ModeratoreNo it doesn't, check this blog post:
http://blogs.msdn.com/b/adpowershell/archive/2010/02/26/find-out-when-your-password-expires.aspx
Shay Levy [MVP]
PowerShay.com
PowerShell Toolbar -
lunedì 24 gennaio 2011 16:56These are all great, but am i missing the obvious as to how to run these on a daily basis without using built-in Windows scheduling service?
-
giovedì 8 settembre 2011 19:20
For fine grained password policies, you can use PowerShell. See my post New-PasswordReminder.ps1 - email users when their password will soon expire
-
martedì 26 giugno 2012 05:51
For fine grained password policies, you can use PowerShell. See my post New-PasswordReminder.ps1 - email users when their password will soon expire
HI,
I can run the script fin in demo and previewuser but not working in normal or task?PS C:\scripts> .\New-PasswordReminder.ps1 -demo
User Expires Policy
======================== ======= ===========
testuser01 2 90
Development 4 90
testuser1 11 90PS C:\scripts> .\New-PasswordReminder.ps1
Send-MailMessage : Cannot validate argument on parameter ‘To’. The argument is null or empty. Supply an argument that i
s not null or empty and then try the command again.
At C:\scripts\New-PasswordReminder.ps1:346 char:28
+ Send-MailMessage -To <<<< $accountObj.mail -Subject "Your password expires in $DaysTillE
xpire day(s)" -Body $emailbody -From $EmailFrom -Priority High -BodyAsHtml
+ CategoryInfo : InvalidData: (:) [Send-MailMessage], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.SendMailMessageSend-MailMessage : Cannot validate argument on parameter 'To'. The argument is null or empty. Supply an argument that i
s not null or empty and then try the command again.
At C:\scripts\New-PasswordReminder.ps1:346 char:28
+ Send-MailMessage -To <<<< $accountObj.mail -Subject "Your password expires in $DaysTillE
xpire day(s)" -Body $emailbody -From $EmailFrom -Priority High -BodyAsHtml
+ CategoryInfo : InvalidData: (:) [Send-MailMessage], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.SendMailMessage -
martedì 26 giugno 2012 13:24
Download version 2.4 from http://www.ehloworld.com/318 and try that. If you still run into issues, post a comment on that page and I'll work to get it resolved.- Proposto come risposta AUSSUPPORT lunedì 2 luglio 2012 23:03

