IP.Tools.psm1
## Running A Build Will Compile This To A Single PSM1 File Containing All Module Code ## ## If Importing Module Source Directly, This Will Dynamically Build Root Module ## # Get list of private functions and public functions to import, in order. $Private = @(Get-ChildItem -Path $PSScriptRoot\private -Recurse -Filter "*.ps1") | Sort-Object Name $Public = @(Get-ChildItem -Path $PSScriptRoot\public -Recurse -Filter "*.ps1") | Sort-Object Name $AllMask = [Math]::Pow(2, 32) New-Variable -Name AllMask -Value $AllMask -Scope Script -Force Class IpNetwork { [ipaddress]$IpAddress [ipaddress]$IpNetmask IpNetwork ([string]$CIDR) { ($IP, $MaskLen) = $CIDR.Split('/') $IP = Get-IpNetworkBase -CIDR $CIDR Write-Verbose "IP: $($IP); Mask: $($MaskLen)" $this.IpAddress = [ipaddress]($IP) $this.IpNetmask = [ipaddress](Convert-MaskLenToIp($MaskLen)) } IpNetwork ([IpAddress]$IP, [IpAddress] $Mask) { Write-Verbose "IP: $($IP); Mask: $($Mask)" $IP = Get-IpNetworkBase -IP $IP -Mask $Mask $this.IpAddress = $IP $this.IpNetmask = $Mask } } # Dot source the private function files. foreach ($ImportItem in $Private) { try { . $ImportItem.FullName Write-Verbose -Message ("Imported private function {0}" -f $ImportItem.FullName) } catch { Write-Error -Message ("Failed to import private function {0}: {1}" -f $ImportItem.FullName, $_) } } # Dot source the public function files. foreach ($ImportItem in $Public) { try { . $ImportItem.FullName Write-Verbose -Message ("Imported public function {0}" -f $ImportItem.FullName) } catch { Write-Error -Message ("Failed to import public function {0}: {1}" -f $ImportItem.FullName, $_) } } # Export the public functions. Export-ModuleMember -Function $Public.BaseName # Private Function Example - Replace With Your Function function Add-PrivateFunction { [CmdletBinding()] Param ( # Your parameters go here... ) # Your function code goes here... Write-Output "Your private function ran!" } function Get-IpBogon { <# .SYNOPSIS Return a list of IP Bogons with [ipaddress] objects representing the IP and Mask .DESCRIPTION Return a list of IP Bogons (Internet non-routable addresses) with [ipaddress] objects representing both IP and Mask. IP Bogons are Internet non-routable addresses that are either reserved for Private use (RFC1918), or are otherwise not available. .INPUTS None .OUTPUTS Array of [ipaddress] objects representing IP Bogons. .EXAMPLE PS> $Bogons = Get-IpBogon.ps1 .LINK https://github.com/jberkers42/ip.tools #> [CmdletBinding()] $Bogons = @() $Bogons += '0.0.0.0/8' # RFC1122 "This" network $Bogons += '10.0.0.0/8' # RFC1918 Private-use networks $Bogons += '100.64.0.0/10' # RFC6598 Carrier-grade NAT $Bogons += '127.0.0.0/8' # RFC1122 IPv4 Loopback $Bogons += '169.254.0.0/16' # RFC3927 IPv4 Link local $Bogons += '172.16.0.0/12' # RFC1918 Private-use networks $Bogons += '192.0.0.0/24' # RFC5736 IETF protocol assignments $Bogons += '192.0.2.0/24' # RFC5737 TEST-NET-1 $Bogons += '192.168.0.0/16' # RFC1918 Private-use networks $Bogons += '198.18.0.0/15' # RFC2544 Network interconnect device benchmark testing $Bogons += '198.51.100.0/24' # RFC5737 TEST-NET-2 $Bogons += '203.0.113.0/24' # RFC5737 TEST-NET-3 $Bogons += '224.0.0.0/4' # RFC1112 Multicast $Bogons += '240.0.0.0/4' # Reserved for future use $BogonIps = @() foreach ($Bogon in $Bogons) { $BogonIp = [IpNetwork]::new($Bogon) $BogonIPs += $BogonIp } Write-Output $BogonIps } function Remove-IpBogon { # <# .SYNOPSIS Remove any Bogon IPs from the list of provided IPs. .DESCRIPTION Remove any Bogon IPs from the list of provided IPs. Each IP is expected to be either a dotted quad notation string representation of the address, or an [ipaddress] object. .INPUTS [IpAddress] or [string] values to filter .OUTPUTS Array of [ipaddress] objects that have had IP Bogons removed. .EXAMPLE PS> $IPs = Get-IpFromSomeSource PS> $IPs | Remove-IpBogon Obtain a list of IPs from some source (like a SIEM), and filter out the Bogon addresses .LINK https://github.com/jberkers42/ip.tools #> [cmdletbinding(SupportsShouldProcess)] param ( [Parameter(Mandatory=$true, ValueFromPipeLine=$true)] [ipaddress] $Address ) Begin { $Me = $MyInvocation.MyCommand.Name Write-Verbose $Me } Process { if ($PSCmdlet.ShouldProcess($Address, "Remove IP if Bogon")) { if (!(Test-IpBogon -Address $Address)) { Write-Output $Address } } } End { } } function Test-IpBogon { [cmdletbinding()] param ( [Parameter(Mandatory=$true, ValueFromPipeLine=$true)] [ipaddress] $Address ) Begin { $Me = $MyInvocation.MyCommand.Name Write-Verbose $Me $IpBogons = Get-IpBogon } Process { $IsBogon = $false foreach ($Bogon in $IpBogons) { if (Test-IpInNetwork -Address $Address -Network $Bogon) { $IsBogon = $true } } Write-Output $IsBogon } End { Clear-Variable 'IpBogons' } } function Convert-MaskLenToIp { <# .SYNOPSIS Convert MaskLen from CIDR Notation (IP/MaskLen) to an IP Address object .DESCRIPTION Convert MaskLen from CIDR Notation (IP/MaskLen) to an IP Address object .PARAMETER MaskLen Integer value representing the mask length .INPUTS Integer Mask Lenth .OUTPUTS [ipaddress] object representing the Netmask .EXAMPLE Pass a single MaskLen as a parameter PS> Convert-MaskLenToIp -MaskLen 24 AddressFamily : InterNetwork ScopeId : IsIPv6Multicast : False IsIPv6LinkLocal : False IsIPv6SiteLocal : False IsIPv6Teredo : False IsIPv6UniqueLocal : False IsIPv4MappedToIPv6 : False Address : 16777215 IPAddressToString : 255.255.255.0 .EXAMPLE Use Pipeline to convert MaskLen to IP Address PS> 27 | Convert-MaskLenToIp AddressFamily : InterNetwork ScopeId : IsIPv6Multicast : False IsIPv6LinkLocal : False IsIPv6SiteLocal : False IsIPv6Teredo : False IsIPv6UniqueLocal : False IsIPv4MappedToIPv6 : False Address : 3774873599 IPAddressToString : 255.255.255.224 .LINK https://github.com/jberkers42/ip.tools #> [CmdletBinding()] [OutputType([ipaddress])] param( [Parameter(Mandatory=$true, ValueFromPipeLine=$true)] [ValidateRange([int]0, [int]32)] [int]$MaskLen ) Begin { $Me = $MyInvocation.MyCommand.Name Write-Verbose $Me } Process { [ipaddress]($AllMask - ($AllMask -shr $MaskLen)) } End { } } function Get-IpNetworkBase { <# .SYNOPSIS Get the Base Network address for the supplied IP/Mask .DESCRIPTION Get the Base Network address for the supplied IP/Mask .PARAMETER CIDR [string] containing CIDR notation for network address .PARAMETER IP [IPAddress] object or Dotted Quad notation string representing the IP address .PARAMETER Mask [IpNetwork] Object or Dotted Quad notation string representing the Netmask .INPUTS CIDR Strings .OUTPUTS [IpAddress] Object .EXAMPLE PS> (Get-IpNetworkBase -CIDR 192.168.100.20/24).IPAddressToString 192.168.100.0 .EXAMPLE Use Pipeline to convert MaskLen to IP Address PS> 27 | Convert-MaskLenToIp .LINK https://github.com/jberkers42/ip.tools #> [CmdletBinding(DefaultParameterSetName = 'CIDR')] [OutputType([IpAddress])] param( [Parameter(ParameterSetName='CIDR', Mandatory=$true, Position = 0, ValueFromPipeline=$true)] [string] $CIDR, [Parameter(ParameterSetName='IpMask', Mandatory=$true, Position = 0)] [IpAddress] $IP, [Parameter(ParameterSetName='IpMask', Mandatory=$true, Position = 1)] [IpAddress] $Mask ) Begin { $Me = $MyInvocation.MyCommand.Name Write-Verbose $Me } Process { If ($PSCmdlet.ParameterSetName -eq "CIDR") { ([IpAddress]$IP, $MaskLen) = $CIDR -split '/' [IpAddress]$Mask = Convert-MaskLenToIp $MaskLen } Write-Verbose "IP: $($IP); Mask: $($Mask);" [IpAddress]$Net = ($IP.Address -band $Mask.Address) return $Net } End { } } function New-IpNetwork { <# .SYNOPSIS Create a new IpNetwork object with the specified CIDR or IP and Mask parameters .DESCRIPTION Create a new IpNetwork object with the specified CIDR or IP and Mask parameters .PARAMETER CIDR [string] containing CIDR notation for network .PARAMETER IP [IPAddress] object or Dotted Quad notation string representing the IP address .PARAMETER Mask [IpNetwork] Object or Dotted Quad notation string representing the Netmask .INPUTS CIDR Strings .OUTPUTS [IpNetwork] Object .EXAMPLE PS> $Network = PS> Test-IpInNetwork -Address 192.168.100.20 -Network .EXAMPLE Use Pipeline to convert MaskLen to IP Address PS> 27 | Convert-MaskLenToIp .LINK https://github.com/jberkers42/ip.tools #> [CmdletBinding(DefaultParameterSetName = 'CIDR', SupportsShouldProcess)] param( [Parameter(ParameterSetName='CIDR', Mandatory=$true, Position = 0, ValueFromPipeline=$true)] [string] $CIDR, [Parameter(ParameterSetName='IpMask', Mandatory=$true, Position = 0)] [string] $IP, [Parameter(ParameterSetName='IpMask', Mandatory=$true, Position = 1)] [string] $Mask ) Begin { $Me = $MyInvocation.MyCommand.Name Write-Verbose $Me } Process { if ($PSCmdlet.ShouldProcess("IpNetwork", "Return new IP Network from CIDR or IP and Mask")) { Switch ($PSCmdlet.ParameterSetName) { "CIDR" { return [IpNetwork]::new($CIDR) } "IpMask" { return [IpNetwork]::new($IP, $Mask) } } } } End { } } function Test-IpInNetwork { <# .SYNOPSIS Test if an IP address exists in the specified network .DESCRIPTION Test if an IP address exists in the specified network .PARAMETER Address [IPAddress] object or Dotted Quad notation string representing the IP address to test .PARAMETER Network [IpNetwork] Object consisting of IpAddress and IpNetmask to check if IP belongs. If supplied as string, will be converted to IpNetwork before testing. .INPUTS IP Addresses and networks. .OUTPUTS [bool] result of test .EXAMPLE PS> $Network = New-IpNetwork "192.168.100.0/24" PS> Test-IpInNetwork -Address 192.168.100.20 -Network $Network .EXAMPLE Use Pipeline to convert MaskLen to IP Address PS> 27 | Convert-MaskLenToIp .LINK https://github.com/jberkers42/ip.tools #> [cmdletbinding()] param ( [Parameter(Mandatory=$true, ValueFromPipeLine=$true)] [ipaddress] $Address, [Parameter(Mandatory=$true, ValueFromPipeline=$true)] [ValidateScript({ $TypeName = $_ | Get-Member | Select-Object -ExpandProperty TypeName -Unique if ($TypeName -eq 'System.String' -and $_ -match "(\d{1,3}\.){3}\d{1,3}\/\d{1,2}") { Write-Verbose "Convert From String: $_" New-IpNetwork $_ } elseif ($TypeName -eq 'IpNetwork') { Write-Verbose "Taken as IpNetwork Object $_" $_ } })] $Network ) Begin { $Me = $MyInvocation.MyCommand.Name Write-Verbose $Me } Process { Write-Verbose "Network To Test: $Network" if ($Network.GetType().Name -eq 'String') { $Network = New-IpNetwork -CIDR $Network } if ($Network.IpAddress.Address -eq ($Address.Address -band $Network.IpNetmask.Address)) { Write-Output $true } else { Write-Output $false } } End { } } Export-ModuleMember -Function Get-IpBogon, Remove-IpBogon, Test-IpBogon, Convert-MaskLenToIp, Get-IpNetworkBase, New-IpNetwork, Test-IpInNetwork |