Monday, March 02, 2015

PowerShell + EAS + MSExchange : Autodiscovery

This post is going to be on how to use PowerShell to get an insight in the Autodiscovery process which the EAS Mail clients use.

Second entry in my #PowerShell + #EAS posts:

  1. PowerShell + EAS : Getting Started


Once you enter Email Address and Password in the Mail setup in the device, the Autodiscovery process kicks in. Remember there is no such thing as the mail account getting magically configured :)

To explain the process is not my intent, Please refer to the MSDN blog post here.

In short the Autodiscovery process tries to get a valid XML response from 4 sources (based on the workflow explained at the MSDN blog ). In this post we will be looking at a way to make those 4 requests and study the responses we get back using PowerShell. This is a more of a hands on approach here.

I will be taking an account for the demo, for which we will see the discovery process in action :
  • TestUser Account on Office365  (testuser@dexterposh.in)

The EAS client looks at your email address and then parses it to get the domain name, below is how to do it in PowerShell using the split operator and multiple assignment:



$email = 'testuser@dexterposh.in'
#Split the email address to get the Username and the domain name
$username, $fqdn = $email -split '@'



When I execute the code:


PS>$email = 'testuser@dexterposh.in'                                                                 
PS>#Split the email address to get the Username and the domain name                                  
PS>$username, $fqdn = $email -split '@'                                                              
PS>                                                                                                  
PS>$username                                                                                         
testuser                                                                                             
PS>$fqdn                                                                                             
dexterposh.in                                                                                        
Before we start hitting the various URLs to kick in autodiscovery it is important to understand that, Autodiscovery is the only step in the EAS communication process which uses XML format for the Request and Response.

So when you make a call to the AutoDiscovery endpoint it expects a Request Body in a certain XML form. Notice that the email address needs to be passed in as Request.

Thought of using Here-Strings but it failed , so going to use a very crude example like below (choose to split in 2 lines for better readability):



$Body= '<?xml version="1.0" encoding="utf-8"?><Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/requestschema/2006"><Request>'
$Body = $Body + "<EMailAddress>$email</EMailAddress><AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006</AcceptableResponseSchema></Request></Autodiscover>"

So now we will go ahead and see actually the PowerShell code snippet for performing the below 4 tests:





Let's gather the credential to create the Auth header and rest of the key pieces needed to make a WebRequest and which is common to first 3 tests:



#Supply the Credential for the testuser
$Credential = Get-Credential

#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 $Credential.UserName, $Credential.GetNetworkCredential().Password)))

#Create a Hashtable for Authorization
$Headers = @{'Authorization' = "Basic $($EncodedUsernamePassword)" }










Test #1 


For the first test the URL format is as below :




#construct the URL from the FQDN
$URL1 = "https://$fqdn/autodiscover/autodiscover.xml"

Now Let's go ahead and hit the autodiscover endpoint
The HTTP Method is POST , Content Type is XML and I don't want the page to redirect me at this point automatically so -MaximumRedirectionCount is given an argument 0 (zero).



Invoke-WebRequest -Uri $URL1 -UserAgent DexterPSAgent -Headers $Headers -ContentType 'text/xml' -Body $body -Method Post -MaximumRedirection 0 

Below is what I see when I run it :


PS>Invoke-WebRequest -Uri $URL1 -UserAgent DexterPSAgent -Headers $Headers -ContentType 'text/xml' -Body $body -Method Post -MaximumRedirection 0                                                                                                                                
Invoke-WebRequest : Unable to connect to the remote server                                                                                   
At line:1 char:1                                                                                                                             
+ Invoke-WebRequest -Uri $URL1 -UserAgent DexterPSAgent -Headers $Headers -Content ...                                                       
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                                                           
    + CategoryInfo          : NotSpecified: (:) [Invoke-WebRequest], WebException                                                            
    + FullyQualifiedErrorId : System.Net.WebException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand                                  
                                                                                                                                             

Examining the $Error[0] shows below:



