четверг, 24 января 2013 г.

Использование Exchange EWS для чистки почтовых ящиков

При переходе на архивирование в Exchange появились две проблемы (кроме очевидного отсуствия возможности тереть сообщения из архива, хотя....): удалить заглушки, оставленные системой архивации, и автоматически удалять из архива сообщения старше 5 лет

По поводу заглушек. В Exchange 2007 можно было производить поиск сообщений по их классу, в 2010 и 2013 данную возможность убрали. Задачу можно решить достаточно просто с использованием EWS (просто - если уже знаешь как или делал подобно хотя бы один раз, когда я первый раз искал информацию её было очень мало).

Алгоритм - подключаемся к EWS (код авторизации и имперсонации я убрал, скрипт уже запускается под пользователем с нужными правами - Impersonate), представляемся нужным пользователем. Ищем и перебираем все папки, начиная с верхней, для каждой папки ищем элементы (неудаленные) по заданному критерию и удаляем их.

На сервер предварительно должен быть установлен Exhcange Web Services 2.0 (можно 1.1+, в коде используется 1.2). Код ниже.

param( 
    [Parameter(Mandatory = $true)]
    [string] $Name
)

####################################
# Log actions to file
function log($msg) {
  $date=get-date
  $data="[ "+$date+" ] "+ $msg
  echo $data >> c:\scripts\mail\clean.log
  #write-host $msg
  }

####################################
# Обработать почтовый ящик с email $MailboxName, начиная с папки $TopFolder, применяя фильтр $Filter
function doMailbox() { 
    param (
        [string]$MailboxName,
        [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]$TopFolder,
        $Filter
    )
    log -msg ("Searching folders in Mailbox Name:"+$MailboxName)

    #Меняем пользователя, под которым происходит работа 
    $service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId(
        [Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress,$MailboxName);
    #Number of Items to Get 
    $FpageSize =1000
    $FOffset = 0 
    $MoreFolders =$true

    while ($MoreFolders) {
        #Setup the View to get a limited number of Items at one time 
        $folderView = new-object Microsoft.Exchange.WebServices.Data.FolderView($FpageSize,$FOffset,[Microsoft.Exchange.WebServices.Data.OffsetBasePoint]::Beginning) 
        #поиск во всех вложенных папках
        $folderView.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Deep 
        $folderView.PropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet( 
            [Microsoft.Exchange.WebServices.Data.BasePropertySet]::IdOnly, 
            [Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName, 
            [Microsoft.Exchange.WebServices.Data.FolderSchema]::FolderClass);

        #запрос к серверу для безусловного поиска вложенных папок
        $oFindFolders = $service.FindFolders($TopFolder,$folderView) 
        
        foreach ($folder in $oFindFolders.Folders) {
            log -msg ("Begining to delete Items from folder:"+$folder.DisplayName)

            &{ 
                #обработать текущую папку
                RemoveMbxItem -Folder $folder.Id.UniqueId -Filter $Filter
            } 
            trap [System.Exception] { 
                $IsFailure = $true; 
                log -msg ("Error: " + $_.Exception.Message)
                continue; 
            }
        } 
        

        if ($oFindFolders.MoreAvailable -eq $false) 
            {$MoreFolders = $false}
            else
            {$FOffset += $FpageSize} 
    }

    log -msg ("Finished with Mailbox:"+$MailboxName)
    $service.ImpersonatedUserId = $null 
}

    
#######################################
# Обработать и удалить элементы из указанной папки с заданным фильтром
function RemoveMbxItem() {
    param(
        $folder,
        $Filter
    )
    #Number of Items to Get
    $pageSize =1000
    $Offset = 0
    $MoreItems =$true
    $ItemCount=0
    
    while ($MoreItems) {
        #Setup the View to get a limited number of Items at one time
        $itemView = new-object Microsoft.Exchange.WebServices.Data.ItemView($pageSize,$Offset,[Microsoft.Exchange.WebServices.Data.OffsetBasePoint]::Beginning)
        #изем только неудаленные элементы
        $itemView.Traversal = [Microsoft.Exchange.WebServices.Data.ItemTraversal]::Shallow

        #перечень свойств, возвращяемых при поиске
        $itemView.PropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet( 
                [Microsoft.Exchange.WebServices.Data.BasePropertySet]::IdOnly, 
                [Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::Subject,
                [Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::DateTimeSent,
                [Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::DateTimeReceived,
                [Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::DateTimeCreated,
                [Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::LastModifiedTime,
                [Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::ItemClass);
        #Create the Search Filter.
        $searchFilter = $Filter
        #преобразуем уникальный ID папки в биндинг к папке
        $uniqueId = new-object Microsoft.Exchange.WebServices.Data.FolderId($Folder);
        $oFindItems = $service.FindItems($uniqueId,$SearchFilter,$itemView)
        
        foreach ($Item in $oFindItems.Items){
            log -msg ("Remove EVStub. Subject="+$item.subject+" Item class="+$item.itemclass+" Modified="+$item.LastModifiedTime )
            #помечаем элемент для удаления в дампстер
            $Item.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::SoftDelete)
            }

        if ($oFindItems.MoreAvailable -eq $false) {
            $MoreItems = $false
        } else {
            $Offset += $pageSize
        }
    }
}

####################################
# Excahnge connector
Import-Module activedirectory
# Load EWS Managed API library
Import-Module -Name "C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll"

# Create Exchange Service object
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)

#EWS address
#$service.Url = new-object System.Uri("https://mail.contoso.ru/ews/exchange.asmx")
$service.AutodiscoverUrl("mailadmin@contoso.ru")

# Load Mailboxes
$Users = Get-ADuser -filter {sAMAccountName -eq $name} -Properties mail

#age for old elements
$date=(get-date).addyears(-5).addMonths(-1)


foreach ($user in $Users) {
    #filter EVStubs
    $FilterEA1 = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo(
        [Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::ItemClass, "IPM.Note.EnterpriseVault.Shortcut")
    #filter old messages
    $FilterEA2 = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsLessThan(
        [Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::DateTimeSent, $date)
    #complex filter
    $Filter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection(
        [Microsoft.Exchange.WebServices.Data.LogicalOperator]::or)
    $Filter.add($FilterEA1)
    $Filter.add($FilterEA2)

 #Main mailbox - delete EVStubs
    doMailbox -MailboxName ($user.mail) -TopFolder ([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot)        -Filter $FilterEA1
    #Archive - delete EVStubs and old
    doMailbox -MailboxName ($user.mail) -TopFolder ([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::ArchiveMsgFolderRoot) -Filter $filter
}

Комментариев нет:

Отправить комментарий