正在尝试在Powershell中动态连接到最近的Exchange服务器

正在尝试在Powershell中动态连接到最近的Exchange服务器,powershell,exchange-server,Powershell,Exchange Server,新的PSSession需要一个explict Exchange服务器的-ConnectionURI。我不想在脚本中硬编码名称(我们有32台服务器),而且我希望它选择同一数据中心中的一个exchange 我想要一个类似于Get-AddomaInControl-Discover-GetClosesSite的解决方案,但似乎我希望的太多了 我想我可以拉cn=Exchange的成员安装域服务器,并对它们进行一些站点相关的排名 寻找最佳实践 更新编辑:9/26我已经找到了一个解决方案。它可能是特定于站点的

新的PSSession需要一个explict Exchange服务器的-ConnectionURI。我不想在脚本中硬编码名称(我们有32台服务器),而且我希望它选择同一数据中心中的一个exchange

我想要一个类似于Get-AddomaInControl-Discover-GetClosesSite的解决方案,但似乎我希望的太多了

我想我可以拉cn=Exchange的成员安装域服务器,并对它们进行一些站点相关的排名

寻找最佳实践


更新编辑:9/26我已经找到了一个解决方案。它可能是特定于站点的,但我将在下面的答案中分享,以显示最终代码。postanote提供的答案提供了帮助我向前迈进的指针。

一般来说,没有官方文档记录的PowerShell最佳实践(组合中的变量太多,但有些人已经将他们的想法放在了主题中,例如,这一个),或者您希望从Microsoft获得什么

关于你在这里的观点:

我想我可以拉cn=Exchange的成员安装域服务器 并做一些网站依赖于他们的排名

这不是什么新鲜事,也不是什么棘手的事,所以你可以这样做

我在我的个人库中有代码,我可以使用这些代码来完成这项工作,也可以用于其他doing资源,因此我永远不必硬编码Exchange、SQL、DC等的服务器名称

关于这个主题有几个博客(已经有一段时间了),其中有示例代码可以按原样使用或根据需要调整,这就是为什么我问你搜索了什么

如何做到这一点的博客示例如下:

