Tuesday, March 17, 2015

PowerShell + EAS + MSExchange - FolderSync

This is the third post in series of poking around EAS protocol using PowerShell, find the first 2 posts below :

  1. PowerShell + EAS : Getting Started
  2. PowerShell + EAS + MSExchange : Autodiscovery

If you are a interested in looking at the C# code samples then checkout posts  @MobilityDojo.net in the Resources section at the bottom.

Once you have discovered the URL of the EAS endpoint to connect to, it is time to follow below 3 requests in order to establish an ActiveSync Partnership with Exchange Server:

Step 1 : HTTP Get (optional)

This is sort of a diagnostic step to ensure that the Exchange Server discovered using the Auto Discovery process is up and reachable, SSL Certificates are in place and the Authentication scheme (basic in our case) is working.

#URL got from the Auto-Discovery - Refer my previous post
$ExchangeURL = 'https://outlook.office365.com/Microsoft-Server-ActiveSync'

#store the Credentials
$cred = Get-Credential -UserName 'testuser@dexterposh.in' -Message 'Enter password for the User'

#need to encode the Username too make it a part of the authorization header
$EncodedUsernamePassword = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($('{0}:{1}' -f $cred.UserName, $cred.GetNetworkCredential().Password)))

#create the Authorization header
$Headers = @{'Authorization' = "Basic $($EncodedUsernamePassword)" }

#Step 1 - HTTP GET - Use Try Catch as the Server Error is expected, If Server throws error that means it is reachable ;)
    Invoke-WebRequest -Uri $ExchangeURL -Headers $Headers -Method GET -UserAgent 'DexterPSAgent' -MaximumRedirection 0


Note the first few variables like $headers and $ExchangeURL will be re-used in the below steps.

We will use Try Catch as the response from the Server Error will throw an error (expected behavior here as the DeviceID and other info is missing in our Request), If Server throws an error that means it is reachable ;)

Below is what I get :

Step 2 : HTTP Options (optional)

In the second step after We know that the Server is up and processing requests on the EAS endpoint, it is a good idea to collect details like the Exchange server version running on the Remote Server so that the client adjusts its behavior.

How to do this using PowerShell is already shown in the PowerShell + EAS :Getting Started post, but below is how you get that :

#Step 2 - HTTP Options
Invoke-WebRequest -Uri $ExchangeURL -Headers $Headers -Method Options -UserAgent 'DexterPSAgent' | Select-Object -ExpandProperty Headers

Below is how it looks in the PowerShell console :

Step 3 - HTTP Post

Now after determining the Server availability (Step 1) and the version it is running (Step 2) , now it is time to finally work on performing the initial FolderSync. 

This step is important as the response in this step tells us the Folder Structure of the Mailbox we are trying to sync too, but the Request and Response follow a standard known AS-WBXML (ActiveSync - Wireless Application Protocol Binary XML).

From what I understand AS-WBXML converts the standard XML to WBXML code page and tokens (basically compresses XML) and transmits it to the ActiveSync Server.

So in the below code we will use a hex byte array as the Request body in WBXML format, so don't be surprised.

$bytes = [byte[]](0x03, 0x01, 0x6a, 0x00, 0x00, 0x07, 0x56, 0x52, 0x03, 0x30, 0x00, 0x01, 0x01)

In XML terms the above hex byte array, means the below and in simple terms it is asking for the Folder Hierarchy from the Remote Server :

<?xml version="1.0" encoding="utf-8"?>
<FolderSync xmlns="FolderHierarchy:">

We will get back to the AS-WBXML topic in upcoming post.
Now before we do the initial Sync, let's take a look at the mobile devices for the testuser on Outlook @Office365.

Now let's make the WebRequest for the FolderSync command and see the changes in the Mobile devices.

Below is the PowerShell code, reusing the $Headers, $ExchangeURL & $cred below:

#Have to create URL in a specific format, try missing the URL in this format and see the error
$ExchangeURL = $ExchangeURL + "/Microsoft-Server-ActiveSync?Cmd=FolderSync&User=$($Cred.UserName)&DeviceID=123456789&DeviceType=DexPSDevice"

#Setting the EAS protocol version to 14.1

#Request body as hex byte array...this is done because EAS uses WBXML format for Request & Response
$bytes = [byte[]](0x03, 0x01, 0x6a, 0x00, 0x00, 0x07, 0x56, 0x52, 0x03, 0x30, 0x00, 0x01, 0x01)

#Finally make the WebRequest and be done with it ;)
Invoke-WebRequest -Uri $ExchangeURL -Headers $Headers -Method Post -ContentType "application/vnd.ms-sync.wbxml" -Body $bytes -UserAgent DexPSAgent -MaximumRedirection 0

Below is a screenshot :

Don't worry about the Content you see in above, we will eventually get there ;)
Let's go back and see if the DexPSAgent of ours reflects in the EAS devices in OWA.

Heartfelt thanks to posts @MobilityDojo.net and @PowerShellMagazine for sharing some of the awesome content that helped me a lot to pick things up. 

Cheers !


Exchange ActiveSync Building Blocks – First Sync


#PSTip - Converting Numbers to Hex