Для тестирования работоспособности почтовой системы была создана пара почтовых ящиков, один из которых находится во внешней сети, и настроено правило, чтобы письмо, отправленное с внутреннего ящика на внешний, автоматически возвращалось на внутренний ящик. Осталось только сделать скрипт на Powershell, который бы периодически отправлял тестовое письмо, и проверял, вернулось ли оно обратно.
В скрипте использованы найденные в интернете функции получения почты через POP3, а отправка осуществляется через командлет Send-MailMessage. В случае, если отправленное письмо не возвращается обратно, скрипт отправляет письмо на адреса администраторов (заданы в переменной addr_to).
Скрипт выкладывается “как есть”, за исключением того, что имена серверов, доменов, и пользователей изменены на тестовые. Имена почтовых серверов, логин и пароль “зашиты” в теле функции NewPOP3 и в основном скрипте – не забудьте поменять. У меня возникала мысль немного дописать скрипт, чтобы он делал несколько попыток получения письма, но как это обычно бывает, руки не дошли. Скрипт работал в организации примерно год, после чего его функциональность перенесли на Microsoft System Center 2012 Orchestrator. Правило в Orchestrator точно так же тестировало работу почты, и в случае проблемы создавало алерт в SCOM, чего скрипт не делает, но это уже совсем другая история.
{
$Encoder=New-Object System.Text.ASCIIEncoding
[byte[]]$Buffer=(,0)*1024
$Buffer=$Encoder.GetBytes($Msg)
$NetStream=$this.GetStream()
$NetStream.Write($Buffer, 0, $Buffer.Length)
}
function Response ()
{
$Encoder=New-Object System.Text.ASCIIEncoding
[byte[]]$Buffer=(,0)*1024
$NetStream=$this.GetStream()
[int]$Count=0
While($true)
{
[byte[]]$buff=(,0)*2
$NotEnd=$NetStream.Read($buff, 0, 1)
if ($NotEnd)
{
if (($buff -eq 10) -and ($Buffer[0] -eq 0)) {continue}
$Buffer[$Count]=$buff[0]
$Count++
if ($buff[0] -eq 10) {break}
}
else {break}
}
return $Encoder.GetString($Buffer, 0, $Count)
}
function NewMessage ()
{
$Message=New-Object -Type PSobject
Add-Member -in $Message NoteProperty Number $([long]0) -Force
Add-Member -in $Message NoteProperty Size $([long]0) -Force
Add-Member -in $Message NoteProperty Recieved $([bool]0) -Force
Add-Member -in $Message NoteProperty Content $([string]::Empty) -Force
return $Message
}
function NewPOP3 ()
{
$ConnectP=
{
$Server='srv-mail04.test.local'
$User='mailtest@test.local'
$Password='P@ssw0rd'
$Res=''
$POP3.Connect($Server,110)
$Res=Response
if (! $Res.StartsWith('+OK')) {throw $Res}
Send "USER $User`r`n"
$Res=Response
if (! $Res.StartsWith('+OK')) {throw $Res}
Send "PASS $Password`r`n"
$Res=Response
if (! $Res.StartsWith('+OK')) {throw $Res}
}
$DisconnectP=
{
$Res=''
Send "QUIT`r`n"
$Res=Response
if (! $Res.StartsWith('+OK')) {throw $Res}
}
$GetList=
{
$Res=''
$List=@()
Send "LIST`r`n"
$Res=Response
if (! $Res.StartsWith('+OK')) {throw "Error"}
While ($true)
{
$Res=Response
if ($Res -eq ".`r`n") {return $List}
else
{
$Message=NewMessage
[string[]]$Value=$Res.Split(" ")
$Message.Number=[int]$Value[0]
$Message.Size=[int]$Value[1]
$Message.Recieved=$false
$List+=$Message
$Message=$null
continue
}
}
}
$Retrieve=
{
param ($Msg)
$Res=''
$Message=NewMessage
$Message.Size=$Msg.Size
$Message.Number=$Msg.Number
Send "RETR $($Msg.Number)`r`n"
$Res=Response
if (! $Res.StartsWith('+OK')) {throw $Res}
$Message.Recieved=$true
while ($true)
{
$Res=Response
if ($Res -eq ".`r`n") {break}
else {$Message.Content+=$Res}
}
return $Message
}
$Delete=
{
param ($Msg)
$Res=''
$Message=NewMessage
$Message.Size=$Msg.Size
$Message.Number=$Msg.Number
Send "DELE $($Msg.Number)`r`n"
$Res=Response
if (! $Res.StartsWith('+OK')) {throw $Res}
}
[PSObject]$TCPClient=New-Object System.Net.Sockets.TcpClient
Add-Member -in $TCPClient ScriptMethod ConnectP $ConnectP
Add-Member -in $TCPClient ScriptMethod DisconnectP $DisconnectP
Add-Member -in $TCPClient ScriptMethod GetList $GetList
Add-Member -in $TCPClient ScriptMethod Retrieve $Retrieve
Add-Member -in $TCPClient ScriptMethod Delete $Delete
return $TCPClient
}
cls
$Result=@()
# интервал ожидания прохождения письма после его отправки
$delay = 15
# кому отправлять письма:
$addr_to = "Admin1@test.local", "Admin2@test.local"
# отправка тестового сообщения
write-host "Отправляем письмо..."
$date = Get-Date
$subject = "Test " + $date
$body = "Тестирование почты " + $date
Send-MailMessage -from mailtest@test.local -to mailtest@internetmail.ru -Subject $subject -Body $body -smtpserver srv-mail01.test.local -encoding ([System.TExt.Encoding]::UTF8)
if($?)
{
write-host "Письмо отправлено!"
# подождать...
write-host "Ждём 15 секунд..."
sleep($delay)
write-host "Получаем почту..."
# получить список писем
$POP3=NewPOP3
trap {$_;$POP3.Close();exit} $POP3.ConnectP()
trap {$_;$POP3.close();exit} $MessageList=$POP3.GetList()
if ($MessageList.Count -eq 0)
{
# если в ящике 0 сообщений - почта не работает
Write-Host "В ящике нет писем. Почта не работает!"
$body = "Почта не работает`n" + $date + "`n`nСообщение, отправленное на адрес mailtest@internetmail.ru, не вернулось на адрес mailtest@test.local.`n`n-- `nЭто тест. Меня видно?"
Send-MailMessage -from mailtest@test.local -to $addr_to -Subject "Тестирование почты" -Body $body -smtpserver srv-mail01.test.local -encoding ([System.TExt.Encoding]::UTF8)
}
else
{
Write-Host "Почта работает"
# удаляем письма
Write-Host "Удаляем письма"
foreach ($Msg in $MessageList)
{
# trap {$_;$POP3.close();exit} $Result+=($POP3.Retrieve($Msg))
trap {$_;$POP3.close();exit} $Result+=($POP3.Delete($Msg))
}
}
$POP3.DisconnectP()
$POP3.Close()
}
else
{
write-host "Ошибка отправки письма!"
$body = "Сбой тестирования почты`n" + $date + "`n`nНе удалось отправить сообщение на адрес mailtest@internet.ru.`n`n-- `nЭто тест. Меня видно?"
Send-MailMessage -from mailtest@test.local -to $addr_to -Subject "Тестирование почты" -Body $body -smtpserver srv-mail01.test.local -encoding ([System.TExt.Encoding]::UTF8)
}