提供的例子如下:

  • 具有邮箱的active directory用户将具有2个属性(msExchHomeServerName和homemdb),其中包含 拥有邮箱的邮箱服务器-一旦连接到您需要的一台服务器 可以使用exchange控制台查找其余的
  • active directory计算机类型对象在servicePrincipalName属性中包含“exchange”字;您只能使用您的 包含服务器的组织单位(如果有) 缩小搜索范围:
  • active directory配置分区包含有关域中exchange服务器的信息;您可以搜索类的对象 msExchExchangeServer:
  • 或者您可以列出“CN=服务器,CN=第一个管理组,CN=管理组,CN=内部,CN=Microsoft”中的所有对象 Exchange,CN=Services,CN=Configuration,DC=domainname,DC=net“使用 powershell或ADSI编辑控制台

    或本帖:

    例如:

    dsquery * "cn=Configuration,dc=MyDomain,dc=com" -Filter "(objectCategory=msExchExchangeServer)"
    
    或者,如果您确实要在给定站点中获取Exchange服务器,则该服务器已存在。请参阅此GitHub源代码:

    提供的样本是:

    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]
            }
        }
    }
    

    我接受邮资通知的答复,认为这是最有帮助的

    最后,我创建了一个解决方案,它可能是特定于站点和Exchange安装的,但它确实说明了另一种技术

    我的约束条件不同于我发现并包括的大多数其他解决方案;指定用户当前在系统上没有邮箱。因此,此代码段之外的代码将收集一些数据,然后选择特定的数据库

    我发现我们安装的Exchange server版本在“CN=Exchange安装域服务器,CN=Microsoft Exchange系统对象”中创建了一些记录,特别是“成员”属性有一个服务器列表。 我提取了该列表,按站点(从本地到前端)对其进行排序,然后解析FQDN以形成要连接的URI

    Function Connect-Exchange {
         #  Find servers list, then sort by name given what site we are running in:  SITE1 = Ascending , SITE2 = Descending
         $ADSite = (Get-ADDomainController).Site
         if ($ADSite -like "SITE1*") { $descOrder =  $true } else { $descOrder = $false }
         $exchSession = $null                                     
         $ExchServersDN = "CN=Exchange Install Domain Servers,CN=Microsoft Exchange System Objects,DC=example,DC=com”
         $ExchServers = (Get-ADObject -Identity $($ExchServersDN) -Properties Member).Member | Sort-Object -Descending:$descOrder 
    
         # Iterate through Exchange server list until connection succeeds
         $i = 0;
         while ((-Not $exchSession) -and ($i -lt $ExchServers.Count)) { 
            $ExchServerURI = "http://" + (Get-ADObject -Identity $ExchServers[$i] -Properties dNSHostName).dnsHostName + "/Powershell"
            $exchSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionURI $ExchServerURI  -ErrorAction SilentlyContinue
            If (-Not $exchSession)  { $i++ }
            else {                                                                 
                Import-PSSession $exchSession -DisableNameChecking | Out-Null
            }
         }
         return $exchSession
    }
    

    谢谢你的评论。。。你说这个问题并不新鲜,但我还没有通过无数的Google和StackExchange搜索成功地找到任何相关信息。我会看看你的链接。在我的场景中,另一个问题是,这是一个入职前的情况。我们尚未为用户创建邮箱。因此,任何基于查找现有用户的方法也没有用。我们正在尝试运行一些大小度量,以尝试平衡我们将在哪个邮箱中创建用户。不用担心会发生这种情况。大多数时候,它只是在琴弦的各个部分循环,以获得你想要的点击。大多数情况下,你会碰到偏音,然后你必须扩展它。几年前,当我第一次尝试做这种用例时,我必须这样做,才能了解其他人已经尝试过、失败过、成功过的东西。当然,一开始我从未得到完整的答案,但改变问题的方向,让我得到了我需要的,解决我需要的。我在回复中提供的是我传递给我的队友和尝试做这件事的客户的正常样本。至于您的项目:“我们尚未为用户创建邮箱。因此,任何基于查找现有用户的方法也没有用。我们正在尝试运行一些大小调整指标,以尝试平衡我们将在哪个邮箱中创建用户。“,然后最后一段代码应该会让您达到您想要的位置。
    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 
    
    dsquery * "cn=Configuration,dc=MyDomain,dc=com" -Filter "(objectCategory=msExchExchangeServer)"
    
    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]
            }
        }
    }
    
    Function Connect-Exchange {
         #  Find servers list, then sort by name given what site we are running in:  SITE1 = Ascending , SITE2 = Descending
         $ADSite = (Get-ADDomainController).Site
         if ($ADSite -like "SITE1*") { $descOrder =  $true } else { $descOrder = $false }
         $exchSession = $null                                     
         $ExchServersDN = "CN=Exchange Install Domain Servers,CN=Microsoft Exchange System Objects,DC=example,DC=com”
         $ExchServers = (Get-ADObject -Identity $($ExchServersDN) -Properties Member).Member | Sort-Object -Descending:$descOrder 
    
         # Iterate through Exchange server list until connection succeeds
         $i = 0;
         while ((-Not $exchSession) -and ($i -lt $ExchServers.Count)) { 
            $ExchServerURI = "http://" + (Get-ADObject -Identity $ExchServers[$i] -Properties dNSHostName).dnsHostName + "/Powershell"
            $exchSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionURI $ExchServerURI  -ErrorAction SilentlyContinue
            If (-Not $exchSession)  { $i++ }
            else {                                                                 
                Import-PSSession $exchSession -DisableNameChecking | Out-Null
            }
         }
         return $exchSession
    }