Get remote server names from receive connector

I was asked to make a list of all remote servers (including IP addresses) which are able to use a receive connector in Exchange 2010.

2013-08-21 00_59_27

The remote IP addreses of the receive connector can be found under RemoteIPRanges property of Get-ReceiveConnector cmdlet. Those addreses can be devided based on RangeFormat declaration:

  • SingleAddress (10.10.10.5)
  • CIDR (10.10.10.5/24)
  • LoHi (10.10.10.5-10.10.10.10)

Theoretically if we need to get all IP addresses, we have to know also IP addresses in particular ranges and then we can resolve those addreses in DNS.

Here are two functions. The first one (New-IPRange) is created by Dr.Tobias Weltner and ensures us to find all IP addresses (also from CIDR or LoHi ranges). The second one is my helper (Get-ReceiveConnectorRemoteIPName) which goes through RemoteIPRanges, calls the first function and resolves IP address by System.Net.Dns .NET class. The processing time depends on amount of IP addreses so be careful about your ranges!

function New-IPRange ($start, $end) {
 # created by Dr. Tobias Weltner, MVP PowerShell
 $ip1 = ([System.Net.IPAddress]$start).GetAddressBytes()
 [Array]::Reverse($ip1)
 $ip1 = ([System.Net.IPAddress]($ip1 -join '.')).Address
 $ip2 = ([System.Net.IPAddress]$end).GetAddressBytes()
 [Array]::Reverse($ip2)
 $ip2 = ([System.Net.IPAddress]($ip2 -join '.')).Address
 for ($x=$ip1; $x -le $ip2; $x++) {
 $ip = ([System.Net.IPAddress]$x).GetAddressBytes()
 [Array]::Reverse($ip)
 $ip -join '.'
 }
}

function Get-ReceiveConnectorRemoteIPName ($Identity) {
 $Connector = Get-ReceiveConnector -identity $Identity | select Identity,RemoteIPRanges
 if($Connector -ne $null){
 $IPs = $Connector.RemoteIPRanges | % { New-IPRange $_.LowerBound $_.UpperBound }
 foreach($IP in $IPs){
 $Output = New-Object PSObject
 $IPName = ([Net.DNS]::GetHostEntry("$ip")).HostName
 if($IPName -eq $IP){$IPName="unresolvable"}
 $output | add-member -Type NoteProperty -name “ReceiveConnector” -value $Connector.Identity
 $output | add-member -Type NoteProperty -name “RemoteIp” -value $IP
 $output | add-member -Type NoteProperty -name “RemoteName” -value $IPName
 $output
 }
 }
}

How to use it? Only paste both functions into EMS, that’s it.

2013-08-21 00_44_51

Now you are ready to use both functions especially Get-ReceiveConnectorRemoteIPName:

[PS] C:\>Get-ReceiveConnectorRemoteIPName "EX2010S01\Application Relay"

ReceiveConnector             RemoteIp    RemoteName
----------------             --------    ----------
EX2010S01\Application Relay  10.10.1.16  appolo.ficility.intra
EX2010S01\Application Relay  10.10.2.2   helt01.ficility.intra
EX2010S01\Application Relay  10.10.2.3   unresolvable
EX2010S01\Application Relay  10.10.2.4   unresolvable
EX2010S01\Application Relay  10.10.1.25  kepro.ficility.intra

2013-08-21 01_54_48

Feel free to use Get-ReceiveConnectorRemoteIPName cmdlet in the following scenarios:

[PS] C:\> Get-ReceiveConnectorRemoteIPName "EX2010S01\Application Relay"| Export-Csv -Path "C:\ReceiveConnectorRemoteIPName.csv"

[PS] C:\> $connectors = Get-ReceiveConnector | ? { $_.identity -like "*relay*" }
[PS] C:\> $connectors| % { Get-ReceiveConnectorRemoteIPName $_.identity }
Advertisements

PowerShell – Functions and examples how to work with IP addresses (IPv4)

The IP addreass can be declared by data type System.Net.IPAddress. These examples are equivalent:

[System.Net.IPAddress]$Address = "192.168.23.12"
[IPAddress]$Address = "192.168.23.12"

$Address object contains:

Address : 202877120
AddressFamily : InterNetwork
ScopeId :
IsIPv6Multicast : False
IsIPv6LinkLocal : False
IsIPv6SiteLocal : False
IsIPv6Teredo : False
IPAddressToString : 192.168.23.12

TypeName: System.Net.IPAddress
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object comparand)
GetAddressBytes Method byte[] GetAddressBytes()
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Address Property long Address {get;set;}
AddressFamily Property System.Net.Sockets.AddressFamily AddressFamily {get;}
IsIPv6LinkLocal Property bool IsIPv6LinkLocal {get;}
IsIPv6Multicast Property bool IsIPv6Multicast {get;}
IsIPv6SiteLocal Property bool IsIPv6SiteLocal {get;}
IsIPv6Teredo Property bool IsIPv6Teredo {get;}
ScopeId Property long ScopeId {get;set;}
IPAddressToString ScriptProperty System.Object IPAddressToString {get=$this.Tostring();}

