PI Services

Le blog des collaborateurs de PI Services

Interaction Powershell - Exchange Web Services

Introduction

Avec Exchange 2010, pour certains besoins bien spécifiques, il se peut que les cmdlets Powershell soit limitées. Cependant, il existe aussi les Exchanges Web Services. Bien entendu, quand on parle des Exchange Web Services, on pense au C# et à un développement complexe. Cependant, on n'oublie souvent que Powershell permet d'exécuter du C#.
Il sera donc question d'accéder aux EWS via Powershell. Il s'agit surtout d'une introduction car les possibilités de scripting sont infinies. L'exemple mis en œuvre dans cet article montrera comment accéder à un dossier bien spécifique pour le purger suivant les dates de réception des emails. Cela permettra entre autres de voir le langage AQS permettant la recherche d'objets dans une boîte aux lettres Exchange.

Prérequis

Avant toute chose, pour manipuler l'API Exchange Web Services, il est nécessaire d'installer le package correspondant sur le poste qui exécutera le script. Il est trouvable en suivant ce lien : http://www.microsoft.com/en-us/download/details.aspx?id=28952

Attention si vous utilisez, Exchange 2013, il faut prendre cette version :
http://www.microsoft.com/en-us/download/details.aspx?id=35371

Il sera ensuite nécessaire d'ajouter dans chacun des scripts qui sera réalisé la dll permettant d'interagir avec les Web Services. Pour rappel, cela se réalise via la commande Powershell Add-Type :

001
002
003
Add-Type -path "C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll"


AQS ou Advanced Query Syntax:

Le langage AQS permet de réaliser des recherches dans les objets d'une boîte aux lettres Exchange. Il est très simple à prendre en main.

Pour comprendre toutes les possibilités de ce langage voici le lien MSDN dédié :
http://msdn.microsoft.com/en-us/library/ee693615.aspx

Grâce à ce langage il va être possible de rechercher des éléments :
- par type (emails, réunions, notes, contacts, ...)
- par date (réception ou envoi)
- par propriété d'un email (champ from, to, cc, subject, body, ...)

L'exemple suivant permet de rechercher des emails ayant été reçu le 3 Septembre 2013 :
"Kind:email AND Received:03/09/2013"

On remarque l'opérateur AND qui permet de prendre en compte 2 propositions. Il en existe d'autres comme le OU (l'une ou l'autre des propositions) et le NOT (l'inverse d'une proposition).

Script commenté

Il s'agit ici d'un script où l'utilisateur se connecte à une boîte aux lettres sur laquelle il possède des droits et dont les messages du dossier nommé Personnel seront supprimées s'ils datent de plus de 30 jours. Aussi, pour chaque dossier, il affiche la taille de celui-ci en Ko. Cette dernière opération est aussi faisable via la commande EMS Get-MailboxFolderStatistics mais avec cette exemple nous n'aurons pas besoin d'installer ces outils mais seulement l'API EWS beaucoup plus légère.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
#Mailbox à traiter
$MailboxName = 'j.dupont@myenterprise.fr'

# A installer avant : www.microsoft.com/en-us/download/details.aspx?id=28952
try{
    Add-Type -path "C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll"
}catch{

}

#On spécifie la version des web services
$Version = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2
$Service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($version)

#On utilise les credentials avec lesquels on est connecté
$Service.UseDefaultCredentials = $true

#On récupère la configuration Autodiscover pour se connecter à la BAL
$Service.AutodiscoverUrl($MailboxName,{$true})

#On récupère l'ID du dossier
$RootFolderID = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root,$MailboxName)

#On se connecte au dossier via la connexion que l'on a initialisé
$RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($Service,$RootFolderID)

#On limite le nombre de dossier à analyser à 1000 (sinon problème de throttling)
$FolderView = New-Object Microsoft.Exchange.WebServices.Data.FolderView(1000)

#On définit un ensemble de propriété à récupérer en même temps que nos dossiers
$PropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
#On crée une propriété de type taille de dossier
$SizeObject = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(3592,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Long)
#On l'ajouter à notre vue de dossier afin que la taille soit aussi récupérée.
$PropertySet.Add($SizeObject); 
$FolderView.PropertySet = $PropertySet;

#On spécifie qu'on analyse l'intégralité de la hiérarchie
$FolderView.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Deep

#On calcule la date d'il y a 30 jours et on la met au format dd/MM/yyyy
$DateOld = ((Get-Date).AddDays(-30)).ToString("dd/MM/yyyy")

#On récupère tous les dossiers
$Response = $RootFolder.FindFolders($FolderView)
#Pour chaque dossier
ForEach ($Folder in $Response.Folders) {
   
    $FolderSize = $null
    #Si la taille est disponible alors on l'export dans la variable $FolderSize
    if($Folder.TryGetProperty($SizeObject,[ref] $FolderSize)){
        $FolderSizeValue = ([Int64]$FolderSize)/1000 
        #On affiche la taille du dossier
        $Message = "Le dossier " + $Folder.DisplayName + " a une taille de $FolderSizeValue Ko"
        Write-Host $Message
    }else{
        $Message = "Taille du dossier " + $Folder.DisplayName +" introuvable."
        Write-host $Message
    }

    #On compare le display name avec la valeur recherchée
    if($Folder.DisplayName -eq "Personnel"){
        #Si le dossier est bien Personnel alors on récupère tous les mails selon les critères de date définies
        $Items = $Folder.FindItems("Kind:email AND Received:<$DateOld",$ItemView) 
        #Pour chaque email trouvée
        ForEach($Item in $Items){
            #On le supprime définitivement (à décommenter pour que ce soit effectif)
            #$Item.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
        }
    }
}

 

On remarque l’opérateur “<” (inférieur à) dans la requête AQS qui permet de spécifier tout ce qui se trouve avant cette date.

On peut accéder aux dossiers publics, modifier, supprimer, créer, tout type d'objet y compris des dossiers. Il est aussi possible de récupérer différentes informations comme la taille d'un dossier. Il est aussi possible d'analyser les pièces jointes pour supprimer celle dont l'extension est d'un certain type. Il est donc possible d'imaginer plein de scripts comme des tâches planifiées effectuant des traitement sur des boîtes aux lettres.