Search code examples
powershellexchange-server

Trying to dynamically connect in Powershell to nearest Exchange Server


New-PSSession wants a -ConnectionURI of an explict Exchange server. I don't want to hardcode a name in the script (we have 32 servers), and furthermore I want it to select an exchange that is in the same datacenter.

I want a solution similar to Get-ADDomainController -Discover -GetClosestSite But it seems I'm hoping for too much.

I suppose I can pull the members of cn=Exchange Install Domain Servers and do some site dependent ranking on them.

Looking for best practices.

Update Edit: 9/26 I have achieved a solution. It may be site specific, but I'll share below in an answer to show the final code. The answer provided by postanote provided pointers that helped me move forward.


Solution

  • There is no official documented best practices for PowerShell in general (there are too many variables in the mix, but some have put their thoughts in the topic , for example, this one - https://github.com/PoshCode/PowerShellPracticeAndStyle ) or for what you are asking for from Microsoft.

    As for you point here:

    I suppose I can pull the members of cn=Exchange Install Domain Servers and do some site dependent ranking on them.

    This is not something new, or tricky, so you can do this.

    I have code in my personal library that I use that does this as well as for other doing resources, so I never have to hardcode server names for Exchange, SQL, DC, etc.

    There are several blogs (that have been out there for a while now) on the topic with sample code to use as is or tweak as needed, which is why I asked what you've searched for.

    One of those blog examples of how to do this is here:

    https://use-powershell.blogspot.com/2012/12/find-exchange-servers-in-domain.html

    The examples provided:

    1. an active directory user with mailbox will have 2 attributes (msExchHomeServerName and homemdb) that will contain the name of the mailbox server that has his mailbox - once conected to one server you can use exchange console to find the rest of them;
    Get-ADUser samaccountname -Properties msExchHomeServerName, homemdb |Select-Object msExchHomeServerName, homemdb |Format-List
    
    1. active directory computer type objects contain "exchange" word in servicePrincipalName attribute; you can use only your organizational unit that contain your servers if you have one to narrow your search:
    Get-ADComputer -Filter * -SearchBase 'OU= SERVERS, DC=domain_name,DC=net' -Properties * | Where-Object {$_.serviceprincipalname -like '*exchange*'} |select-object  name
    
    1. active directory configuration partition contain information about exchange servers in domain; you can search for objects of class msExchExchangeServer:
    Get-ADObject -LDAPFilter "(objectClass=msExchExchangeServer)" –SearchBase "CN=Configuration,DC=domainname,DC=net" | Select-Object  name
    

    or you can list all objects from "CN=Servers,CN=First Administrative Group,CN=Administrative Groups,CN=INTERNAL,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=domainname,DC=net" using powershell or ADSI Edit console;

    Get-ADObject -Filter * -SearchBase "CN=Servers,CN=First Administrative Group,CN=Administrative Groups,CN=INTERNAL,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=domainname,DC=net" -SearchScope onelevel 
    

    Or this post:

    https://social.technet.microsoft.com/Forums/ie/en-US/94d89161-9dfb-48fc-b307-2f0e1320c9dc/how-to-find-file-servers-and-exchange-servers-in-ad-

    Example:

    dsquery * "cn=Configuration,dc=MyDomain,dc=com" -Filter "(objectCategory=msExchExchangeServer)"
    

    Or if you are really trying to get an Exchange server in given site, then this to already exists. See this GitHub source:

    https://github.com/mikepfeiffer/PowerShell/blob/master/Get-ExchangeServerInSite.ps1

    The sample provided is:

    function Get-ExchangeServerInSite {
        $ADSite = [System.DirectoryServices.ActiveDirectory.ActiveDirectorySite]
        $siteDN = $ADSite::GetComputerSite().GetDirectoryEntry().distinguishedName
        $configNC=([ADSI]"LDAP://RootDse").configurationNamingContext
        $search = new-object DirectoryServices.DirectorySearcher([ADSI]"LDAP://$configNC")
        $objectClass = "objectClass=msExchExchangeServer"
        $version = "versionNumber>=1937801568"
        $site = "msExchServerSite=$siteDN"
        $search.Filter = "(&($objectClass)($version)($site))"
        $search.PageSize=1000
        [void] $search.PropertiesToLoad.Add("name")
        [void] $search.PropertiesToLoad.Add("msexchcurrentserverroles")
        [void] $search.PropertiesToLoad.Add("networkaddress")
        $search.FindAll() | %{
            New-Object PSObject -Property @{
                Name = $_.Properties.name[0]
                FQDN = $_.Properties.networkaddress |
                    %{if ($_ -match "ncacn_ip_tcp") {$_.split(":")[1]}}
                Roles = $_.Properties.msexchcurrentserverroles[0]
            }
        }
    }