Рассмотрим способ получения статистики по письму из массовой рассылки, внутри вашей компании, с помощью EWS
-
Сначала нужно получить библиотеку EWS
Удобно скачать библиотеку из репозитория Powershell.
Но для этого может потребоваться сначала подключить провайдер пакетов NuGet:Register-PackageSource -Name MyNuGet -Location https://www.nuget.org/api/v2 -ProviderName NuGet Установить-PackageProvider -Name NuGet-Force
Далее поиск и установка пакета с библиотекой:
Find-Package Exchange.WebServices.Managed.Api | Install-Package
-
После установки нужно указать в следующем скрипте путь к библиотеке, для переменной $dllpath
#Useage Examples: #$AllUserMailboxs = Get-mailbox -RecipientTypeDetails UserMailbox -ResultSize unlimited #foreach ($Mailbox in $AllUserMailboxs) { #Write-host "Checking:"$mailbox.Windows #.\ReadMsgstatus.ps1 -userName "Admin@xyz.com" -password "AdminPass" ` #-mailbox "USERPrimarySMTP@xyz.com" -subject "Test Msg" -sender "sender@xzy.com" -userName 'AdminUserName' -SentDate "04/30/21"} param ( $sender, $subject, $mailbox, $userName, $SentDate ) $SQ = "Received:$SentDate AND From:`"$Sender`" AND Subject:`"$subject`"" $report=@() $itemsView=1000 $uri=[system.URI] "https://mail.DomainName.ru/EWS/Exchange.asmx" $dllpath = "C:\Program Files\PackageManagement\NuGet\Packages\Exchange.WebServices.Managed.Api.2.2.1.2\lib\net35\Microsoft.Exchange.WebServices.dll" Import-Module $dllpath $AccountWithImpersonationRights=$userName # Учетка админа под которой будем работать. У нее должны быть полномочия управлять целевым ящиком $MailboxToImpersonate=$mailbox # Ящик в котором мы хотим производить действия. ## Set Exchange Version $ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2016 $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion) $service.url = $uri $service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId ([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SMTPAddress,$MailboxToImpersonate); $Folderid = new-object Microsoft.Exchange.WebServices.Data.FolderId ([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$MailboxToImpersonate) $view = New-Object Microsoft.Exchange.WebServices.Data.ItemView -ArgumentList $ItemsView $propertyset = New-Object Microsoft.Exchange.WebServices.Data.PropertySet ([Microsoft.Exchange.WebServices.Data.BasePropertySet]::IdOnly ) $view.PropertySet = $propertyset $items = $service.FindItems($Folderid,$SQ,$view) if ($items -ne $null) { # Если во входящих найдены письма - добавляются в отчет $emailProps = New-Object Microsoft.Exchange.WebServices.Data.PropertySet ([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties) $mail = [Microsoft.Exchange.WebServices.Data.EmailMessage]::Bind($service, $items.ID, $emailProps) $datam=$mail | Select @{N="Sender";E={$_.Sender.Address}},@{N="USER";E={$mailbox}},Isread,Subject,DateTimeReceived,@{n="Folder";e={"Inbox"}} $report+=$datam #| ?{ $_.DateTimeReceived -match "$SentDate" } } Else { # Иначе строится структура папок ящика и ищет в них Write-Host "Mail Not Found in Inbox Folder for:"$mailbox -f Yellow -NoNewline Write-Host " Checking Deleted Item Folder" $MailboxRootid= new-object Microsoft.Exchange.WebServices.Data.FolderId ([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot,$MailboxToImpersonate) $MailboxRoot=[Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$MailboxRootid) $FolderList = new-object Microsoft.Exchange.WebServices.Data.FolderView(100) $FolderList.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Deep $findFolderResults = $MailboxRoot.FindFolders($FolderList) $allFolders = $findFolderResults | ? {$_.DisplayName -eq "Deleted Items" -or $_.DisplayName -eq "Удаленные"} $count = $allFolders.Count $DI = $allFolders # Цикл который перебирает все найденные папки с удаленными, пока не будет найдено письмо $Folderids=$DI.ID foreach($Folderid in $Folderids){ $items = $service.FindItems($Folderid,$SQ,$view) if($items -ne $null){break} } if ($items.count -eq $null) { write-host "Item not found in the Deleted item folder, Now Checking in the Recover Deleted items Folder" $itemsView=90000 $view = New-Object Microsoft.Exchange.WebServices.Data.ItemView -ArgumentList $ItemsView $propertyset = New-Object Microsoft.Exchange.WebServices.Data.PropertySet ([Microsoft.Exchange.WebServices.Data.BasePropertySet]::IdOnly) $view.PropertySet = $propertyset $MailboxRootid= new-object Microsoft.Exchange.WebServices.Data.FolderId ` ([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Recoverableitemsroot,$MailboxToImpersonate) $MailboxRoot=[Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$MailboxRootid) $FolderList = new-object Microsoft.Exchange.WebServices.Data.FolderView(100) $FolderList.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Deep $findFolderResults = $MailboxRoot.FindFolders($FolderList) $Deletions = $findFolderResults | ? {$_.DisplayName -eq "Deletions"} $Folderid=$Deletions.ID $items=$service.FindItems($Folderid,$SQ,$view) if ($items.count -eq $null){ Write-Host "Item Not Found in the Dumpsters." Write-host "Checking in other folders" $MailboxRootid= new-object Microsoft.Exchange.WebServices.Data.FolderId ` ([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot,$MailboxToImpersonate) $MailboxRoot=[Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$MailboxRootid) $FolderList = new-object Microsoft.Exchange.WebServices.Data.FolderView(100) $FolderList.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Deep $findFolderResults = $MailboxRoot.FindFolders($FolderList) $allFolders=$findFolderResults | ? {$_.FolderClass -eq "IPF.Note"} | select ID,Displayname $allFolders=$allFolders | ? { ` $_.DisplayName -notlike "Inbox" -and ` $_.DisplayName -notlike "Deleted Items" -and ` $_.DisplayName -notlike "Drafts" -and ` $_.DisplayName -notlike "Sent Items" -and ` $_.DisplayName -notlike "Outbox"} $allfoldersCount=$allfolders.id.count $counter=0 $itemFound=$false if ($allFolders) { do { Write-Host "Checking Email Item in Folder:"$allfolders[$counter].DisplayName $folderID=$allfolders[$counter].ID $items =$service.FindItems($Folderid,$SQ,$view) if($items.count -eq $null) {Write-Host "Item Was Not Found in Folder:"$allfolders[$counter].DisplayName -ForegroundColor Yellow} else{ Write-Host "Item Was Found in Folder:"$allfolders[$counter].DisplayName -ForegroundColor Green $emailProps = New-Object Microsoft.Exchange.WebServices.Data.PropertySet ([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties) $mail = [Microsoft.Exchange.WebServices.Data.EmailMessage]::Bind($service, $items.ID, $emailProps) $data=$mail | Select @{N="Sender";E={$_.Sender.Address}},@{N="USER";E={$mailbox}},Isread,Subject,DateTimeReceived,@{n="Folder";e={$allfolders[$counter].DisplayName}} $report+=$data $itemFound=$true} $counter++ } until ($counter -eq $allfoldersCount -or $itemFound -eq $true) }} else{ $emailProps = New-Object Microsoft.Exchange.WebServices.Data.PropertySet ([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties) $mail = [Microsoft.Exchange.WebServices.Data.EmailMessage]::Bind($service, $items.ID, $emailProps) $data=$mail | Select @{N="Sender";E={$_.Sender.Address}},@{N="USER";E={$mailbox}},Isread,Subject,DateTimeReceived,@{n="Folder";e={"Deletions"}} $report+=$data } } else{ $emailProps = New-Object Microsoft.Exchange.WebServices.Data.PropertySet ([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties) $mail = [Microsoft.Exchange.WebServices.Data.EmailMessage]::Bind($service, $items.ID, $emailProps) $data=$mail | Select @{N="Sender";E={$_.Sender.Address}},@{N="USER";E={$mailbox}},Isread,Subject,DateTimeReceived,@{n="Folder";e={$DI.DisplayName}} $report+=$data } } $report
Скрипт представляет собой немного подправленную версию скрипта от Sunil Chauhan из его блога, где есть еще много примеров работы с EWS.
- Вызов скрипта выполняем следующим образом
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn $mailboxes = (get-mailbox -resultsize unlimited -RecipientTypeDetails UserMailbox | select -ExpandProperty WindowsEmailAddress) | select -ExpandProperty Address $sender = 'email@DomainName.ru' $subject = 'Ежедневная рассылка' $SentDate = "04/30/21" $result = foreach($mailbox in $mailboxes ){ C:\ReadMsgstatus.ps1 -sender $sender -subject $subject -mailbox $mailbox -userName 'AdminUserName' -SentDate $SentDate } Clear-Variable DeletedReadCount,InboxReadCount,DeletedUnreadCount,InboxUnreadCount # Прочитанные в удаленных $result | ? { $_.IsRead } | ? { $_.Folder -eq "Удаленные" -or $_.Folder -match "Delet" } | Group-Object Folder | ForEach-Object {$DeletedReadCount += $_.Count} # Прочитанные во входящих $result | ? { $_.IsRead } | ? { $_.Folder -ne "Удаленные" -or $_.Folder -notmatch "Delet" } | Group-Object Folder | ForEach-Object {$InboxReadCount += $_.Count} # Непрочитанные в удаленных $result | ? { !$_.IsRead } | ? { $_.Folder -eq "Удаленные" -or $_.Folder -match "Delet" } | Group-Object Folder | ForEach-Object {$DeletedUnreadCount += $_.Count} # Непрочитанные во входящих $result | ? { !$_.IsRead } | ? { $_.Folder -ne "Удаленные" -or $_.Folder -notmatch "Delet" } | Group-Object Folder | ForEach-Object {$InboxUnreadCount += $_.Count} $List = New-Object 'System.Collections.Generic.List[System.Object]' $List.add( ( @{'Дата отправки'=$SentDate;'Тема письма'=$subject;'Прочитанные во входящих'=$InboxReadCount;'Непрочитанные во входящих'=$InboxUnreadCount;'Прочитанные в удаленных'=$DeletedReadCount;'Непрочитанные в удаленных'=$DeletedUnreadCount} | % { New-Object object | Add-Member -NotePropertyMembers $_ -PassThru }) ) $List | ft 'Тема письма','Дата отправки','Прочитанные во входящих','Прочитанные в удаленных','Непрочитанные во входящих','Непрочитанные в удаленных'
-
Для того что бы скрипт работал и попадал в чужие ящики от лица административной учетной записи нужно настроить имперсонализацию:
New-ManagementRoleAssignment –Name "EWS_impersonation" –Role "ApplicationImpersonation" –User "AdminUserName"
-
Для того что бы данный скрипт мог работать с самого сервера Exchange нужно внести изменение в реестр
New-ItemProperty HKLM:\System\CurrentControlSet\Control\Lsa -Name "DisableLoopbackCheck" -Value "1" –PropertyType dword
В противном случае мы будем получать ошибку авторизации 401