尝试在 Powershell 中动态连接到最近的 Exchange 服务器
Trying to dynamically connect in Powershell to nearest Exchange Server
New-PSSession 需要显式 Exchange 服务器的 -ConnectionURI。我不想在脚本中硬编码名称(我们有 32 台服务器),而且我希望它成为 select 位于同一数据中心的交换。
我想要一个类似于 Get-ADDomainController -Discover -GetClosestSite 的解决方案但是我似乎希望太多了。
我想我可以提取 cn=Exchange Install Domain Servers 的成员并对它们进行一些站点相关的排名。
寻找最佳实践。
更新编辑:9/26 我已经找到了解决方案。它可能是特定于站点的,但我将在下面的答案中分享以显示最终代码。 postanote 提供的答案提供了帮助我前进的指针。
PowerShell 总体上没有官方记录的最佳实践(混合变量太多,但有些人已经将他们的想法放在主题中,例如,这个 - https://github.com/PoshCode/PowerShellPracticeAndStyle)或您向 Microsoft 提出的要求。
至于你点这里:
I suppose I can pull the members of cn=Exchange Install Domain Servers
and do some site dependent ranking on them.
这不是什么新鲜事,也不是什么棘手的事,所以你可以做到。
我的个人图书馆中有我使用的代码,可以执行此操作以及其他资源,因此我永远不必为 Exchange、SQL、DC 等硬编码服务器名称
有几个博客(已经存在一段时间了)关于这个主题的示例代码可以按原样使用或根据需要进行调整,这就是为什么我问你搜索了什么。
此处是有关如何执行此操作的博客示例之一:
https://use-powershell.blogspot.com/2012/12/find-exchange-servers-in-domain.html
提供的示例:
- 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
- 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
- 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
或者这个post:
示例:
dsquery * "cn=Configuration,dc=MyDomain,dc=com" -Filter "(objectCategory=msExchExchangeServer)"
或者,如果您真的想在给定站点中获取 Exchange 服务器,那么这已经存在。请参阅此 GitHub 来源:
https://github.com/mikepfeiffer/PowerShell/blob/master/Get-ExchangeServerInSite.ps1
提供的样本是:
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]
}
}
}
我接受 postanote 的回答是最有帮助的。
最后,我创建了一个可能特定于站点和 Exchange 安装的解决方案,但它确实说明了另一种技术。
我的约束不同于我发现并包含的大多数其他解决方案;给定用户当前在系统上没有邮箱。因此,此代码段之外的代码将收集一些数据,然后 select 一个特定的数据库。
我发现我们安装的 Exchange 服务器版本在 "CN=Exchange Install Domain Servers,CN=Microsoft Exchange System Objects," 中创建了一些记录,特别是 Members 属性有一个服务器列表。
我提取了该列表,按站点(从本地到前面)对其进行排序,然后解析 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
}
New-PSSession 需要显式 Exchange 服务器的 -ConnectionURI。我不想在脚本中硬编码名称(我们有 32 台服务器),而且我希望它成为 select 位于同一数据中心的交换。
我想要一个类似于 Get-ADDomainController -Discover -GetClosestSite 的解决方案但是我似乎希望太多了。
我想我可以提取 cn=Exchange Install Domain Servers 的成员并对它们进行一些站点相关的排名。
寻找最佳实践。
更新编辑:9/26 我已经找到了解决方案。它可能是特定于站点的,但我将在下面的答案中分享以显示最终代码。 postanote 提供的答案提供了帮助我前进的指针。
PowerShell 总体上没有官方记录的最佳实践(混合变量太多,但有些人已经将他们的想法放在主题中,例如,这个 - https://github.com/PoshCode/PowerShellPracticeAndStyle)或您向 Microsoft 提出的要求。
至于你点这里:
I suppose I can pull the members of cn=Exchange Install Domain Servers and do some site dependent ranking on them.
这不是什么新鲜事,也不是什么棘手的事,所以你可以做到。
我的个人图书馆中有我使用的代码,可以执行此操作以及其他资源,因此我永远不必为 Exchange、SQL、DC 等硬编码服务器名称
有几个博客(已经存在一段时间了)关于这个主题的示例代码可以按原样使用或根据需要进行调整,这就是为什么我问你搜索了什么。
此处是有关如何执行此操作的博客示例之一:
https://use-powershell.blogspot.com/2012/12/find-exchange-servers-in-domain.html
提供的示例:
- 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
- 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
- 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
或者这个post:
示例:
dsquery * "cn=Configuration,dc=MyDomain,dc=com" -Filter "(objectCategory=msExchExchangeServer)"
或者,如果您真的想在给定站点中获取 Exchange 服务器,那么这已经存在。请参阅此 GitHub 来源:
https://github.com/mikepfeiffer/PowerShell/blob/master/Get-ExchangeServerInSite.ps1
提供的样本是:
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]
}
}
}
我接受 postanote 的回答是最有帮助的。
最后,我创建了一个可能特定于站点和 Exchange 安装的解决方案,但它确实说明了另一种技术。
我的约束不同于我发现并包含的大多数其他解决方案;给定用户当前在系统上没有邮箱。因此,此代码段之外的代码将收集一些数据,然后 select 一个特定的数据库。
我发现我们安装的 Exchange 服务器版本在 "CN=Exchange Install Domain Servers,CN=Microsoft Exchange System Objects," 中创建了一些记录,特别是 Members 属性有一个服务器列表。 我提取了该列表,按站点(从本地到前面)对其进行排序,然后解析 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
}