Exchange Web Services for Mailbox Access
Mail Manager
Most administrators are familiar with the Exchange Web Services from the virtual directories and as a means for Outlook to publish out-of-office messages. But the services can do much more and provide useful functions such as sorting out attachments. In this article, we look at EWS mailbox access via PowerShell and possibilities for in-house development.
Exchange Web Services (EWS) is an important interface that lets applications access Exchange content. Outlook uses the services to call the availability service and the Out of Office Wizard, among other things. Exchange has been using EWS since version 2007, which is the basic prerequisite for using the corresponding API. In addition, you need the Exchange Web Services Managed API 2.2 [1].
If you only use Exchange locally, the EWS API is available as described below. However, Microsoft 365 previously had different interfaces for the different tools. For Exchange, it was the EWS interface presented here, among others.
In the future, Microsoft Graph will serve as the central access point for the interaction of the various services in Microsoft 365. However, it is not directly available for a local Exchange and only in hybrid environments will you be able to access local Exchange environments via Microsoft Graph. Furthermore, EWS will no longer receive function updates in Exchange Online [2].
Disabling Exchange Basic Authentication
For Exchange, basic authentication was, for a long time, a fast way to log on – always active and easy to use. However, it offers a greater potential for attack, and additional security mechanisms such as multi-factor authentication are often not used because of their complexity.
For this reason, Microsoft decided as early as 2018 to switch off basic authentication for EWS at Exchange Online as of October 2020. In 2019, the provider extended this shutdown to Exchange ActiveSync (EAS), POP, IMAP, and Remote PowerShell. Due to COVID-19, the deadline has now been postponed to the second half of 2021. In the future, logon will be based on state-of-art authentication with Active Directory Authentication Library (ADAL) and OAuth 2.0 [3].
Getting Started with Exchange Web Services
Since Exchange 2007, Microsoft has recommended using the same name range for internal and external connections. The "mail.domain.com" name is all it takes for client access to all the servers in an environment.
You can change the names of the access points in the Exchange Administration Center by going to Servers/Virtual Directories
. Another way to set up the URLs is to use the PowerShell with the Set-WebServicesVirtualDirectory
cmdlet and the InternalUrl
and ExternalUrl
parameters. Make sure that these URLs are also stored in the certificate, and try to limit the number of names to as few as possible.
To access data, you need a user account with appropriate rights for the mailboxes. For Exchange, assign the corresponding "ApplicationImpersonation" role to a user with the following command:
New-ManagementRoleAssignment -name:Impersonata -Role:ApplicationImpersonation -User:User
"Impersonation" means that the process pretends to be the corresponding user and works in their context. Alternatively, you can create a corresponding role in the EAC and assign it to the service user (Figure 1).
Using PowerShell with the EWS Managed API
The EWS Managed API can also be accessed directly via PowerShell. As an example, we will be downloading the attachments of an email. This functionality is also used by many archive providers who remove attachments via EWS and exchange them for an archive link. Also conceivable in this context is processing role mailboxes and downloading attachments for further processing.
In Listing 1, we first define the variables. Here we need the path to the WebServices.dll
for the Managed API 2.2, which we will use to define the mailbox with the folder to be checked, along with the access credentials. To use the operators, the script loads the API DLL using the Import-Module
cmdlet, which makes various operators available [4].
Listing 1
Sort Out Email Attachments
01 [string]$DllPath = "C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll" 02 [string]$Mailbox = "groupmail@example.com" 03 [string]$Password = "CS%Outlook2020" 04 [string]$Domain = "schulenburg" 05 [string]$EWSURL = "https://outlook.office365.com/EWS/Exchange.asmx" 06 [string]$DownloadPath = "C:\Temp\Attachments" 07 [string]$Folder = "Inbox" 08 Import-Module -Name $DllPath 09 $ExchangeService = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1) 10 $ExchangeService.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials($Mailbox,$Password,$Domain) 11 $ExchangeService.Url = $EwsURL 12 $offset = 0 13 Do { 14 $ItemView = New-Object Microsoft.Exchange.WebServices.Data.ItemView(1000, $offset) 15 $ItemView.PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties) 16 $Items = $ExchangeService.FindItems([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]:: $Folder,$ItemView) 17 $Items 18 foreach ($Item in $Items) 19 { 20 If ($Item.HasAttachments -eq $true) 21 { 22 Write-Host "Subject: $($Item.Subject)" -ForegroundColor cyan 23 $PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange. WebServices.Data.ItemSchema]::Attachments) 24 $Message = [Microsoft.Exchange.WebServices.Data.EmailMessage]::Bind($ExchangeService, $Item.Id,$PropertySet) 25 Foreach ($Attachment in $Message.Attachments) 26 { 27 $AttachmentName = $Attachment.Name 28 If ($AttachmentName -match ".pdf") 29 { 30 $AttachmentName 31 $Attachment.Load("$DownloadPath\$AttachmentName") 32 } 33 } 34 } 35 } 36 $offset = $offset + 1000 37 } while($Items.MoreAvailable)
Once the DLL is loaded, we have access to the WebServices.Data.ExchangeService
name range and can use the New-Object
cmdlet to create a new object to connect to EWS. A specific version of Exchange is not necessary nor does it have to match the version of your server. It only defines the lowest supported version.
The EWS-API offers different possibilities to determine access points. This can be done by an autodiscover of the domain or simply by a fixed assignment like in our example (ExchangeService.Url = $EwsURL"
).
Various options are also available for authentication. To simplify matters, we stored the login data in the script, which you should generally avoid in production use.
$ExchangeService.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials($Mailbox,$Password,$Domain)
Alternatively, you can use the currently logged in user as follows:
$ExchangeService.UserDefaultCredentials = $true
In our example, we first discovered the emails from the specified mailbox using FindItems
. The result is then checked for attachments with the property HasAttachments
. And, in the foreach
loop, the document type is checked before the attachments are downloaded. As a result, all PDF attachments of emails end up in the Inbox in the folder C:\ Temp\Attachments
.
The script can now be extended further, and the processed emails could easily be moved to another suborder using the Move method (in the script $Item.Move ("DeletedItems")
). You can find an overview of the options on the Exchange website [5], and the template for our sample script on the Icewolf blog [6].
Basic functions like writing a log or sending an email to the administrator are possible independently of EWS. Another example is clearing all emails older than 30 days from the trash. This is an interesting option for any mailbox, and you can find a template on the Icewolf blog [7].
Buy this article as PDF
(incl. VAT)