The current challenge has to do with scheduling email traffic in a lab environment. I previously posted about job scheduling in PowerShell with this post I am combining this into a useful way to schedule PowerShell scripts. The scheduled PowerShell scripts in this case will send emails through Exchange to simulate a ‘live’ environment. My plan is to simulate traffic for testing with CU updates as well as features built into Exchange like quotas, message limits retention policies, transport rules and more.
The Script
With this script I am going to try a different approach to explaining how the script works, so I am going to visually break out the major script parts below:

function random-mailboxes { # Prep Random mailboxes (version 1) $mbxcount = (get-mailbox | where {($_.RecipientTypeDetails -ne "DiscoveryMailbox") -and ($_.RecipientTypeDetails -ne "RoomMailbox")}).count $range = get-random -minimum 0 -maximum $mbxcount $mailbox = (get-mailbox | where {($_.RecipientTypeDetails -ne "DiscoveryMailbox") -and ($_.RecipientTypeDetails -ne "RoomMailbox")}).primarysmtpaddress # Create Random User List $counter = 0 $userlist = @() while ($counter -lt $range) { $position = get-random -minimum 0 -maximum $mbxcount $alias = $mailbox[$position].local+"@"+$mailbox[$position].domain $validation = $false if ($userlist -contains $alias) { $validation = $true $counter-- } $counter++ if ($validation -eq $false) { # Put all the mailboxes into a list of unique results $global:userlist += @($alias) } } }
The above section of code is for choosing random mailboxes for use in the script. The thought process is if this were to simulate a list of mailboxes that are sending emails, then a random group would be good because that would simulate a ‘real world’ environment where emails being sent to and from people are not predictable as compared to a controlled lab environment. From the code you can see that I am gathering up the PrimarySMTPAddresses of all mailboxes and randomly adding these to a user list (global variable) to be used by other parts of the script. Because of the way the primarysmtpaddres is stored, I need to reassemble it use it later in the script.
Next Section
This section of code gathers information for the email messages that will be scheduled later. All variables will be used by either of the three choices in the script (all, random, csv).
Function create-emailps1 { cls write-host " " $filepath = read-host "Enter the filename and path of the PS1 file to be run for email population [i.e. c:\temp\scripttorun.ps1]" $sendto = read-host "Do you want to send emails to (a) All mailboxes, (r) Random mailboxes or (c) use a CSV file" # Set the email server used for email relay $transport = (get-transportservice).name $smtpserver = $transport[0]
Next Section
This section of code is for sending emails to all users in Exchange. Two email lists are created – $Sender and $recipient. For $sender the loop will go incrementally forward with the $counter variable in the loop, while $recipient will be going backwards (starting from the last value and proceeding to the first value) via the $mbxcount variable (total number of user mailboxes). The script also asks for a subject, body and attachment.
if ($sendto -eq "a") { write-host " " write-host "This section is for sending test messages to all mailboxes" -ForegroundColor green write-host " " $noofcopies = read-host "How many test email messages to be sent per sender" $subject = read-host "Enter a subject line for the test message" $body = "This is a test message to help populate email in the mailboxes on Exchange 2013." $attachment = read-host "Specify an attachement for the test email" $mbxcount = ($mailboxes = Get-Mailbox -Filter 'RecipientTypeDetails -eq "UserMailbox"' -resultsize unlimited).count $mbxcount-- $mailboxes = (Get-Mailbox -Filter 'RecipientTypeDetails -eq "UserMailbox"' -resultsize unlimited).primarysmtpaddress # Create one line per mailbox foreach ($line in $mailboxes) { # Recipient - starts from the end of the mailbox variable $recipient = $mailboxes[$mbxcount] # Sender starts from the beginning of the mailbox variable $sender = $line $variable = '$counter' add-content $filepath "$variable = 0" add-content $filepath "while ('$counter' -lt $noofcopies) {" add-content $filepath "send-mailmessage -from '$sender' -to '$recipient' -subject '$subject' -body '$body' -smtpserver '$smtpserver' -attachment '$attachment'" add-content $filepath "$variable++" add-content $filepath "}" $mbxcount-- } }
Next Section
This section of code is for sending emails to random users in Exchange. Two email lists are created – $Sender and $recipient. In this case I created two different loops. One for $sender (the outer loop) and $recipient (the inner loop). Essentially for each value in the $sender variable, we’ll created a set of code for entire list of values in the $recipient variable. The script also asks for a subject, body and attachment. A very similar setup to what was done for all mailboxes above.
if ($sendto -eq "r") { write-host " " write-host "This section is for sending test messages to random mailboxes" -ForegroundColor green write-host " " $noofcopies = read-host "How many test email messages to be sent per sender" $subject = read-host "Enter a subject line for the test message" $body = "This is a test message to help populate email in the mailboxes on Exchange 2013." $attachment = read-host "Specify an attachement for the test email" # Choose random mailboxes random-mailboxes $sender = $userlist random-mailboxes $recipient = $userlist # Create one line per mailbox foreach ($line in $sender) { foreach ($line2 in $recipient) { $sender = $line $recipient = $line2 $variable = '$counter' add-content $filepath "$variable = 0" add-content $filepath "while ($variable -lt $noofcopies) {" add-content $filepath "send-mailmessage -from '$sender' -to '$recipient' -subject '$subject' -body '$body' -smtpserver '$smtpserver' -attachment '$attach'" add-content $filepath "$variable++" add-content $filepath "}" } } }
Final Section
This is a much smaller section of code, where a CSV file is utilized for the various parts of the email script. Simply laid out, this section asks for the CSV file, normalizes the variables and then writes everything to the PS1 file like the two above sections do.
if ($sendto -eq "c") { write-host " " write-host "This section is for sending test messages using a CSV file" -ForegroundColor green write-host " " # CSV format should be sender,recipient,subject,body,attachment,noofcopies $csvfile = read-host "Specify a CSV file to read from" $csv = import-csv $csvfile foreach ($line in $csv) { $sender = $line.sender $recipient = $line.recipient $subject = $line.subject $body = $line.body $attachment = $line.attachment $noofcopies = $line.noofcopies $variable = '$counter' add-content $filepath "$variable = 0" add-content $filepath "while ($variable -lt $noofcopies) {" add-content $filepath "send-mailmessage -from '$sender' -to '$recipient' -subject '$subject' -body '$body' -smtpserver '$smtpserver' -attachment '$attachment'" add-content $filepath "$variable++" add-content $filepath "}" } }
In Action
First tested was sending messages to all users in the organizations. Here is the run through:
Contents of the PS1 file that can be scheduled later or run manually:
Here is the run through with randomly picked senders and recipients:
Contents of the PS1 file that can be scheduled later or run manually:
Here is the run through with a pre-created CSV file:
Contents of the PS1 file that can be scheduled later or run manually:
Contents of the CSV file used:
Scheduling
Combining the above code with the scheduling code from my previous post, you can then schedule some test mail flow by using the PS1 file that was created in the above sections of code. You can also manually run the script later if you wish. Here is a decision making code block I made for this:
This would then require my schedule-email function I wrote in a previous blog article. That’s it. A lot of line codes to create some easy to use PowerShell scripts for later use or scheduled use.
Resources
Get-Random
Add-Content
Send-MailMessage
New-JobTrigger
Register-ScheduledJob