Rolling Your Own Exchange ActiveSync Client


Update August 2013:
If you really want to roll your own EAS client I have created a RESTful API which takes away some of the pain in doing so, and potentially helps you create your own client.
It’s all open source and available from https://easweb.codeplex.com.
If that sounds like too much of a niche interest to you, keep calm and carry on reading this post 🙂

I got my hands dirty with ActiveSync two weeks back (http://mobilitydojo.net/2010/03/17/digging-into-the-exchange-activesync-protocol), and shared the results with you here. I also mentioned that doing the things I did required a few lines of code since not everything could be done in Fiddler. Because of this I promised you I had something in the works to let you actually play around too, without cracking open your Visual Studio, and now I’m trying to make good on this promise 🙂

I introduce to you, the first beta release of “Exchange ActiveSync MD”. It is a desktop app that will let you emulate a device connecting to ActiveSync. Yes, it is similar to what www.testexchangeconnectivity.com, but I only focus on EAS, and I have a couple of options not present in the ActiveSync test MSFT provide. It will require you to have .Net 3.5 installed on your computer – I’ve tested it running on Windows 7 and Windows Server 2008 R2, but it should work on other Windows versions too with .Net present. It will not require an installation, and you can just run the .exe file itself.

It has only three screens to relate to, and while most of it is fairly self-explanatory, (doesn’t always the programmer believe this to be the fact?), I’ll walk you through it:

Main
image

This would be the place you’ll be finding yourself in most of the time using this simple app. There are two tests you can perform; “Basic Connectivity” and “Full Sync”.

Basic Connectivity: for this test you will need to provide the connection parameters, but you can ignore the other options and parameters. This test will perform a HTTP GET against the specified server address to pinpoint basic issues like DNS resolution, server being reachable, and authentication. If the GET works you’ll get a 501/505 the same way as opening the address in a browser. If the GET goes through a HTTP OPTIONS is done against the server to pull down info like server version, etc.

Full Sync:
You still need to fill out the connection parameters, but there are default values provided for the other options. (The connection will be made at the Exchange 2007 RTM level if nothing else is specified in MS-ASProtocolVersion.) The program will attempt the FolderSync command, and provide response based on the security polices in effect on the server. You will be informed in the output window if the sync didn’t go through for some reason, and a tip for correcting it.
For Device ID, Device Type & User Agent you can specify whatever you like as long as you’re not using the new features in Exchange 2010 for restricting these parameters.
The “Device Properties” are additional attributes you might need to set for the sync to go through.
The output window has switches for binary, hex, and base64. Most likely you’re not going to need them all that often. (This only applies to the response body, other text and headers are in plain old text format.) I had to use it for some debugging purposes since the wbxml isn’t all that easy to read.

Certificate Info
image

While you can ignore any certificates issues on the previous tab it can be very handy to pull down the chain and see why it fails if you weren’t expecting it to fail. You don’t need to provide any credentials – just point it to a server running SSL (on port 443). The app then establishes a socket connection and pulls down the chain. Some basic info is printed out, and at the bottom the certificates themselves are embedded in base64. This means that you can open up your Notepad, paste in the string, and save the file with the extension .cer and you will have a certificate file you can use. I am aware I could have provided a possibility for provisioning it directly into a certificate store, but that felt like more work than it was worth 🙂 I could also have pulled all the certs into a single p7b format, but.. well, it works the way it should and serves my purposes in it’s present form. Let me know if there is something that is missing from this tab in the feature department.

Base64 Utility
image

I often find my self needing to convert between a base64 string and plain text when testing, so I just included a tab for it in this app. You might not need it that often, but it’s convenient to have easily accessible.

So does it actually work then? I’ve tested against Exchange 2007 SP1/SP2, and Exchange 2010. No Exchange 2007 RTM unfortunately (even if it’s a choice on the list), and Exchange 2003 is not on the supported list yet. (Of course you can test all client versions against the latest server version since Exchange is backwards compatible.) I believe I have tested the different combos of enforcing policies and blocking non-provisionable but there are differences between each AS-version so I cannot guarantee at this time that there’s not some sneaky bug somewhere. (It is a beta for a reason you know.)

I’m also aware that the interface looks kinda “not done by an actual designer”, and while I do like creating 3D graphics and related stuff I never was top-notch at creating user interfaces 🙂

There are two known issues I haven’t solved at the present time: 
– If you turn on “Trust all certificates”, and then uncheck it you’ll still be trusting all certificates. Workaround is to close the program, and re-start.
– If you have a username and/or password with special characters it might not encode properly, and thus you’ll get a 401 returned.

I am aware of these issues, and will try fixing them. The issues I am not aware will be fixed later on.

While not a bug as such, the internals doesn’t exactly conform to what could be considered “beautiful code”, but that might not be the most important thing at the moment I guess 🙂 (Obviously in the process of cleaning the code, maybe I come across a line that need to be fixed up to so it serves a purpose too.)

My first focus is to do some additional testing, and making sure everything works as advertised. The second priority, which is more fun obviously, is adding new features. How many features could you cram into a small utility like this you say?  Technically you can implement a fully featured ActiveSync client, and while I’m not going to do that the next weeks I am investigating if I can implement wbxml parsing. No promises yet though.

In the meantime, test it out, see if it’s useful, and let me know if you have any questions or feedback.

Download: http://mobilitydojo.net/downloads/ (Sends you to the download page so you can fetch the latest release.)

71 thoughts on “Rolling Your Own Exchange ActiveSync Client”

  1. hi,

    i got an error launching the ‘Full Sync Test’:

    System.IO.FileNotFoundException: Die Datei oder Assembly “WBXML not found .. and so on.
    where i find the missing WBXML?

  2. You’re right – I get that too if I download it and run it 🙂
    It’s my fault for not remembering to include the WBXML.dll file that I use in my app.
    I’ve uploaded a zip-file containing both the executable and the dll and as long as the two files are in the same directory things should work.
    The download link is changed to reflect this so just re-download and have a new go at it.

  3. I used this client and it created a “fakedevice” on my system that I now cannot get rid of.

    Error:
    The ActiveSyncDevice path/user/FakeDevice§EASMD cannot be found.

    Exchange Management Shell command attempted:
    Remove-ActiveSyncDevice -Identity ‘Path/User/ExchangeActiveSyncDevices/FakeDevice§EASMD’

    This was performed by bringing up the user in Exchange Mangement Console, selecting Manage Mobile Phone, selecting the device and clicking “remove”

    Any ideas?

  4. I have seen this once while testing on Exchange 2007. I can’t remember if it was with EAS MD or with the Windows Mobile emulator (could have been either).
    It seems there is a snafu that occurs for no apparent reason (at least to me).
    I managed to get around it by using ADSIEdit and removing it that way – which isn’t really recommended to do in most cases.

  5. Fantastic utility – can you give me a heads up where I can find example xml files to feed into the WBXML tab. Alternatively in the next release you could embed the example xml 🙂 Thanks again…

  6. Some samples can be found over at the MSDN library for MS-ASCMD: http://msdn.microsoft.com/en-us/library/ee159670(v=exchg.80)
    These can be copy-pasted and corrected for things like using actual user names, etc.
    After getting used to a couple of these you can look into the actual WBXML encoding if you wish.

    I have given some thought to providing a more interactive way to build WBXML in an upcoming release, but I haven’t decided yet whether to do it or if so in what form 🙂

  7. Thanks a ton for this utility! It has helped me in playing around with the EAS commands. There seems to be one problem, and I want to bring to your notice:

    I tested this using the hotmail EAS server. When I used the itemoperations command to synchronize only email metadata, the utility works fine if the folder is empty. However if the folder contains even 1 email, it throws a unhandled exception : Index out of range. I have pasted the exception message below. Can you please fix this? I was trying to check if there is any a available source code, but couldnt find it. Thanks a lot! — Shashank

    Here is the exception:

    See the end of this message for details on invoking
    just-in-time (JIT) debugging instead of this dialog box.

    ************** Exception Text **************
    System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
    Parameter name: index
    at System.ThrowHelper.ThrowArgumentOutOfRangeException()
    at System.SZArrayHelper.get_Item[T](Int32 index)
    at System.Linq.Enumerable.ElementAt[TSource](IEnumerable`1 source, Int32 index)
    at WBXML.WBXMLReader.ParseElement(IList`1 document, Int32 next)
    at WBXML.WBXMLReader.ParseElement(IList`1 document, Int32 next)
    at WBXML.WBXMLReader.ParseElement(IList`1 document, Int32 next)
    at WBXML.WBXMLReader.ParseElement(IList`1 document, Int32 next)
    at WBXML.WBXMLReader.ParseElement(IList`1 document, Int32 next)
    at WBXML.WBXMLReader.ParseElement(IList`1 document, Int32 next)
    at WBXML.WBXMLReader.ParseElement(IList`1 document, Int32 next)
    at WBXML.WBXMLReader.ParseElement(IList`1 document, Int32 next)
    at WBXML.WBXMLReader.ParseElement(IList`1 document, Int32 next)
    at WBXML.WBXMLReader.ParseElement(IList`1 document, Int32 next)
    at WBXML.WBXMLReader.ParseElement(IList`1 document, Int32 next)
    at WBXML.WBXMLReader.ParseElement(IList`1 document, Int32 next)
    at WBXML.WBXMLReader.ParseElement(IList`1 document, Int32 next)
    at WBXML.WBXMLConverter.Parse(IList`1 document)
    at EAS_MD.frmEAS.btnExecuteWbxml_Click(Object sender, EventArgs e)
    at System.Windows.Forms.Control.OnClick(EventArgs e)
    at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
    at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
    at System.Windows.Forms.Control.WndProc(Message& m)
    at System.Windows.Forms.ButtonBase.WndProc(Message& m)
    at System.Windows.Forms.Button.WndProc(Message& m)
    at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
    at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

    ************** Loaded Assemblies **************
    mscorlib
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.4971 (win7RTMGDR.050727-4900)
    CodeBase: file:///C:/Windows/Microsoft.NET/Framework64/v2.0.50727/mscorlib.dll
    —————————————-
    EAS_MD
    Assembly Version: 1.7.1.0
    Win32 Version: 1.7.1.0
    CodeBase: file:///F:/Shashank/EAS/EAS/EAS_MD/EAS_MD_1.71.exe
    —————————————-
    System.Windows.Forms
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.4977 (win7RTMGDR.050727-4900)
    CodeBase: file:///C:/Windows/assembly/GAC_MSIL/System.Windows.Forms/2.0.0.0__b77a5c561934e089/System.Windows.Forms.dll
    —————————————-
    System
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.4971 (win7RTMGDR.050727-4900)
    CodeBase: file:///C:/Windows/assembly/GAC_MSIL/System/2.0.0.0__b77a5c561934e089/System.dll
    —————————————-
    System.Drawing
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.4980 (win7RTMGDR.050727-4900)
    CodeBase: file:///C:/Windows/assembly/GAC_MSIL/System.Drawing/2.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll
    —————————————-
    System.Configuration
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.4927 (NetFXspW7.050727-4900)
    CodeBase: file:///C:/Windows/assembly/GAC_MSIL/System.Configuration/2.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll
    —————————————-
    System.Xml
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.4927 (NetFXspW7.050727-4900)
    CodeBase: file:///C:/Windows/assembly/GAC_MSIL/System.Xml/2.0.0.0__b77a5c561934e089/System.Xml.dll
    —————————————-
    WBXML
    Assembly Version: 1.0.0.0
    Win32 Version: 1.0.0.0
    CodeBase: file:///F:/Shashank/EAS/EAS/EAS_MD/WBXML.DLL
    —————————————-
    System.Xml.Linq
    Assembly Version: 3.5.0.0
    Win32 Version: 3.5.30729.4926 built by: NetFXw7
    CodeBase: file:///C:/Windows/assembly/GAC_MSIL/System.Xml.Linq/3.5.0.0__b77a5c561934e089/System.Xml.Linq.dll
    —————————————-
    System.Core
    Assembly Version: 3.5.0.0
    Win32 Version: 3.5.30729.4926 built by: NetFXw7
    CodeBase: file:///C:/Windows/assembly/GAC_MSIL/System.Core/3.5.0.0__b77a5c561934e089/System.Core.dll
    —————————————-

    ************** JIT Debugging **************
    To enable just-in-time (JIT) debugging, the .config file for this
    application or computer (machine.config) must have the
    jitDebugging value set in the system.windows.forms section.
    The application must also be compiled with debugging
    enabled.

    For example:

    When JIT debugging is enabled, any unhandled exception
    will be sent to the JIT debugger registered on the computer
    rather than be handled by this dialog box.

  8. If my memory serves me right hotmail offers up Exchange 2003 level support for ActiveSync. And that’s real fun when developing since that’s not publicly documented. So I can’t tell how it’s supposed to act like that with non-empty folders.

    I would however agree that my utility doesn’t handle this in a very polite manner if it spits out index out of range type exceptions and crashes. (Not that I have invested heavily in exception handling in the encoder/decoder dll.)

    If you would like to have a crack at fixing the source I have documented how this dll works, along with the source code as well here:
    http://mobilitydojo.net/2012/03/07/exchange-activesync-building-blocksencode-decode/

  9. This is a very useful utility! I found it this week and used it yesterday to test an Exchange 2010 environment, which is currently in transition from 2007. I use a legacy host, for the old servers and it works well in generally. But in case of active sync, I have no way to test it, because I implement it in an test environment. Therefore I used this very cool tool. And it works well, except the client redirect to the legacy host. Is it possible, that this tool cannot handle this redirection to the legacy CAS Server? Many thanks.

  10. When the CAS detects that you are located on a different server it should return a http 451 with the correct address. (In the form of a X-MS-LOCATION header.) This should be caught by my utility and then printed in the output view. It’s not an automatic redirect, but I thought it would be more useful for diagnostic purposes to do it this way.
    If this is not the behaviour you’re seeing I’m not sure why. (Could be a bug in my util, could be something in the Exchange setup.)

  11. Ok, that makes sense for me. Thanks for clarification. The tool does work as a charme, it was my misinterpretation of the return code 😉 Best wishes and many thanks again.

  12. This is really cool utility to test the two main features ActiveSync and Autodiscover. Its works flawlessly…. Great job Andreas!

  13. Has anyone built any fully functional clients using this?

    I have a corporate email system that only allows access via ActiveSync if you’re not behind the corporate firewall. I am a remote worker who travels to various customers and sometimes VPN access is not easy to get. If I can get email on my phone without VPN why not my laptop?

    It would be awesome if something like this could be built into DavMail which is what I used to use to connect to Exchange before I moved to a company that didn’t allow OWA access from outside the firewall.

  14. I’ve been doing some mock-ups of OWA through ActiveSync in my lab based on this API. (I’ve got some API updates coming soon.) But I haven’t released it outside the virtual machines it’s been running on.

    It would be cool to have a web client available, but there are some licensing issues to providing this. So that might be a reason it’s not been done by someone else already (not necessarily using my API but in general).

    In the meantime; if you use Outlook 2013 you can use EAS on the client side to gain access to the Exchange Server. (Don’t know which platform you’re running on.)

  15. Great Tool! Is there any way to automate it. for example: if I have to monitor ActiveSync exchange server to make sure users can access email all the time (24×7 monitoring), can I do that?

  16. This tool does not have command line options that would enable it to run without a UI, or scheduled/as a service.

    Nagios has a plugin that will do this: https://exchange.nagios.org/directory/Plugins/Email-and-Groupware/Microsoft-Exchange/Active-Sync-Check/details

    Unsurprisingly System Center Operations Manager also has support for monitoring ActiveSync, but SCOM is overkill if you’re only interested in monitoring EAS.

    I don’t know if you are comfortable with coding yourself, but since the source for EAS MD is open it should be fairly easy to build a version which runs on the command line. I realize that if you aren’t into coding having the source doesn’t solve the problem, but I haven’t built a version myself since I haven’t seen all that much demand for it.

  17. Thanks. I looked at the Nagios plugin you mentioned but couldn’t find much info on how to use it and get it. Is it paid or free?

  18. While Nagios is open source, and should be freely available to download, I am not familiar with their licensing model in general. The plugin should be free though.

Leave a Reply

Your email address will not be published. Required fields are marked *

*