≡ Menu

Testing Exchange Autodiscover with PowerShell and the EWS Managed API

Have you ever used that “Test E-mail AutoConfiguration” utility in Outlook? It’s a useful tool that will query the autodiscover service, showing you exactly what CAS URLs are being handed to a particular user, and what the MAPI/HTTP endpoint is for their Exchange mailbox. You can run this tool by pressing the Ctrl button, right clicking on the Outlook 2007/2010 tray icon, and selecting “Test E-mail AutoConfiguration”. This is nice, but there are times when I want to be able to determine this information for a user without having to fire up Outlook, or when Outlook isn’t installed where ever I happen to be at the moment. My solution for this is a PowerShell function that will retrieve this information using the EWS Managed API. Here’s the code:

function Test-Autodiscover {
    [CmdletBinding()]
    param(
      [Parameter(Position=1, Mandatory=$true)]
      [String]
      $EmailAddress,
      
      [ValidateSet("Internal", "External")]
      [Parameter(Position=2, Mandatory=$false)]
      [String]
      $Location = "External",      
      
      [Parameter(Position=3, Mandatory=$false)]
      [System.Management.Automation.PSCredential]
      $Credential,
      
      [Parameter(Position=4, Mandatory=$false)]
      [switch]
      $TraceEnabled,
      
      [Parameter(Position=5, Mandatory=$false)]
      [bool]
      $IgnoreSsl = $true,
      
      [Parameter(Position=6, Mandatory=$false)]
      [String]
      $Url
      )
      
      begin{
        Add-Type -Path 'C:\Program Files\Microsoft\Exchange\Web Services\1.1\Microsoft.Exchange.WebServices.dll'
      }
      
      process {
        $autod = New-Object Microsoft.Exchange.WebServices.Autodiscover.AutodiscoverService
        $autod.RedirectionUrlValidationCallback = {$true}
        $autod.TraceEnabled = $TraceEnabled
        
        if($IgnoreSsl) {
          [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}        
        }
        
        if($Credential){
          $autod.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials -ArgumentList $Credential.UserName, $Credential.GetNetworkCredential().Password
        }
        
        if($Url) {
          $autod.Url = $Url
        }
        
        switch($Location) {
          "Internal" {
            $autod.EnableScpLookup = $true
            $response = $autod.GetUserSettings(
              $EmailAddress,
              [Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::InternalRpcClientServer,
              [Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::InternalEcpUrl,
              [Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::InternalEwsUrl,
              [Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::InternalOABUrl,
              [Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::InternalUMUrl,
              [Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::InternalWebClientUrls
            )
            
            New-Object PSObject -Property @{
              RpcClientServer = $response.Settings[[Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::InternalRpcClientServer]
              InternalOwaUrl = $response.Settings[[Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::InternalWebClientUrls].urls[0].url
              InternalEcpUrl = $response.Settings[[Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::InternalEcpUrl]
              InternalEwsUrl = $response.Settings[[Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::InternalEwsUrl]
              InternalOABUrl = $response.Settings[[Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::InternalOABUrl]
              InternalUMUrl = $response.Settings[[Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::InternalUMUrl]
            }
          }
          "External" {
            $autod.EnableScpLookup = $false
            $response = $autod.GetUserSettings(
              $EmailAddress,
              [Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::ExternalMailboxServer,
              [Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::ExternalEcpUrl,
              [Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::ExternalEwsUrl,
              [Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::ExternalOABUrl,
              [Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::ExternalUMUrl,
              [Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::ExternalWebClientUrls
            )
            
            New-Object PSObject -Property @{
              HttpServer = $response.Settings[[Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::ExternalMailboxServer]
              ExternalOwaUrl = $response.Settings[[Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::ExternalWebClientUrls].urls[0].url
              ExternalEcpUrl = $response.Settings[[Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::ExternalEcpUrl]
              ExternalEwsUrl = $response.Settings[[Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::ExternalEwsUrl]
              ExternalOABUrl = $response.Settings[[Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::ExternalOABUrl]
              ExternalUMUrl = $response.Settings[[Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::ExternalUMUrl]
            }            
          }
        }                
      }
<#
    .SYNOPSIS
        This function uses the EWS Managed API to test the Exchange Autodiscover service.

    .DESCRIPTION
        This function will retreive the Client Access Server URLs for a specified email address
        by querying the autodiscover service of the Exchange server.

    .PARAMETER  EmailAddress
        Specifies the email address for the mailbox that should be tested.

    .PARAMETER  Location
        Set to External by default, but can also be set to Internal. This parameter controls whether
        the internal or external URLs are returned.
        
    .PARAMETER  Credential
        Specifies a user account that has permission to perform this action. Type a user name, such as 
        "User01" or "Domain01\User01", or enter a PSCredential object, such as one from the Get-Credential cmdlet.
        
    .PARAMETER  TraceEnabled
        Use this switch parameter to enable tracing. This is used for debugging the XML response from the server.    
        
    .PARAMETER  IgnoreSsl
        Set to $true by default. If you do not want to ignore SSL warnings or errors, set this parameter to $false.
        
    .PARAMETER  Url
        You can use this parameter to manually specifiy the autodiscover url.        

    .EXAMPLE
        PS C:\> Test-Autodiscover -EmailAddress administrator@uclabs.ms -Location internal
        
        This example shows how to retrieve the internal autodiscover settings for a user.

    .EXAMPLE
        PS C:\> Test-Autodiscover -EmailAddress administrator@uclabs.ms -Credential $cred
        
        This example shows how to retrieve the external autodiscover settings for a user. You can
        provide credentials if you do not want to use the Windows credentials of the user calling
        the function.

    .LINK
        http://msdn.microsoft.com/en-us/library/dd633699%28v=EXCHG.80%29.aspx

#>      
}


There are a few ways to use this Test-Autodiscover function. First, lets say that you are logged on to a domain workstation. Running the function with the following parameters will use your logged on credentials to perform an SCP look up and return the internal settings for the specified e-mail address:

Test-Autodiscover -EmailAddress administrator@uclabs.ms -Location internal

You can omit the -Location parameter, which by default is set to “External”, and the function will use DNS to locate autodiscover and retrieve the external settings:

Test-Autodiscover -EmailAddress administrator@uclabs.ms

Finally, you might be testing this from the a machine outside your domain. Just create a PSCredential object using the Get-Credential cmdlet and assign it to the -Credential parameter of the function. For example, here’s the result from testing autodiscover for an Exchange Online mailbox hosted through Office 365:

Test-Autodiscover -EmailAddress admin@uclabs.onmicrosoft.com -Credential $cred

In order to use this function you’ll need a few things. First, if you haven’t already, go download the EWS Managed API. You’ll also need the .NET Framework 3.5.1 and PowerShell v2 installed. At that point, all you need to do is add the Test-Autodiscover function to your shell session and you’re good to go.

14 comments… add one

  • Hakim August 24, 2011, 10:41 pm

    Thanks you Mike, nice article and also very nice tools that can help many administrator !

  • Mike Pfeiffer August 25, 2011, 8:24 am

    Thanks Hakim

  • Rasheedah February 20, 2012, 8:22 am

    Great article and tool..I finally got it to work but i am getting this:

    Exception calling “GetUserSettings” with “2″ argument(s): “The Autodiscover service couldn’t be located.”
    At C:\test-autodiscover.psm1:75 char:47
    + $response = $autod.GetUserSettings <<<< (
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    Cannot index into a null array.
    At C:\test-autodiscover.psm1:86 char:47
    + HttpServer = $response.Settings[ <<<< [Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::Ex
    ternalMailboxServer]
    + CategoryInfo : InvalidOperation: (ExternalMailboxServer:UserSettingName) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

    I assume this is not configured on the server, yes?

    Thanks!!

  • Rasheedah February 20, 2012, 9:38 am

    I just ran the test autoconfigu via outlook and no errors….I am thinking I did something wrong running the powershell..

  • Mike Pfeiffer February 20, 2012, 2:27 pm

    Did you supply credentials?

    Test-Autodiscover -EmailAddress admin@uclabs.onmicrosoft.com -Credential $cred

  • archer August 23, 2012, 2:11 pm

    Great Job, Mike ( MVP) . Im running the script against a hosted exchange mailbox. First , was getting this error :
    “Cannot find path ‘C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll’ because it does not exist.

    Was able to modify the script using the loadfile function

    ” $dllpath = “C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll”
    [void][Reflection.Assembly]::LoadFile($dllpath) ”
    Now i couldnt get past this :
    =======================

    Exception calling “GetUserSettings” with “2″ argument(s): “The request failed. The remote server returned an error: (40
    1) Unauthorized.”
    At C:\Users\v-9saram\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1:56 char:47
    + $response = $autod.GetUserSettings <<<< (
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    Cannot index into a null array.
    At C:\Users\v-9saram\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1:67 char:47
    + HttpServer = $response.Settings[ <<<< [Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::Ex
    ternalMailboxServer]
    + CategoryInfo : InvalidOperation: (ExternalMailboxServer:UserSettingName) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

    Any inputs would be really appreaciated..

  • Mike Pfeiffer August 23, 2012, 3:43 pm

    Looks like an authentication issue. Did you provide creds when running the function? For example:

    Test-Autodiscover -EmailAddress admin@uclabs.onmicrosoft.com -Credential $cred

  • Mike S. October 3, 2012, 6:17 pm

    Great article and tool Mike. I tried running it a few different way as you described using the -Location and -Credential parameter but I seem to be getting the same error no matter how I run it.

    For example: I first open powershell and execute the following command to feed credentials for the script.
    1. $cred=Get-Credential
    2. I enter my credentials. In this case its my Office 365 credentials.
    3. I dot source the script so that I can execute the function Test-Autodiscover
    4. I execute the following command :
    Test-Autodiscover -EmailAddress user@myfederatedo365domain.com -Credential $cred

    I get this error:
    Exception calling “GetUserSettings” with “2″ argument(s): “The Autodiscover service could not be located.”
    At C:\Users\mike\Desktop\Test-Autodiscover.ps1:75 char:47
    + $response = $autod.GetUserSettings <<<< (
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    Cannot index into a null array.
    At C:\Users\mike\Desktop\Test-Autodiscover.ps1:86 char:47
    + HttpServer = $response.Settings[ <<<< [Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::Ex
    ternalMailboxServer]
    + CategoryInfo : InvalidOperation: (ExternalMailboxServer:UserSettingName) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

    This happens no matter if I run it with -Location internal, -Location External. Same error. Can you provide some guideance. I appreciate it. Thanks.

  • Mike Pfeiffer October 20, 2012, 3:33 pm

    Since you’re using a vanity domain, make sure you have an autodiscover record in DNS for that domain. Without it, you’ll get that exact error.

  • Ondrej March 18, 2013, 7:13 am

    Hi,
    whats the fastest way to check that supplied URL is correct? I want to use hard coded URL for connection, but I need to have some check. And if that check fails the script use autodiscovery for getting correct URL

  • Brent Quick April 2, 2013, 11:15 am

    So in trying to get this to work, I am seeing an error not previously mentioned.

    Function is dot sourced and I am providing the correct credentials.

    Test-Autodiscover -EmailAddress admin@O365domain.onmicrosoft.com -Credential (Get-Credential)

    cmdlet Get-Credential at command pipeline position 1
    Supply values for the following parameters:

    Cannot index into a null array.
    At line:85 char:13
    + New-Object PSObject -Property @{
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

    Any idea’s? Thanks!

  • Mike Pfeiffer April 2, 2013, 7:36 pm

    Hi Brent,

    Just tried a couple of things…it looks like you’ll get that when $autod.GetUserSettings() fails thanks to my lack of error handling :)

    Try running it with tracing turned on

    Test-Autodiscover -EmailAddress user@domain.com -Credential (Get-Credential) -TraceEnabled

    I noticed that when I entered invalid creds and caused the code to fail that I would get the same “Cannot index into a null array.” With tracing enabled, you should see a 401 unauthorized if indeed the creds are no good. Otherwise, you should get something that will hopefully explain why it fails.

  • Andrei G June 18, 2013, 1:31 pm

    Hi,
    i was getting the same error until i entered the UPN in the credential prompt, after which it worked fine. If entering domain\user it would fail.

    Thanks

  • Dan March 27, 2014, 6:09 am

    I am trying to use this function in a script script to get user info from an office365 wave 15 mailbox. I am calling the function using:

    Test-Autodiscover -EmailAddress $Email -Location “External” -Credential $Credential -TraceEnabled $true

    If I specify a -url “https://outlook.office365.com/EWS.Exchange.asmx” I receive the following error. I was wondering if anyone may have any insight into this error:

    Exception calling “GetUserSettings” with “7″ argument(s): “The request failed
    schema validation: Could not find schema information for the element
    ‘http://schemas.microsoft.com/exchange/2010/Autodiscover:Request’.”
    At C:\…\Test-AutoDiscover.ps1:77 char:13
    + $response = $autod.GetUserSettings(
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ServiceResponseException

    Cannot index into a null array.
    At C:\…\Test-AutoDiscover.ps1:87 char:13
    + New-Object PSObject -Property @{
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

    If I do not specify a url the script returns the following:

    Request error: Unable to connect to the remote server

    No Autodiscover endpoints are available for host autodiscover.domain.onmicrosoft.com

    Trying to get Autodiscover redirection URL from http://autodiscover.Domain.onmicrosoft.com/autodiscover/autodiscover.xml.

    Redirection URL found: ‘https://autodiscover-s.outlook.com/autodiscover/autodi
    over.xml’

    Determining which endpoints are enabled for host autodiscover-s.outlook.com

    Request error: The operation has timed out

    No Autodiscover endpoints are available for host autodiscover-s.outlook.com

    Trying to get Autodiscover host from DNS SRV record for domain.onmicrosoft.com.

    DnsQuery returned error error ‘DNS name does not exist’ error code 0x0000232B.

    No appropriate SRV record was found.

    No matching Autodiscover DNS SRV records were found.

    Exception calling “GetUserSettings” with “7″ argument(s): “The Autodiscover
    service couldn’t be located.”
    At C:\..\Test-AutoDiscover.ps1:77 char:13
    + $response = $autod.GetUserSettings(
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : AutodiscoverLocalException

Leave a Comment