5 Lesser Known Operations in Exchange Web Services on Exchange 2013

Editor’s note: The following post was written by Exchange Server MVP Glen Scales

 5 new lesser known operations in Exchange Web Services on Exchange 2013 and how to use them

 

In this blog post I’m going to look at 5 of the lesser known new Exchange Web Services Operations in Exchange 2013. As with most of the new features in 2013 these new operations build on top of the EWS foundation from 2007 and 2010 and allows the easier programmatic manipulation of the Mailbox data.

1. Getting the User Photo from Exchange via EWS

EWS in 2013 now has two methods you can use to Get User photos, there is a normal SOAP based EWS operation called GetUserPhoto and there is also a REST-based end point. The REST based operation can be useful for non EWS applications where you just want to make use of the user Photo. To use this REST-based end point to access the photo you just need the SMTP Address of the user and the size of the user photo you want. The sizes that can requested are

Size Code

Notes

HR48x48

If you request HR48x48 then the Active Directory thumbnail is returned

HR64x64

HR96x96

HR120x120

HR240x240

HR360x360

HR432x432

HR504x504

HR648x648

If you request a size that is not available the largest available size will be returned if no picture is available the active directory thumbnail gets returned.

Managed API Sample – While there are no methods in the EWS Managed API to access the GetUserPhoto operation you can still use the Autodiscover Class to find the ExternalPhotoURL and then use any of the regualr.NET Web Request classes such as the WebClient Class to access the REST endpoint. The following is a PowerShell sample that shows how to do this

 

 

$MailboxName="fsmith@domain.onmicrosoft.com"

$PhotoSize="HR64x64"

 

Add-Type -Path"C:\Program Files\Microsoft\Exchange\Web Services\2.0\Microsoft.Exchange.WebServices.dll"

 

