Exchange Web Service (EWS) et Powershell : exemple de script

Bonjour,

Aujourd’hui je vous présente un exemple de code Powershell utilisant les types et fonctionnalités de l’Exchange Web Service Managed API (EWS API 1.1)

Le script suivant permet de parcourir un dossier d’email en particulier. Il check si les éléments possèdent un ID personnalisé (qui est une propriété étendue). Dans le cas contraire, il en affecte une (génération d’un GUID)

Voici le code:

$usertoQuery = "EMAILADDRESS"
 
$dllpath = "XXX\Microsoft.Exchange.WebServices.dll"
[void][Reflection.Assembly]::LoadFile($dllpath)
 
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)
 
$service.Credentials = new-object Microsoft.Exchange.WebServices.Data.WebCredentials("LOGIN","PWD","DOMAIN")
$service.Url = new-object Uri("http://URL/EWS/Exchange.asmx");
 
$svFldid = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::SearchFolders,$MailboxName)
$delFldid = [Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete
 
$fvFolderView = new-object Microsoft.Exchange.WebServices.Data.FolderView(1000)
 
$folders = $service.findfolders($svFldid,$fvFolderView)
$ExtendedProp = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition([Microsoft.Exchange.WebServices.Data.DefaultExtendedPropertySet]::PublicStrings, "MyCustomID", [Microsoft.Exchange.WebServices.Data.MapiPropertyType]::String)
$ExtendedProp
$Propset = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties, $ExtendedProp)
 
foreach ($folder in $folders)
{
    if ($folder.displayName -eq "FOLDERNAME_I_WANT_TO_CHECK")
    {
		"We are in the correct folder"
         $fvItemView = new-object Microsoft.Exchange.WebServices.Data.ItemView(10000)
 
		 $items = $service.FindItems($folder.Id,$fvItemView)	
		 #Don't show any result for the next line
		 $service.LoadPropertiesForItems($items, $Propset)
		 foreach ($item in $items)
		 {
			"**Subject** : " 
			$item.Subject
			"**Number of Extended Properties**: " 
			$item.ExtendedProperties.Count		
 
			$a = 0
 
			foreach ($extendedProperty in $item.ExtendedProperties)
			{
				if ($extendedProperty.PropertyDefinition.Name -eq $ExtendedProp.Name)
				{					
					$a = 1
					"Break (Value = " + $extendedProperty.Value + ")"
					break;						
				}		
			}
 
			if ($a -eq 0)
			{			
				$g1 = [Guid]::NewGuid()
				$item.SetExtendedProperty($ExtendedProp, $g1.ToString())
				"Guid = " + $g1
				"ValueGuid added!"
				$item.Update([Microsoft.Exchange.WebServices.Data.ConflictResolutionMode]::AlwaysOverwrite)
				"Item saved"
			}
		 }	 
    }
}

Et voila une base pour maitriser (un peu) la sémantique Powershell et manipuler l’api EWS d’une autre façon!

Microsoft Exchange – EWS: Propriétés personnalisées – Création

Bonjour,

Aujourd’hui, cap sur les propriétés personnalisées avec Exchange Web Service API:

Au delà des propriétés “basiques” telles que Subject, Body, From (…) il est possible d’avoir des propriétés personnalisées sur chaque “ServiceObject”.
EmailMessage étant un ServiceObject, à l’instar de Folder ou encore de Contact, voyons comment jouer avec ces propriétés personnalisées (ou “étendues“):

ExtendedPropertyDefinition extendedPropertyDefinition = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.PublicStrings, "Name Of my property", MapiPropertyType.String);
 
MyMessage.SetExtendedProperty(extendedPropertyDefinition, "ValueOf my property");

La propriété personnalisée peut avoir différents types : string, integer, booleen, date.. (énuméré dans MapiPropertyType)

Pour sauver les modifications apportées (si toutefois c’est un élément récupéré et non une création), utilisez la méthode suivante :

MyMessage.Update(ConflictResolutionMode.AlwaysOverwrite);