PS>$Error[0].exception                                                                           
Unable to connect to the remote server                                                           
PS>$Error[0].exception.innerexception                                                            
No connection could be made because the target machine actively refused it 50.63.67.387:443      

That is true because the Remote Server is not listening on port 443. So the First step fails in this case for me. Now as per the standard my Client should proceed to Test #2.








Test #2


As per the documentation the next URL the EAS Mail client tries to reach is  of below format:

$URL2 = "https://autodiscover.$fqdn/autodiscover/autodiscover.xml"

Let's make a WebRequest, rer-using most of the things like Headers, Body etc from the Test #1.



Invoke-WebRequest -Uri $URL2 -UserAgent DexterPSAgent -Headers $Headers -ContentType 'text/xml' -Body $Body -Method Post -MaximumRedirection 0


Again I get the same Error as in the Test #1 here in this case too (skipping the screenshot). See below telnet fails to the hostname on port 443.






P.S. - Not using Test-NetConnection cmdlet as I am still on Windows 7.
Also if you are on-premise Exchange Server and have Autodiscovery configured this is the most common scheme which Enterprises use.








Test #3


This is getting interesting now as still I have not been able to get valid XML Response from the Autodiscovery.

Time to perform the Test #3 , Notice that in this URL scheme uses HTTP and the method GET (so no content)



#Test 3 - Autodiscovery ; http://autodiscover.FQDN/autodiscovery/autodiscovery.xml -- HTTP GET

$URL3 = "http://autodiscover.$fqdn/autodiscover/autodiscover.xml"

# HTTP GET - Request to the URL
Invoke-WebRequest -Uri $URL3 -UserAgent DexterPSAgent -Headers $Headers -Method GET -MaximumRedirection 0


Now let's try this :















Note - You have to use -MaximumRedirectionCount 0 here as the 302 status code is one of the expected value here and moreover when someone is redirecting , One needs to be aware of it !




If you have not checked out the MSDN blog link then now is a good time to do that.

It states that once we get a 302 response, we need to make a call to the Location HTTP Header. So If I we look at the HTTP headers of previous response we will see that there is a location this URL is redirecting us to:




Let's make the HTTP POST call now to the URL mentioned in the Location header above and be done with this Test.










I get a 401 unauthorized, which means there is some problem with the Authorization header. It appears the Username used for creating the Authorization header is 'testuser' but as this is one of the account in Office 365.

Accounts in O365 use email address as the username...Note this will change if you are on-premise and have the Autodiscovery running.


So let's re-create the Authorization header and make the Call.



$Credential = Get-Credential -UserName 'testuser@dexterposh.in' -Message 'Enter credentials for TestUser'
$EncodedUsernamePassword = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($('{0}:{1}' -f $Credential.UserName, $Credential.GetNetworkCredential().Password)))
$Headers = @{'Authorization' = "Basic $($EncodedUsernamePassword)" }
Invoke-WebRequest -Uri $URL4 -UserAgent DexterPSAgent -Headers $Headers -ContentType 'text/xml' -Body $body -Method Post -MaximumRedirection 0
















Note - For Office 365 accounts this is how discovery works.





Test #4

Now we don't need to actually perform this step as we already have built neverthless, let me point out how to do this using PowerShell.




Easy use Nslookup.exe in PowerShell and parse the output , I bet someone has already done it . Check out the Resources link below ;)


PS>nslookup.exe -type=srv "_autodiscover._tcp.$fqdn"


More poking around EAS using PowerShell is gonna follow, Stay tuned for more !
 

Resources:




Autodiscover for EAS Devs (Must Read!)
http://blogs.msdn.com/b/exchangedev/archive/2011/07/08/autodiscover-for-exchange-activesync-developers.aspx


Original article at MobilityDojo.net
http://mobilitydojo.net/2011/08/18/exchange-activesync-building-blocks-autodiscover/ 

Getting SRV Records with PowerShellhttp://blogs.msdn.com/b/timid/archive/2014/07/08/getting-srv-records-with-powershell.aspx

No comments:

Post a Comment