Skip to main content

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 ;)
TRY
{
    Invoke-WebRequest -Uri $ExchangeURL -Headers $Headers -Method GET -UserAgent 'DexterPSAgent' -MaximumRedirection 0
}
CATCH
{
    $_.exception

}



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:">
   <SyncKey>0</SyncKey>
</FolderSync>

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
$Headers.Add("MS-ASProtocolVersion",'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 !


Resources

Exchange ActiveSync Building Blocks – First Sync

http://mobilitydojo.net/2011/08/24/exchange-activesync-building-blocks-first-sync/


#PSTip - Converting Numbers to Hex
http://www.powershellmagazine.com/2012/10/12/pstip-converting-numbers-to-hex/

Popular posts from this blog

Test connectivity via a specific network interface

Recently while working on a Private cloud implementation, I came across a scenario where I needed to test connectivity of a node to the AD/DNS via multiple network adapters.  Many of us would know that having multiple network routes is usually done to take care of redundancy. So that if a network adapter goes down, one can use the other network interface to reach out to the node. In order to make it easy for everyone to follow along, below is an analogy for the above scenario: My laptop has multiple network adapters (say Wi-Fi and Ethernet) connected to the same network. Now how do I test connectivity to a Server on the network only over say Wi-Fi network adapter?

PowerShell + SCCM : Run CM cmdlets remotely

Today I saw a tweet about using implicit remoting to load the Configuration Manager on my machine by Justin Mathews . It caught my eye as I have never really tried it, but theoretically it can be done. Note - The second tweet says "Cannot find a provider with the name CMSite", resolution to which is in the Troubleshooting section at the end.

PowerShell : Trust network share to load modules & ps1

Problem Do you have a central network share, where you store all the scripts or PowerShell modules ? What happens if you try to run the script from a network share ? or if you have scripts (local) which invoke scripts or import PowerShell modules stored on this network share ? Well you would see a security warning like below (Note - I have set execution policy as 'Unrestricted' not 'bypass' here): Run a .ps1 from the network share Well this is a similar warning, which you get when you download scripts from Internet. As the message says run Unblock-File cmdlet to unblock the script and then run it, let's try it.