As can be seen the IPAddress Class has some limitation for advanced tasks, but the following article uses its functionality really nice related to breaking up decimals in low-/high-bytes and creating IP address ranges (http://powershell.com/cs/blogs/tobias/archive/2011/02/20/creating-ip-ranges-and-other-type-magic.aspx)

New-IPRange

function New-IPRange ($start, $end) {
 # created by Dr. Tobias Weltner, MVP PowerShell
 $ip1 = ([System.Net.IPAddress]$start).GetAddressBytes()
 [Array]::Reverse($ip1)
 $ip1 = ([System.Net.IPAddress]($ip1 -join '.')).Address
 $ip2 = ([System.Net.IPAddress]$end).GetAddressBytes()
 [Array]::Reverse($ip2)
 $ip2 = ([System.Net.IPAddress]($ip2 -join '.')).Address
 for ($x=$ip1; $x -le $ip2; $x++) {
 $ip = ([System.Net.IPAddress]$x).GetAddressBytes()
 [Array]::Reverse($ip)
 $ip -join '.'
 }
}

New-IPRange

Do not use  “0.0.0.0”  and “255.255.255.255” because you will wait on 4294967296 addresses :-).

Of course we can specify IP range through  Microsoft.Exchange.Data.IPRange:

LowerBound : 157.144.33.22
UpperBound : 157.144.33.22
Netmask :
CIDRLength :
RangeFormat : SingleAddress
Size : ::1

LowerBound : 157.144.202.0
UpperBound : 157.144.202.127
Netmask : 255.255.255.128
CIDRLength : 25
RangeFormat : CIDR
Size : ::80

TypeName: Microsoft.Exchange.Data.IPRange

Name MemberType Definition
---- ---------- ----------
CompareTo Method int CompareTo(Microsoft.Exchange.Data.IPRange x)
Contains Method bool Contains(ipaddress ipAddress), bool Contains(Microsoft.Exchange.Data.IPvxAddress ipAddress)
Equals Method bool Equals(System.Object obj), bool Equals(Microsoft.Exchange.Data.IPRange other)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
CIDRLength Property System.Int16 CIDRLength {get;}
LowerBound Property Microsoft.Exchange.Data.IPvxAddress LowerBound {get;}
Netmask Property System.Net.IPAddress Netmask {get;}
RangeFormat Property Microsoft.Exchange.Data.IPRange+Format RangeFormat {get;}
Size Property Microsoft.Exchange.Data.IPvxAddress Size {get;}
UpperBound Property Microsoft.Exchange.Data.IPvxAddress UpperBound {get;}

But I would like to  focus on converting numbers to binary and back (http://www.powershellmagazine.com/2012/10/16/converting-numbers-to-binary-and-back/) because it is basic principle for network addressing.

New-IPv4toBin

function New-IPv4toBin ($ipv4){
 $BinNum = $ipv4 -split '\.' | ForEach-Object {[System.Convert]::ToString($_,2).PadLeft(8,'0')}
 return $binNum -join ""
}

New-IPv4toBin

New-CidrToBin

function New-CidrToBin ($cidr){
 if($cidr -le 32){
 [Int[]]$array = (1..32)
 for($i=0;$i -lt $array.length;$i++){
 if($array[$i] -gt $cidr){$array[$i]="0"}else{$array[$i]="1"}
 }
 $cidr =$array -join ""
 }
 return $cidr
}

New-CidrToBinGet-Broadcast (require New-IPv4toBin)

function Get-Broadcast ($addressAndCidr){
 $addressAndCidr = $addressAndCidr.Split("/")
 $addressInBin = (New-IPv4toBin $addressAndCidr[0]).ToCharArray()
 for($i=0;$i -lt $addressInBin.length;$i++){
 if($i -ge $addressAndCidr[1]){
 $addressInBin[$i] = "1"
 } 
 }
 [string[]]$addressInInt32 = @()
 for ($i = 0;$i -lt $addressInBin.length;$i++) {
 $partAddressInBin += $addressInBin[$i] 
 if(($i+1)%8 -eq 0){
 $partAddressInBin = $partAddressInBin -join ""
 $addressInInt32 += [Convert]::ToInt32($partAddressInBin -join "",2)
 $partAddressInBin = ""
 }
 }
 $addressInInt32 = $addressInInt32 -join "."
 return $addressInInt32
}

Get-BroadcastTest-IPinIPRange (require New-IPv4toBin)

function Test-IPinIPRange ($Address,$Lower,$Mask) {
 [Char[]]$a = (New-IPv4toBin $Lower).ToCharArray()
 if($mask -like "*.*"){
 [Char[]]$b = (New-IPv4toBin $Mask).ToCharArray()
 }else{
 [Int[]]$array = (1..32)
 for($i=0;$i -lt $array.length;$i++){
 if($array[$i] -gt $mask){$array[$i]="0"}else{$array[$i]="1"}
 }
 [string]$mask = $array -join ""
 [Char[]]$b = $mask.ToCharArray()
 }
 [Char[]]$c = (New-IPv4toBin $Address).ToCharArray()
 $res = $true
 for($i=0;$i -le $a.length;$i++){
 if($a[$i] -ne $c[$i] -and $b[$i] -ne "0"){
 $res = $false
 } 
 }
 return $res
}

The first IP address is checked regarding IP range (IP,mask or IP,cidr)

Test-IPinIPRange

New-IPv4fromBin

function New-IPv4fromBin($addressInBin){
 [string[]]$addressInInt32 = @()
 $addressInBin = $addressInBin.ToCharArray()
 for ($i = 0;$i -lt $addressInBin.length;$i++) {
 $partAddressInBin += $addressInBin[$i] 
 if(($i+1)%8 -eq 0){
 $partAddressInBin = $partAddressInBin -join ""
 $addressInInt32 += [Convert]::ToInt32($partAddressInBin -join "",2)
 $partAddressInBin = ""
 }
 }
 $addressInInt32 = $addressInInt32 -join "."
 return $addressInInt32
}

New-IPv4fromBinAdvanced examples:

IPAddressExamplesDownload: IPAddressFunctions.ps1 (click for content)

How to load all functions above into Powershell:

FilePathLoadPS1