User PasswordExpired notification

Looking for help and also for advice, i can’t put my head around
Need send user notification:14, 7 and 1 day before ps expared
also how i can create .csv for each day email was sent
this is my code, its not working properly, but i think maybe you can explain me how to fix it
also sime time i received error on this line

  $daystoexpire = (New-TimeSpan -Start "$today" -End "$expireson").Days

and error:
New-TimeSpan : Cannot bind parameter ‘End’. Cannot convert value “180.00:00:00” to type “System.DateTime”. Error: “String was not recognized as a valid DateTime.”

  • … $daystoexpire = (New-TimeSpan -Start “$today” -End “$expireson”).Days

Code

$FourteenDayWarnDate = 14
$SevenDayWarnDate = 7
$OneDayWarnDate = 1

$Searchbase = "OU=...,DC=..."
$filter = {(Enabled -eq $True) -and (PasswordNeverExpires -eq $False) -and (PasswordExpired -eq $false)}
$adProperties = @("Name", 'PasswordNeverExpires', 'PasswordExpired', 'PasswordLastSet', 'EmailAddress')
$users = 
Get-ADUser -Searchbase $Searchbase -Filter $filter -Properties $adProperties
foreach ($user in $users)
{
  $Name = $user.Name
  $emailaddress = $user.emailaddress
  $passwordSetDate = $user.PasswordLastSet
  $maxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge
  $expireson = $passwordsetdate + $maxPasswordAge
  $today = (get-date)
  $daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days
  $subject="..."
  $body =@"
"@
  
  if ($daystoexpire -lt $FourteenDayWarnDate)
  {
    
    #Send-Mailmessage -smtpServer $smtpServer -from $from -to $emailaddress -subject $subject -body $body -bodyasHTML -priority High
    Write-Host "$($user.Name): Email notification sent" -BackgroundColor DarkGreen
  } 
  
  if ($daystoexpire -lt $SevenDayWarnDate)
  {
    
    #Send-Mailmessage -smtpServer $smtpServer -from $from -to $emailaddress -subject $subject -body $body -bodyasHTML -priority High
    Write-Host "$($user.Name): Email notification sent" -BackgroundColor DarkGreen
  }
  
  if ($daystoexpire -lt $OneDayWarnDate)
  {
   
    #Send-Mailmessage -smtpServer $smtpServer -from $from -to $emailaddress -subject $subject -body $body -bodyasHTML -priority High
    Write-Host "$($user.Name): Email notification sent" -BackgroundColor DarkGreen
  } 
  else {}        
}

Thanks

Brad,
Welcome back to the forum. :wave:t3: Long time no see. :wink:

I’d recommend not to re-invent the wheel again and again. There are more than enough working examples out there for those standard tasks like notifying users about their expiring passwords.

Simply search for “powershell password expiration notification email” with your prefered internet search engine and pick the one you like. :man_shrugging:t3:

One quite promissing search hit would be the blog post from Mike Kanakos even including a step by step explanation of the process.

https://4sysops.com/archives/a-password-expiration-reminder-script-in-powershell/

Thank you Olaf for your help( :slight_smile: as always)

There’s a group policy setting that will do exactly this.

hmmm … I’m curious … can you show which one it is? You may use this site

https://gpsearch.azurewebsites.net

There you can search and copy the deep link url. Like this for example:

https://gpsearch.azurewebsites.net/Default.aspx?PolicyID=4843

That’s the setting for activating the screen saver.

While not email, the notification is part of the login process. Interactive log-on prompt user to change password before expiration - Windows Security | Microsoft Learn

What a pity. :smirk: I was hoping you had the ultimate trick do solve this issue. :smiling_face: :wink: :love_you_gesture:t3:

Thank you neemobeer,
but GPO not the option,
in my case powershell script should do the work
one more question: How i can create .csv file with users to who email was sent
Thanks

Just out of curiousity - why … whatfor? Don’t you trust your email system? Will you archive this information? And with what approach would you like to work - your own one or the one I linked? … or a completely other one?

Basically you collect the information inside your loop and output it later on to a CSV file with Export-Csv

The most common approach is to assign your loop to a variable and and output inside the loop the information you’re after.
Here you have an example of what I mean:

$ServiceList = Get-Service

$Result =
foreach ($Service in $ServiceList) {
    if ($Service.ServiceType -contains 'Win32OwnProcess') {
        [PSCustomObject]@{
            Name   = $Service.Name
            Status = $Service.Status
            Type   = $Service.ServiceType
        }
    }
}
$Result