Public/Resolve-IPv4Address.ps1
$dotnetclass = @"
public class SubnetInformation { public SubnetInformation() { } public string AddressValueSupplied { get; set; } public string AddressFormatSupplied { get; set; } public string IPAddress { get; set; } public string Subnet { get; set; } public string SubnetMask { get; set; } public int SubnetMaskLength { get; set; } public string BroadcastAddress { get; set; } public int NumberOfHosts { get; set; } public string FirstHostAddress { get; set; } public string LastHostAddress { get; set; } public string AddressClassification { get; set; } public string AddressSpaceClassification { get; set; } public object GeoInformation { get; set; } public override string ToString() { return Subnet + "/" + SubnetMaskLength.ToString(); } } "@ Add-Type -TypeDefinition $dotnetclass <# .SYNOPSIS Resolves the subnet definition of a given IPv4 address and subnet mask. An optional geoinformation can be obtained (requires Internet access). .DESCRIPTION Resolves the subnet definition of a given IPv4 address and, optionally, subnet mask. An optional geoinformation can be obtained (requires Internet access). The subnet definition includes: - Subnet address - mask and mask length - broadcast address - number of usable host addresses (none for /31 mask) - the first and last available host address - classification of the supplied address within the subnet (host/subnet/braodcast) - classification of the supplied address within the IPv4 address space (public/private/reserved/other...) - geoinformation about the specified address, if it was classified as 'Public' and the switch -IncludeGeoInformation was given. The geoinformation is obtained from http://ip-api.com. If only an IP address, without a mask, was given, the subnet definition will return: - a Class A/B/C subnet for private IP addresses - a /32 subnet for any other address classes .PARAMETER IPAddress One or more IPv4 address definitions in form IP.IP.IP.IP, IP.IP.IP.IP/MASK or IP.IP.IP.IP/SM.SM.SM.SM .PARAMETER IncludeGeoInformation If specified, an attempt will be made to connect to ip-api.com and retrieve the geo information about the address. .EXAMPLE '8.8.8.8','141.20.1.3' | Resolve-IPv4Address -IncludeGeoInformation Returns a /32 subnet and geoinformation for both specified public addresses. .EXAMPLE Resolve-IPv4Address -IPAddress '10.0.101.22/22 Returns a complete subnet definition, without geoinformation, for the specified address. .EXAMPLE Resolve-IPv4Address -IPAddress '192.168.178.223/255.255.255.128' -IncludeGeoInformation Returns a complete subnet definition for the specified address. No geoinformation will be returned, despite the switch, because the address is clissifed as 'Private' in the IPv4 address space. .INPUTS String[] .OUTPUTS SubnetInformation #> function Resolve-IPv4Address { [CmdletBinding()] Param( [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true, HelpMessage="Enter one or more IPv4 address definitions, separated by commas.")] [string[]]$IPAddress, [Parameter(Mandatory=$false)] [switch]$IncludeGeoInformation ) Begin {} Process { foreach ($currentIPAddress in $IPAddress) { $addressFormat = 'UNKNOWN' $Address = $null $SubnetMask = $null $MaskLength = -1 switch -Regex ($currentIPAddress) { '^(?<ip>(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\/(?<mask>(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))$' { $Address = $Matches['ip'] $SubnetMask = $Matches['mask'] if (Test-IPAX4SubnetMask -SubnetMask $SubnetMask) { $MaskLength = Get-IPAX4SubnetMaskLength -SubnetMask $SubnetMask $addressFormat = 'ADDRANDMASK' } else { Write-Warning ('Subnet mask {0} not valid!' -f $SubnetMask) $Address = $null $SubnetMask = $null $addressFormat = 'INVALID' } } '^(?<ip>(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\/(?<masklen>(?:3[0-2]|2[0-9]|1[0-9]|[0-9]))$' { $Address = $Matches['ip'] $MaskLength = $Matches['masklen'] $SubnetMask = Get-IPAX4SubnetMask -SubnetMaskLength $MaskLength $addressFormat = 'ADDRANDLEN' } '^(?<ip>(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))$' { $Address = $Matches['ip'] $decimalAddress = Convert-V4DottedToInt -InputString $Address if (($decimalAddress -le 184549375) -and ($decimalAddress -ge 167772160)) { $MaskLength = 8 } elseif (($decimalAddress -le 2887778303) -and ($decimalAddress -ge 2886729728)) { $MaskLength = 16 } elseif (($decimalAddress -le 3232301055) -and ($decimalAddress -ge 3232235520)) { $MaskLength = 24 } else { $MaskLength = 32 } $SubnetMask = Get-IPAX4SubnetMask -SubnetMaskLength $MaskLength $addressFormat = 'ADDRONLY' } } if ($null -ne $Address) { $ipval = Convert-V4DottedToInt -InputString $Address $snval = Convert-V4DottedToInt -InputString $SubnetMask $snaddr = $ipval -band $snval if ($MaskLength -eq 32) { $firstip = Convert-IntToV4Dotted $snaddr $lastip = Convert-IntToV4Dotted $snaddr $numaddr = 1 $bcaddr = $snaddr $acl = 'Host' } elseif ($MaskLength -eq 31) { $firstip = $null $lastip = $null $numaddr = 0 $bcaddr = $snaddr + 1 if ($ipval -eq $snaddr) { $acl = 'Subnet' } else { $acl = 'Broadcast' } } else { $firstip = Convert-IntToV4Dotted ($snaddr + 1) $numaddr = [math]::Pow(2,(32 - $MaskLength)) - 2 $lastip = Convert-IntToV4Dotted ($snaddr + $numaddr) $bcaddr = $snaddr + $numaddr + 1 if ($ipval -eq $snaddr) { $acl = 'Subnet' } elseif ($ipval -eq $bcaddr) { $acl = 'Broadcast' } else { $acl = 'Host' } } $classification = Get-IPAX4Classification -IPAddress $Address $result = [SubnetInformation]::new() $result.AddressValueSupplied = $currentIPAddress $result.AddressFormatSupplied = $addressFormat $result.IPAddress = $Address $result.Subnet = Convert-IntToV4Dotted $snaddr $result.SubnetMask = $SubnetMask $result.SubnetMaskLength = $MaskLength $result.BroadcastAddress = Convert-IntToV4Dotted $bcaddr $result.NumberOfHosts = $numaddr $result.FirstHostAddress = $firstip $result.LastHostAddress = $lastip $result.AddressClassification = $acl $result.AddressSpaceClassification = $classification if ($IncludeGeoInformation -and ($classification -eq 'Public')) { $result.GeoInformation = Get-IPAXGeoInformation -IPAddress $Address } } else { if ($addressFormat -eq 'UNKNOWN') { Write-Warning "Unknown address format: '$currentIPAddress'" } $result = $null } $result } } End {} } |