This monitors external mail relays, tracks the round trip time of emails to the relay and back, and writes event log messages if the messages do not return in the configured time interval, if you want to use SCOM to alert on congestion or failures.
I'm considering using a started task to stop it and re-start it within a maintenance window, but I still need to figure out the best way to insure that it gets restarted if the server re-boots, and that only one instance of it runs at a time.
If anybody sees something that could be done better, let me know.
$check_interval = 5
$from_addr = ""
$to_addr = ""
$relays = "smtp1.relaydomain.com","smtp2.relaydomain.com"
$hubservers = "",""
$edgeservers = @{"" = "Edge1";"," = "Edge2"}
$headings= '"Timestamp","Source","Relay","Edge_Recv","Hub_Recv","Trip_Time_seconds","Msg_Subj"'
$outfile = $(get-date).tooadate().tostring() + "_mtr.csv"
ac $outfile $headings
$script_start = get-date
#Create event log source and log start event in the application event log
if (!([System.Diagnostics.EventLog]::SourceExists("Mail_Monitor"))){[system.diagnostics.eventlog]::createeventsource("Mail_Monitor","Application")}
$app_log = new-object system.diagnostics.eventlog ("Application",".")
$app_log.source = "Mail_Monitor"
$app_log.writeentry("Mail Monitor script started.","Information",10220)
$sent = @{}
function sendemail {
#### Send email
foreach ($relay in $relays){
$from = "$from_addr"
$to = "$to_addr"
$subj = $subj_ts + $relay
$body = get-date | out-string
$SmtpClient = new-object system.net.mail.smtpClient
$SmtpClient.Host = $relay
$mailmessage = New-Object system.net.mail.mailmessage
$mailmessage.from = ($from)
$mailmessage.To.add($to)
$mailmessage.Subject = $subj
$mailmessage.Body = $body
$smtpclient.Send($mailmessage)
if (!($?)) {$app_log.writeentry("Error sending email $($subj) to $($relay) ","Warning",10222)}
else {$sent.add($subj,$(get-date).tostring())}
}
}
while ($true){
$sentby = [environment]::machinename
$subj_ts = $(get-date).tooadate().tostring() + " Sent by " + $sentby + " To relay "
sendemail
$log_start = $(get-date).tostring()
sleep -seconds $($check_interval * 60)
$log_end = $(get-date).tostring()
$msgtrk = @()
$msg_returned = 0
foreach ($hubserver in $hubservers){
$msgtrk += get-messagetrackinglog -Sender $from_addr -Recipients $to_addr -Server $hubserver -EventID "RECEIVE" --Start $log_start -End $log_end
}
if ($msgtrk.count -ge 1){
$msgtrk = $msgtrk | sort timestamp
foreach ($msg in $msgtrk) {
if ($sent[$msg.messagesubject] -and $msg.source -eq "SMTP"){
$msg.messagesubject -match "^(\d{5}\.\d{1,10}?)\sSent\sby\s(.+)\sTo\srelay\s(.+)" > $nul
$recvhost = $msg.serverhostname
$recvedge = $msg.clientip
$sent_ts = $matches[1]
$mailrelay = $matches[3]
$source = $matches[2]
$trip_time = [timespan]::fromdays($msg.timestamp.tooadate() - $sent_ts)}
$sent_time = [datetime]::fromoadate($sent_ts)
$sent.remove($msg.messagesubject)
$event_text = "Email round trip time for $mailrelay at $sent_time is $($trip_time.totalseconds) seconds."
if ($trip_time.totalminutes -lt $check_interval){$app_log.writeentry($event_text,"Information",10221)}
if ($trip_time.totalminutes -ge $check_interval){$app_log.writeentry("$event_text","Warning",10221)}
$outstr = $msg.timestamp.tostring() + "," + $source + "," + $mailrelay + "," + $edgeservers[$recvedge] + "," + $recvhost + "," + $($trip_time.totalseconds)+ "," + $msg.messagesubject
ac $outfile $outstr
}
}
if ($sent.count -ne 0) {$app_log.writeentry("External email checks are overdue. `n $($sent) ","Warning",10222)}
if ($sent.count -eq 0) {$app_log.writeentry("All external mail checks have been returned. ","Information",10222)}
}