Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Pulls a list of IPs which have been whitelisted by receive connectors for a given SMTP server name. Compares those lists between the nodes to ensure that all nodes under the server have the same whitelists. This is very rough at present; but hopefully helps a few people out of a hole. This does not require any Exchange mangement tools/features t…
#get a list of all receive connectors
[string[]]$smtpServers = ('mySmtpRelayServerName')
[string]$server1Name = '' #for ease just using the FQDNs; we could have code to do a [System.Net.Dns]::Resolve before using if we wanted to allow short names
[string]$server2Name = ''
[string]$OutFile = '.\WhitelistComparison.csv'
[string]$searchBase = ([ADSI] "LDAP://RootDSE").configurationNamingContext.ToString()
import-module 'ActiveDirectory'
function Get-AdConfigurationNamingContext {
param ()
process {
([ADSI] "LDAP://RootDSE").configurationNamingContext.ToString()
function Get-ReceiveConnectorForHost {
param (
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
[string]$SearchBase = (Get-AdConfigurationNamingContext)
process {
[System.Net.IPHostEntry]$smtpServer = [System.Net.Dns]::Resolve($SmtpServerHostname)
Get-AdObject -filter {(objectClass -eq 'msExchSmtpReceiveConnector') -and (msExchSMTPReceiveConnectorFQDN -eq $smtpServer.HostName)} -SearchBase $searchBase -Properties 'msExchSmtpReceiveRemoteIPRanges' | %{
(New-Object -TypeName PSObject -Property @{
Host = $smtpServer #this is the name of the SMTP server and/or cluster
Node = ([System.Net.Dns]::Resolve(($_.DistinguishedName -replace '.+,CN=Protocols,CN=(.+?),CN=Servers,.+','$1'))) #this is the name of the server or cluster node to which this rule applies
ReceiveConnector = $_ # this is the rule
$connectors = $smtpServers | Get-ReceiveConnectorForHost
#here we get a bit specific; as I had to knock this up quickly... could easily improve to compare all nodes in all clusters. May be an issue where the same smtp is referred to by mutiple cnames, but can use IPs to work around that.
#may also be an issue distinguishing the ALLOWs vs the DENIES; as couldn't find a good property for that / the only sign was that DENY tends to just have the value
$server1 = $connectors | ?{$_.Node.Hostname -eq $server1Name} | Select -first 1
$server2 = $connectors | ?{$_.Node.Hostname -eq $server2Name} | Select -first 1
Compare-Object -ReferenceObject ($server1.ReceiveConnector.msExchSmtpReceiveRemoteIPRanges) -DifferenceObject ($server2.ReceiveConnector.msExchSmtpReceiveRemoteIPRanges) -IncludeEqual | %{
(New-Object -TypeName PSObject -Property @{
IP = $_.InputObject
Action = switch ($_.SideIndicator) {
'==' {'no action required'; break;}
'<=' {"Add to server2Name"; break;}
'=>' {"Add to server1Name"; break;}
} | sort Action, IP | Export-Csv -Path $OutFile -NoTypeInformation -Encoding UTF8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment