0

I have this PowerShell script that sends out emails to managers if the user's account is expiring within a certain amount of days, however, managers get a separate email for every user. Is there a way to send only one email with the list of users?

Import-Module ActiveDirectory

#Set our non-changing variables for the email
$From = "accountexpiry@company.com"
$CC = "helpdesk@company.com"
$SMTPServer = "mail.company.com"

#Get the start date, which defaults to today, and the end date which is based off the start date
$startDate = Get-Date
$endDate = $startDate.AddDays(7)

#Query AD for all the accounts between our dates and request for a couple additional properties
$Users = Get-ADUser -Filter {AccountExpirationDate -gt $startDate -and AccountExpirationDate -lt $endDate} -Properties AccountExpirationDate, Manager

#Loop through the query results
Foreach($User in $Users)
{

    #The $User.Manager is not a email address, but a Distinguished Name; to get the email we can pass it to Get-Aduser though
    $Manager = Get-ADUser $User.Manager -Properties EmailAddress

    #Set our dynamic variables
    $To = $Manager.EmailAddress
    $Subject = "Account Expiration Notification for " + $User.Name
    $Body = 
    "Hello,
    This notification is to inform you that the account for $($User.Name) will expire on $($User.AccountExpirationDate). 
    If you need to extend this, please contact HR and IT will process the request.

    Thank you,
    IT Help Desk"

    Send-MailMessage -To $To -From $From -Subject $Subject -SmtpServer $SMTPServer -Body $Body
}
Sam
  • 115
  • 2
  • 9
  • Yes, but you should first specify how the email text should look for that. – marsze Oct 26 '21 at 21:01
  • 1
    One way to accomplish it would be to use Group-Object on the result of $users by their Managers and then loop through the grouped-object and essentially only send one mail-message per manager. You'd need to modify the message to expand the info of the grouped object into a list or something so the email didn't look terrible. – thepip3r Oct 26 '21 at 21:21

1 Answers1

1

As @thepip3r suggested in his comment, a good way to send just one email per Manager could be using Group-Object. Code below should do the trick, haven't tested it but I believe it should work.

One thing to note is that, this code will assume there is always a list of users that will expire and will send the list of users using the following format:

This notification is to inform you that the account for the following users are about to expire:
- user.example1 expires on XX/XX/XXXX
- user.example2 expires on XX/XX/XXXX
- user.example3 expires on XX/XX/XXXX

If you need to extend this, please contact HR and IT will process the request.

If you want to change the wording of the email for when there is only one user and when there are more than one then you should work on some conditions for that.

Code

Import-Module ActiveDirectory

#Set our non-changing variables for the email
$mailProps = @{
    From = "accountexpiry@company.com"
    CC = "helpdesk@company.com"
    SMTPServer = "mail.company.com"
    BodyAsHTML = $true
}

#Get the start date, which defaults to today, and the end date which is based off the start date
$startDate = Get-Date
$endDate = $startDate.AddDays(7)

#Query AD for all the accounts between our dates and request for a couple additional properties
$props = @{
    Filter = "AccountExpirationDate -gt '$startDate' -and AccountExpirationDate -lt '$endDate'"
    Properties = 'AccountExpirationDate', 'Manager'
}
$Users = Get-ADUser @props

# Save the body on a ScriptBlock for later use
$bodyScriptBlock = {
    param([string[]]$UserList)
@"
Hello,</br>
This notification is to inform you that the account for the following users are about to expire:</br>
{0}</br></br>
If you need to extend this, please contact HR and IT will process the request.</br>
</br>
Thank you,</br>
IT Help Desk</br>
"@ -f ($UserList -join '</br>')
}

# Group all users by their Manager
$Users | Group-Object Manager | ForEach-Object {
    
    # Get this Manager's email address
    $managerEmail = (Get-ADUser $_.Name -Properties EmailAddress).EmailAddress

    # Create a string[] with the user's Name and their Account's Expiration Date
    $userList = foreach($user in $_.Group)
    {
        '- {0} expires on {1}' -f $user.Name, $user.AccountExpirationDate
    }
    
    # Execute the Body scriptblock passing this user's list
    $body = & $bodyScriptBlock -UserList $userList

    # Set the remaing values for Mail props
    $mailProps.To = $managerEmail
    $mailProps.Subject = "Account Expiration Notification for Managees" # ??? No idea what to put here
    $mailProps.Body = $body

    # Send the email with the list of users
    Send-MailMessage @mailProps
}

Email Example

exampleEmail

Santiago Squarzon
  • 41,465
  • 5
  • 14
  • 37
  • 1
    Thank you for the code! This works great. I do have one issue. In the email rather than creating a user list, it's adding users on the same line. I was able to add
    {0} in the body section but it still lists all the users in the same line. In idea how I can fix this?
    – Sam Oct 27 '21 at 20:07
  • @Sam Oh my, I totally forgot this was HTML. My bad. See my edits, if you're looking for something prettier (HTML related), please ask a new question and if this one solved your problem, please consider accepting it. – Santiago Squarzon Oct 27 '21 at 20:18
  • 1
    That worked thank you! – Sam Oct 28 '21 at 01:30
  • @Sam Sure no problem. You could [accept](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work/5235#5235) the answer if it was helpful. – Santiago Squarzon Oct 28 '21 at 01:51
  • sorry I forgot to ask, how can output to a log file from within the PowerShell. I really appreciate your help. – Sam Oct 29 '21 at 16:21
  • @Sam it depends on what you want to use as log, if you want to export `$userList` to a file just do `$userList | Out-File path\to\log.log`. – Santiago Squarzon Oct 29 '21 at 16:24
  • 1
    Thank you. I was able to use this. Write-Output "Creating Log File" $day = $today.Day $month = $today.Month $year = $today.Year $date = "$day-$month-$year" $logFileName = "$date-userexpiring.csv" $userList | Out-File "C:\UserLogs\$logFileName" – Sam Oct 29 '21 at 16:39