Dans le cas d’un Dossier, c’est la même méthode mais sans paramètre qui sera appelée.

Pour récupérer les valeurs des propriétés personnalisées, ou encore plus complexe: récupérer toutes les propriétés d’un email, je vous suggère l’article suivant

Exchange Web Service (EWS) : impersonation (administrateur)

Bonjour,

Aujourd’hui un court post mettant en avant la pratique de l’impersonation (le super utilisateur)

Avec cela, un super utilisateur, identifié avec la méthode classique de connexion, pourra parcourir et interagir avec toutes les boites emails sur serveur Exchange, sans se préoccuper des mots de passe.

Pour l’implémentation:

D’abord, sur la machine possédant le serveur Exchange ouvrir Exchange Management Shell et tapez ceci:

New-ManagementRoleAssignment –Name AgentImpersonationRole –Role ApplicationImpersonation –User "Votre_Nom_D_Utilisateur_Ici"

Voila, votre compte est désormais un super compte!

Au niveau de l’API, ça se passe comme cela:

//Connection avec l'API:
m_service = new ExchangeService(ExchangeVersion.Exchange2010_SP1);
//sUser est le super utilisateur précédement créé (Votre_Nom_D_Utilisateur_Ici)
m_service.Credentials = new WebCredentials(sUser, sPwd, sDomain);
m_service.Url = new Uri("http://XXXX/EWS/Exchange.asmx");
 
//Spécification de la boite email à gérer:
m_service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "BoiteEmailAmodifier");
//Action sur cette boite email:
Folder newFolder = new Folder(m_service);
newFolder.DisplayName = "ImpersonatedTestFolder";
newFolder.Save(WellKnownFolderName.Inbox);

Voila, vous avez créé un dossier sur une boite email différente de la votre en jouant des droits de super utilisateur. Vous pouvez ainsi faire des opérations de groupes sur des comptes emails sans vous préoccuper des passwords.

Microsoft Exchange – EWS: Propriétés personnalisées – Récupération et suppression

Dans le cas où votre application dépend beaucoup des propriétés personnalisées apposées sur vos précieux emails, vous vous êtes peut être déjà posé la question : Comment suis-je sensé les récupérer… toutes ?

Pour récupérer la valeur d’un champ personnalisé d’un email il faut… savoir que ce champ existe ! Impossible donc de demander à l’API « renvoi moi toutes les propriétés perso de ce message et leur valeur »

Impossible ? Pas vraiment, en contournant l’API et en passant par le webservice, nous pouvons utiliser la méthode « ExportItem » qui permet de récupérer des propriétés inédites.

Pour cela, il suffit de récupérer l’uniqueId de l’email et de le passer dans une instance de ExportItemsType, puis d’appeler la méthode ExportItems via le web service (et pas l’API !)

(Rappel : configurer le web service)

string sItemID = item.Id.UniqueId;
 
ExportItemsType exExportItems = new ExportItemsType();
 
exExportItems.ItemIds = new ItemIdType[2];
 
exExportItems.ItemIds[0] = new ItemIdType();
 
exExportItems.ItemIds[0].Id = sItemID;
 
ExportItemsResponseType exResponse = m_exchangeServerBinding.ExportItems(exExportItems);
 
ExportItemsResponseMessageType rmResponse = (ExportItemsResponseMessageType)exResponse.ResponseMessages.Items[0];
 
Byte[] messageBytes = rmResponse.Data;
 
ProcessFile(messageBytes);
 
private void ProcessFile(String fnFileName)
 
{
 
Byte[] fsfileBytes = ReadByteArrayFromFile(fnFileName);
 
EWSFTParser ipItemParser = new EWSFTParser();
 
MapiItem mpMapiItem = ipItemParser.ParseItem(fsfileBytes);
 
ViewEmailProperties fEmailProperties = new ViewEmailProperties(mpMapiItem);
 
fEmailProperties.ShowDialog();
 
}

