If you’ve read any of my posts in the past, you know that I’ve got a lab at the office. Part of this includes a handful of Exchange Servers. To better simulate “real-world” (not stress-test) simulations, I want to send messages around the organization. Thankfully, I’ve had some experience with Exchange Web Services (EWS) in the past.
Here’s what I came up with:
# Get the mailboxes directly from Active Directory
$Mailboxes = Get-ADUser -LDAPFilter "(&(&(&((msExchHomeServerName=*EXMBX*)(description=*)))))" -Properties mail | Select-Object -ExpandProperty mail
# Get possible attachments
$AttachmentPath = "\\Demo.Lab\Files\Scripts\Exchange\Users\Attachments\"
$AllAttachments = Get-ChildItem -Path $AttachmentPath -File
#These are my possible Exchange Servers
$ExchangeServers = "EASTEXMBX01v", "EASTEXMBX02v", "WESTEXMBX01v", "WESTEXMBX02v"
# When does the simulated "workday" start and end?"
# Numbers are in "hour" format: 8 = 8:00 AM = 08:00 / 19 = 7:00 PM = 19:00
$WordHourStart = 8
$WorkHourEnd = 20
# Calculate the current day of the week and the current hour of the day
$WorkDay = ( get-date ).ToUniversalTime().DayOfWeek.value__ -in 1..5 # Monday through Friday
$WorkHours = ( ( Get-Date ).ToUniversalTime().Hour -ge $WorkHourStart ) -and ( ( Get-Date ).ToUniversalTime().Hour -le $WorkHourEnd ) # Business Hours
$MinSleepTime = 10 # seconds between message sending
$MaxSleepTime = 15 # seconds between message sending
So now I’ve got the bounds of when I want to send these messages (Work hours/days) and how frequently I want to send messages.
Then I just begin a while loop when I’m in within “working hours” and repeat.
# Pick any email account for
$FromMailbox = ( $Mailboxes | Get-Random -Count 1 )
$ToMailboxes = ( $Mailboxes | Get-Random -Count ( Get-Random -Minimum 1 -Maximum 10 ) )
Only one account can send a message – so I grab one at random. Then I need to select the possible recipients. Here I’m using between 1 and 10, but you can easily change this to whatever you like.
Then I setup my impersonation user (more about that here)
#region Impersonation User
$EWSDomain = "DEMOLAB"
$EWSUsername = "ExchangeSender"
$EWSPassword = "YouDon'tGetThisFromMe"
#endregion Impersonation User
Now I need to load the Exchange Web Services API into memory (download here)
#region Load the Managed API's DLL
$EwsDll = "C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll"
try
{
# Load the Exchange Types
[Void][Reflection.Assembly]::LoadFile($EwsDll)
$ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_SP1
## Create Exchange Service Object
$EWS = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion)
## Set Credentials to use explict credentials
$ImpersonationUser = New-Object System.Net.NetworkCredential($EWSUsername,[string]$EWSPassword, $EWSDomain)
$EWS.Credentials = $ImpersonationUser
$EWS.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $FromMailbox)
}
catch [System.Exception]
{
Write-Error ( "Exchange Web Services Managed API load failed." )
return $null
break
}
#endregion Load the Managed API's DLL
Since I want the mail to go through ANY mailbox server, I elected to not use Autodiscovery. You can choose how to do this for yourself. Then I create the email and need some random text for the subject and body. For this I shamelessly use the Web API available from LoremIpsum. The last construction step is to add the attachments (if I have any) and send the message.
#Write-Host "Performing AutoDiscovery"
#$EWS.AutodiscoverUrl($FromMailbox, { $true })
$ExchangeServer = $ExchangeServers | Get-Random
Write-Host "Building URL for EWS using $ExchangeServer"
$EWS.Url = "https://$( $ExchangeServer ).demo.lab/EWS/Exchange.asmx"
Write-Host "Creating new Email Object"
$Email = New-Object -TypeName Microsoft.Exchange.WebServices.Data.EmailMessage($EWS)
Write-Host "Assigning From Address: $FromMailbox"
$Email.From = $FromMailbox
Write-Host "Adding Recipients:"
$i = 1
ForEach ( $Recipient in $ToMailboxes )
{
Write-Host "`t#$( $i ): $Recipient"
$Email.ToRecipients.Add($Recipient) | Out-Null
$i++
}
Write-Host "Adding Subject" -ForegroundColor DarkCyan
$SubjectWordCount = Get-Random -Minimum 3 -Maximum 10
Write-Host "`tInvoking random word generator..." -ForegroundColor Cyan
$Feed = Invoke-WebRequest -Uri "http://lipsum.com/feed/xml?amount=$SubjectWordCount&start=yes&what=words"
$Email.Subject = ( [xml]( $Feed.Content ) ).feed.lipsum
Write-Host "Adding Body" -ForegroundColor DarkCyan
$BodyParagraphCount = Get-Random -Minimum 1 -Maximum 10
Write-Host "`tInvoking random paragraph generator..." -ForegroundColor Cyan
$Feed = Invoke-WebRequest -Uri "http://lipsum.com/feed/xml?amount=$BodyParagraphCount&start=yes&what=paras"
$Email.Body = ( [xml]( $Feed.Content ) ).feed.lipsum
Write-Host "Adding Attachments"
$AttachmentCount = Get-Random -Minimum 0 -Maximum $AllAttachments.Count
if ( $AttachmentCount -gt 0 )
{
$Attachments = $AllAttachments | Get-Random -Count $AttachmentCount
$i = 1
ForEach ( $Attachment in $Attachments )
{
Write-Host "`t#$( $i ): $( $Attachment.Name )"
$Email.Attachments.AddFileAttachment($Attachment.FullName) | Out-Null
$i++
}
}
else
{
Write-Host "No attachments" -ForegroundColor Yellow
}
Write-Host "Sending Email... " -NoNewline
$Email.SendAndSaveCopy([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::SentItems)
Write-Host "[Message Sent!]" -ForegroundColor Green
$SleepTime = Get-Random -Minimum $MinSleepTime -Maximum $MaxSleepTime
Write-Host "Sleeping for $SleepTime seconds" -ForegroundColor Yellow
Start-Sleep -Seconds $SleepTime
Putting it all together yields the following:
# Send Random Messages
# No longer done this way
#$UserCsv = "\\Demo.Lab\Files\Scripts\Exchange\Users\AllUsers.csv"
#$Mailboxes = Import-Csv -Path $UserCsv
# Get the mailboxes directly from Active Directory
$Mailboxes = Get-ADUser -LDAPFilter "(&(&(&((msExchHomeServerName=*EXMBX*)(description=*)))))" -Properties mail | Select-Object -ExpandProperty mail
# Get possible attachments
$AttachmentPath = "\\Demo.Lab\Files\Scripts\Exchange\Users\Attachments\"
$AllAttachments = Get-ChildItem -Path $AttachmentPath -File
#These are my possible Exchange Servers
$ExchangeServers = "EASTEXMBX01v", "EASTEXMBX02v", "WESTEXMBX01v", "WESTEXMBX02v"
# When does the simulated "workday" start and end?"
# Numbers are in "hour" format: 8 = 8:00 AM = 08:00 / 19 = 7:00 PM = 19:00
$WordHourStart = 8
$WorkHourEnd = 20
# Calculate the current day of the week and the current hour of the day
$WorkDay = ( get-date ).ToUniversalTime().DayOfWeek.value__ -in 1..5 # Monday through Friday
$WorkHours = ( ( Get-Date ).ToUniversalTime().Hour -ge $WorkHourStart ) -and ( ( Get-Date ).ToUniversalTime().Hour -le $WorkHourEnd ) # Business Hours
$MinSleepTime = 10 # seconds between message sending
$MaxSleepTime = 15 # seconds between message sending
$CurrentMessage = 1
While ( $WorkDay -and $WorkHours )
{
# Calculate the current day of the week and the current hour of the day
$WorkDay = ( Get-date ).ToUniversalTime().DayOfWeek.value__ -in 1..5 # Monday through Friday
$WorkHours = ( ( Get-Date ).ToUniversalTime().Hour -ge $WorkHourStart ) -and ( ( Get-Date ).ToUniversalTime().Hour -le $WorkHourEnd ) # Business Hours
Write-Host "Writing Message #$( $CurrentMessage )" -ForegroundColor Red
# Pick any email account for
$FromMailbox = ( $Mailboxes | Get-Random -Count 1 )
$ToMailboxes = ( $Mailboxes | Get-Random -Count ( Get-Random -Minimum 1 -Maximum 10 ) )
#region Impersonation User
$EWSDomain = "DEMOLAB"
$EWSUsername = "R2D2"
$EWSPassword = "C-3POLuke"
#endregion Impersonation User
#region Load the Managed API's DLL
$EwsDll = "C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll"
try
{
# Load the Exchange Types
[Void][Reflection.Assembly]::LoadFile($EwsDll)
$ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_SP1
## Create Exchange Service Object
$EWS = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion)
## Set Credentials to use explict credentials
$ImpersonationUser = New-Object System.Net.NetworkCredential($EWSUsername,[string]$EWSPassword, $EWSDomain)
$EWS.Credentials = $ImpersonationUser
$EWS.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $FromMailbox)
}
catch [System.Exception]
{
Write-Error ( "Exchange Web Services Managed API load failed." )
return $null
break
}
#endregion Load the Managed API's DLL
#Write-Host "Performing AutoDiscovery"
#$EWS.AutodiscoverUrl($FromMailbox, { $true })
$ExchangeServer = $ExchangeServers | Get-Random
Write-Host "Building URL for EWS using $ExchangeServer"
$EWS.Url = "https://$( $ExchangeServer ).demo.lab/EWS/Exchange.asmx"
Write-Host "Creating new Email Object"
$Email = New-Object -TypeName Microsoft.Exchange.WebServices.Data.EmailMessage($EWS)
Write-Host "Assigning From Address: $FromMailbox"
$Email.From = $FromMailbox
Write-Host "Adding Recipients:"
$i = 1
ForEach ( $Recipient in $ToMailboxes )
{
Write-Host "`t#$( $i ): $Recipient"
$Email.ToRecipients.Add($Recipient) | Out-Null
$i++
}
Write-Host "Adding Subject" -ForegroundColor DarkCyan
$SubjectWordCount = Get-Random -Minimum 3 -Maximum 10
Write-Host "`tInvoking random word generator..." -ForegroundColor Cyan
$Feed = Invoke-WebRequest -Uri "http://lipsum.com/feed/xml?amount=$SubjectWordCount&start=yes&what=words"
$Email.Subject = ( [xml]( $Feed.Content ) ).feed.lipsum
Write-Host "Adding Body" -ForegroundColor DarkCyan
$BodyParagraphCount = Get-Random -Minimum 1 -Maximum 10
Write-Host "`tInvoking random paragraph generator..." -ForegroundColor Cyan
$Feed = Invoke-WebRequest -Uri "http://lipsum.com/feed/xml?amount=$BodyParagraphCount&start=yes&what=paras"
$Email.Body = ( [xml]( $Feed.Content ) ).feed.lipsum
Write-Host "Adding Attachments"
$AttachmentCount = Get-Random -Minimum 0 -Maximum $AllAttachments.Count
if ( $AttachmentCount -gt 0 )
{
$Attachments = $AllAttachments | Get-Random -Count $AttachmentCount
$i = 1
ForEach ( $Attachment in $Attachments )
{
Write-Host "`t#$( $i ): $( $Attachment.Name )"
$Email.Attachments.AddFileAttachment($Attachment.FullName) | Out-Null
$i++
}
}
else
{
Write-Host "No attachments" -ForegroundColor Yellow
}
Write-Host "Sending Email... " -NoNewline
$Email.SendAndSaveCopy([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::SentItems)
Write-Host "[Message Sent!]" -ForegroundColor Green
$SleepTime = Get-Random -Minimum $MinSleepTime -Maximum $MaxSleepTime
Write-Host "Sleeping for $SleepTime seconds" -ForegroundColor Yellow
Start-Sleep -Seconds $SleepTime
$CurrentMessage++
}
When running it looks something like this:
That’s it. Pretty simple, but it works.