functionAutoDiscoverPhotoURL{

       param (

       $EmailAddress="$( throw 'Email is a mandatory Parameter' )",

                     $Credentials="$( throw 'Credentials is a mandatory Parameter' )"

              )

       process{

              $version= [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013

              $adService=New-Object

Microsoft.Exchange.WebServices.Autodiscover.AutodiscoverService($version);

              #This Example does an Autodiscover against Exchange Online

             $uri=[system.URI] ("https://autodiscover-

s.outlook.com/autodiscover/autodiscover.svc")

              $adService.Url =$uri 

              $creds=New-Object

System.Net.NetworkCredential($Credentials.UserName.ToString(),$Credentials.GetNetworkCredentia

l().password.ToString())

             $adService.Credentials=$creds

             $adService.EnableScpLookup=$false;

              $adService.RedirectionUrlValidationCallback= {$true}

              $adService.PreAuthenticate=$true;

             $UserSettings=new-object

Microsoft.Exchange.WebServices.Autodiscover.UserSettingName[] 1

              $UserSettings[0] =

[Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::ExternalPhotosUrl

              $adResponse=$adService.GetUserSettings($MailboxName, $UserSettings)

              $PhotoURI=

$adResponse.Settings[[Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::ExternalPh

otosUrl]

              return$PhotoURI.ToString()

       }

}

#Example Use

$pscreds= (Get-Credential)

$PhotoURL=AutoDiscoverPhotoURL-EmailAddress$MailboxName -Credentials $pscreds

$PhotoURL=$PhotoURL+"/GetUserPhoto?email="+$MailboxName+"&size="+$PhotoSize;

$wbClient=new-objectSystem.Net.WebClient

$wbClient.Credentials=New-ObjectSystem.Net.NetworkCredential($pscreds.UserName.ToString(),$pscreds.GetNetworkCredential().password.ToString())

#Download photo to a file

$wbClient.DownloadFile($PhotoURL,"c:\Temp\UsrPhoto.jpg");

#Get photo as a ByteArray

$photoBytes=$wbClient.DownloadData($PhotoURL);

 

2. – How to Archive an Item using the ArchiveItem Operation in EWS

Personal Archives is a feature that was introduced in Exchange 2010 and again improved on in Exchange 2013. The ArchiveItem Operation is aimed at giving you the ability to move items from your Primary Mailbox to your Personal Archive. For example this operation can be used to selectively Archive Messages from the Inbox folder based on a particular Search criteria. The following sample will Archive messages that are older than 1 year to the Archive Store while maintaining the folder hierarchy.

 

$queryTime= (Get-Date).AddYears(-1)

$AQSString= "System.Message.DateReceived:<"+$queryTime.ToString("MM/dd/yyyy")

# Bind to the Inbox Folder

$folderid=new-objectMicrosoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$MailboxName)

$Inbox=[Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)

$ivItemView= New-ObjectMicrosoft.Exchange.WebServices.Data.ItemView(1000)

$fiItems=$null

$type=("System.Collections.Generic.List"+'`'+"1")-as"Type"

$type=$type.MakeGenericType("Microsoft.Exchange.WebServices.Data.ItemId"-as"Type")

$archiveItems= [Activator]::CreateInstance($type)

do{

    $fiItems=$service.FindItems($Inbox.Id,$AQSString,$ivItemView)

    #[Void]$service.LoadPropertiesForItems($fiItems,$psPropset)

    foreach($Itemin$fiItems.Items){

              $archiveItems.Add($Item.Id)

       }

   

    $ivItemView.Offset+=$fiItems.Items.Count

}while($fiItems.MoreAvailable-eq$true)

$type= ("System.Collections.Generic.List"+'`'+"1") -as"Type"

$type=$type.MakeGenericType("Microsoft.Exchange.WebServices.Data.ItemId"-as"Type")

$batchArchive= [Activator]::CreateInstance($type)

foreach($itItemIDin$archiveItems){

       $batchArchive.add($itItemID)

      if($batchArchive.Count-eq 100){

       $service.ArchiveItems($batchArchive,[Microsoft.Exchange.WebServices.Data.WellKnownFold

erName]::Inbox)

              $batchArchive.clear()

       }

}

if($batchArchive.Count-gt 0){

       $service.ArchiveItems($batchArchive,[Microsoft.Exchange.WebServices.Data.WellKnownFold

erName]::Inbox)

      $batchArchive.clear()

}

 

3. Mark all the messages in a folder Read using the MarkAllAsRead Operation in EWS

  Everybody knows the pain of having to mark a lot of messages read after coming back from a holiday. This new operation in EWS makes it easy to do this for all messages within a particular folder (In previous versions you would have had to find the messages that where unread and then modify each message individually). In the EWS Managed API to use this operation you can take advantage of two new methods that have been added to the folder class MarkAllItemsAsRead and MarkAllItemsAsUnread. For example here is how you can mark all the Unread Messages in the Inbox folder as Read (the Boolean parameter in the method tells Exchange whether to suppress Read Recipients or not).

 

 

  # Bind to the Inbox Folder

$folderid=new-objectMicrosoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$MailboxName)

$Inbox=[Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)

"Number of Messages Unread : "+$Inbox.UnreadCount

$Inbox.MarkAllItemsAsRead($false)

 

4. Marking messages as Junk Email

Another new Operation that has been added to EWS is the ability to Mark and UnMark messages as JunkEmail and move these messages to and from the Junk Email folder. This Operation does two separate things when you use it

· Moves a messages To or From the Junk Email Folder

· Add or Removes the sender of the Messages you’re marking or unmarking as Junk Email to the blocked sender list of that Mailbox.

To use this operation you first need to get the ItemIds of the Items you want to Mark or UnMark as Junk Email. This is typically done in EWS using the FindItem Operation and then filtering on a particular Item property. To control what the MarkAsJunk operation does in the EWS Managed API the MarkAsJunk method has two parameters IsJunk and MoveItem. The following table lists the combinations and actions for these parameters

Folder

IsJunk

MoveItem

Action

Inbox/Any

True

True

Item will be moved to the Junk email folder and email sender added to Blocked Senders List of the Mailbox

Inbox /Any

True

False

The Sender of the Email is added to the Blocked Senders List

JunkEmail

False

True

Item will be moved to the Inbox folder and email Sender will be removed from the Blocked Senders List of the Mailbox

JunkEmail/Any

False

False

The Sender of the Email will be removed from the Blocked Senders list of the Mailbox

 

In this example Messages that have NewLetter in the Subject are marked as JunkEmail and moved to the JunkEmail Folder using the MarkAsJunk operation.

 

# Bind to the Inbox Folder

$folderid=new-objectMicrosoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$MailboxName)

$Inbox=[Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)

#Define ItemView to retrive just 1000 Items

$ivItemView= New-ObjectMicrosoft.Exchange.WebServices.Data.ItemView(1000)

$fiItems=$null   

$type= ("System.Collections.Generic.List"+'`'+"1") -as"Type"

$type=$type.MakeGenericType("Microsoft.Exchange.WebServices.Data.ItemId"-as"Type")

$JunkItems= [Activator]::CreateInstance($type)

 

do{

    $fiItems=$service.FindItems($Inbox.Id,$ivItemView)

    #[Void]$service.LoadPropertiesForItems($fiItems,$psPropset)

   foreach($Itemin$fiItems.Items){

       if($Item.Subject-ne$null){

                    if($Item.Subject.Contains("newsletter")){

                           $JunkItems.Add($Item.Id)

                     }

              }

    }

    $ivItemView.Offset+=$fiItems.Items.Count

}while($fiItems.MoreAvailable-eq$true)

$service.MarkAsJunk($JunkItems,$true,$true);

 

 

5. Using UserRetentionPolicyTags

While it is possible in Exchange 2010 to use UserRetentionPolicyTags in EWS it did require that you define and use the raw extended properties. In 2013 in the EWS using the UserRetentionPolicyTags is made easier through the integration of these tags into the FolderClass and also the GetUserRetentionPolicyTags operation which can be used to get all the user RetentionPolicyTags and their associated settings. For example here is how to create a new folder and set the RetentionPolicyTag on that Folder to a UserRetentionPolicyTag called “1 Month Delete”.

 

 

$getRTResp=$service.GetUserRetentionPolicyTags();

foreach ($rtTagin$getRTResp.RetentionPolicyTags) {

    if ($rtTag.DisplayName-eq"1 Month Delete")

    {

              $NewFolder=new-objectMicrosoft.Exchange.WebServices.Data.Folder($service)

              $NewFolder.DisplayName="My New Folder12345" 

              $NewFolder.FolderClass="IPF.Note"

              $NewFolder.PolicyTag=New-Object

Microsoft.Exchange.WebServices.Data.PolicyTag($true,$rtTag.RetentionId)

              $NewFolder.Save($folderid)

    }

}

 

 

About the author

photogs

Glen Scales is a freelance software developer and engineer who specializes in Microsoft Exchange APIs used to create customized solutions for a range of clients and industries, particularly in the realm of cloud-based services within messaging environments. He has been an Exchange MVP since 2004, contributing regularly to the Exchange development forums on TechNet and creating and sharing open source code libraries and scripts on his blog (https://gsexdev.blogspot.com) and twitter @glenscales.

About MVP Mondays

The MVP Monday Series is created by Melissa Travers. In this series we work to provide readers with a guest post from an MVP every Monday. Melissa is a Community Program Manager, formerly known as MVP Lead, for Messaging and Collaboration (Exchange, Lync, Office 365 and SharePoint) and Microsoft Dynamics in the US. She began her career at Microsoft as an Exchange Support Engineer and has been working with the technical community in some capacity for almost a decade. In her spare time she enjoys going to the gym, shopping for handbags, watching period and fantasy dramas, and spending time with her children and miniature Dachshund. Melissa lives in North Carolina and works out of the Microsoft Charlotte office.