Le EWSFTParser ainsi qu’un projet Visual studio 2010 peuvent être récupérés ici (merci à Glen Scales, MVP microsoft)

J’ai fait fonctionner son parser/browser en moins de 5minutes donc vous devriez vous en sortir aussi.

Supprimer une propriété personnalisée

Pour supprimer la propriété personnalisée, utilisez la méthode RemoveExtendedProperty

ExtendedPropertyDefinition extendedPropertyDefinition =    new ExtendedPropertyDefinition(DefaultExtendedPropertySet.PublicStrings, sFieldToRemove, MapiPropertyType.String);
 
if (item.RemoveExtendedProperty(extendedPropertyDefinition))
 
{
 
item.Update(ConflictResolutionMode.AlwaysOverwrite);
 
AddText("Custom property removed!");
 
return;
 
}

Microsoft Exchange – EWS: Ecrire un nouvel email avec toutes les options

Après avoir vu comment récupérer les emails, voyons comment créer un nouvel email et l’envoyer à un compte email Exchange.

Création d’un nouveau message et envoi

string sDestinataire = m_edDestinataire.Text;
 
/* Création d'email et envoi */
 
EmailMessage message = new EmailMessage(m_service);
 
message.Subject = m_edSubject.Text;
 
message.Body = m_rtbBody.Text;
 
message.Body.BodyType = BodyType.HTML;
 
message.Importance = Importance.Normal;
 
//Ajout d’une propriété personnalisée appelé “MaProprietePerso” avec pour valeur //« Mavaleur »
 
string sPropertyName = “MaProprietePerso”;
 
ExtendedPropertyDefinition extendedPropertyDefinition =
 
new ExtendedPropertyDefinition(DefaultExtendedPropertySet.PublicStrings, sPropertyName, MapiPropertyType.String);
 
message.SetExtendedProperty(extendedPropertyDefinition, “MaValeur”);
 
//Avec ou sans pièces jointes:
 
if (sFilename != string.Empty)
 
message.Attachments.AddFileAttachment(sFilename);
 
//Destinataire :
 
message.ToRecipients.Add(sDestinataire);
 
//Accusé de reception :
 
if (m_ckDelivery.Checked)
 
message.IsDeliveryReceiptRequested = true;
 
//Sauvegarde et envoi de l’email :
 
message.SendAndSaveCopy();

Ce code vous permet de créer un nouveau message et de spécifier : son titre(sujet), le corps du message, son importance, des propriétés personnalisées, des pièces jointes, des destinataires et un accusé de réception.

Envoi différé

Un point rarement mentionné porte sur l’envoi différé, pour utiliser cette fonctionnalité, ajouter la classe suivante :

public static class ExchangeExtensions
 
{
 
public static ExtendedPropertyDefinition PR_DEFERRED_SEND_TIME = new ExtendedPropertyDefinition(16367, MapiPropertyType.SystemTime);
 
public static ExtendedPropertyDefinition PR_DEFERRED_DELIVERY_TIME = new ExtendedPropertyDefinition(15, MapiPropertyType.SystemTime);
 
/// 
 
/// Sets Delayed Delivery
 
///
 
///
<span> </span>
 
///
<span> </span>Do Not Send Before This Date and Time
 
public static void SetDelayedDelivery(Microsoft.Exchange.WebServices.Data.EmailMessage email, DateTime deliveryDate)
 
{
 
string ut = deliveryDate.ToUniversalTime().ToString();
 
email.SetExtendedProperty(PR_DEFERRED_SEND_TIME, ut);
 
email.SetExtendedProperty(PR_DEFERRED_DELIVERY_TIME, ut);
 
}
 
}

Et sur le message, avant de l’envoyer :

ExchangeExtensions.SetDelayedDelivery(message, dateTimePicker1.Value);
 
//Sauvegarde et envoi de l’email :
 
message.SendAndSaveCopy();

Vous savez désormais récupérer les messages stockées sur le serveur Exchange et écrire de nouveaux emails en spécifiant de nombreuses options différentes.