0

I'm building a script that checks for user accounts with soon-expiring passwords and sends emails to these people reminding them to change their passwords. Yes, our domain settings already generate those prompts counting down from 14 days. Yes, people ignore these. Yes, I'm trying to save work due to people failing to change their passwords in time while working remotely.

In the script I go through an array of the OUs I am responsible for and get the user accounts with expiring passwords and store these in an array containing their DisplayName, Mail, and calculated values containing DaysLeft and ExpiryDate:

$diff = New-TimeSpan -Start ([datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")) -End (Get-Date)

$OusToSearch = @(
    'OU=ORG1,DC=corp,DC=com'
    'OU=ORG2,DC=corp,DC=com'
    'OU=ORG3,DC=corp,DC=com'
)
ForEach ($OU in $OusToSearch) {
    $PwdExpUsersInOU = Get-ADUser -SearchBase $OU -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and Mail -like '*'} -Properties "DisplayName", "mail", "msDS-UserPasswordExpiryTimeComputed" | Where-Object { 
        $diff = New-TimeSpan -End ([datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")) -Start (Get-Date)
        $diff.Days -le 14 -and $diff.Days -ge 0
        } | Select-Object "DisplayName","Mail",@{Name="DaysLeft";Expression={$diff.Days}},@{Name="ExpiryDate";Expression={[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}}
    $PwdExpUsers += $PwdExpUsersInOU
}

Thanks to other askers and answerers here for lots of that code.

This part works. At this point I have an array $PwdExpUsers containing the relevant information.

Next I break this array apart into several smaller arrays in order to send tailored email addressed to each person that query returns with messages appropriate to how soon their passwords are expiring:

Note 1: This is currently testing code and filters for and only creates emails for those with passwords expiring tomorrow, as should be obvious from the code below. Once I get the addressing issue figured out I'll expand this to handle the rest of the array.

Note 2: The message content is HTML I've already stored in variables ($MsgTomorrow) earlier in the script. It works fine.

$Outlook = New-Object -ComObject Outlook.Application

$ExpTomorrow = $PwdExpUsers | Where-Object -FilterScript {$PSItem.DaysLeft -eq '0'}

foreach ($Account in $ExpTomorrow) {
    $Mail = $Outlook.CreateItem(0)
    $Mail.Importance = 2
    $Mail.To = $PSItem.Mail
    $Mail.Subject = "IMPORTANT: Your computer login password expires tomorrow"
    $Mail.HTMLBody = $MsgTomorrow
    $Mail.Save()
}

At the end of this I have emails in my Drafts folder with the correct subject and body, but no email address in the To field.

I assume I am failing to grasp how the $PSItem.Mail value is being passed along, and what $Mail.To expects to receive.

A valid solution would also remove the ForEach bit entirely and allow me to create a single email addresses to all members of the array $ExpTomorrow.

1
  • 1
    $Mail.To = $PSItem.Mail --> $Mail.To = $Account.Mail. BTW why use Outlook for this and not Send-MailMessage ? Commented Mar 31, 2020 at 19:46

1 Answer 1

1

$PSItem -aka $_ ... This is the variable for the value that is running through the pipe line.

Try $Mail.To = $Account.Mail

If this doesn't do it please post example content of $ExpTomorrow

───────

You can also try it this way without outlook.

#
$smtp = "mail.server.com"
$from = "[email protected]"
$subject = "Email Subject Example - Password expiring!"

foreach($Account in $ExpTomorrow){
    # All HTML will go into the body.
    $body = "You are bad at maintaining your passwords, please do it now." 
    $to = $Account.Mail

    # Now send the email using Send-MailMessage 
    send-MailMessage -SmtpServer $smtp -To $to -From $from -Subject $subject -Body $body -BodyAsHtml -Priority high
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you. This solved it. My error was assuming that $PSItem (yes, I know it's $_. I prefer to use the full name when scripting for clarity.) was the same thing as $Account. I'll have to figure out just what their relationship is later.
cleaned up the send-MailMessage bit. As for figuring out their relationship, they don't really have one as the $PSitem is in the $ExpTomorrow pipeline only. It's kind of like using javascript's this keyword.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.