Welcome to ThePowerShellGuy.com Sign in | Join | Help

Finding a Range of IP addresses

A recent question in Microsoft.public.windows.powershell asked for ideas on working with a range of IP addresses expressed in CIDR notation (192.168.1.0/24). The intent is to get a list of IP addresses inside the range. I posted a small sample in the group, but here is one that’s cleaned up a little bit and will accept pipeline input. You can see the original usenet article here.

Get-IPRange supports input in the standard CIDR notation which looks like 192.168.1.0/24 or 10.132.0.0/16, etc. It also supports 3 switches that allow you to control how the results are returned.

                -AsString – Returns string representation of the IP in Dot-Decimal Format (i.e. “192.168.1.1”)

                -AsDecimal – Returns decimal representation of the  IP (I.e. 3232235777)

                -AsIPAddress – Returns a [System.Net.IPAddress] object representing the IP address. This is the default if no other switches are specified.

You can also pass the IP Range via the –IPAddress parameter or via the Pipeline. Examples of each:

Get-IPRange –IPAddress “192.168.1.1/24

 

192.168.1.0/24”,”192.168.10.0/22” | Get-IPRange

Here is the function. Feel free to let me know of any bugs, but be gentle as I know I'm not validating a lot of the input :)

Function Get-IPRange {

    param([string]$ipaddress="",[switch]$AsString,[switch]$AsDecimal,[switch]$AsIPAddress)

   

    begin {

        # support functions

        function ToDecimal {

            # Convert a string IP ("192.168.1.1") to it's Decimal Equivalent

            # Convert a Binary IP ("11011011111101011101110001111111") to it's Decimal Equivalent

            param([string]$paddress)

           

            if ($paddress.length -gt 15) {

                # Possibly Binary as it's too long for Dot-Decimal

                return [system.Convert]::ToInt64($paddress.replace(".",""),2)

            } else {

                # Possibly Dot-Decimal.

                # Converting an IP address to decimal involves shifting bits

                # for each octect. Powershell doesn't have any bit shifting operators

                # so we'll use some math (YUCK!)

                [byte[]]$b = ([system.Net.IPAddress]::Parse($paddress)).GetAddressBytes()

                $longip = 0

                for ($i = 0; $i -lt 4; $i++) {

                    $num = $b[$i]

                    $longip += (($num % 256) * ([math]::pow(256,3-$i)))

                }

                return [int64]$longip

            }

        }

       

        function ToIP {

            param ($paddress)

           

            if ($paddress.Length -gt 15) {

                # Possibly Binary as it's too long for Decimal

                # If it's not a string, it'll also fail this test

                 return [system.Net.IPAddress]::Parse( (ToDecimal $paddress) )

            } else {

                # Most likely Decimal which the Parse method understands on its own.

                return [system.Net.IPAddress]::Parse($paddress)

            }

        }

       

        function ToBinary {

            param($paddress)

           

            if ($paddress.GetType().Name -eq "string") {

                #Dot-Decimal

                return ([system.Convert]::ToString((ToDecimal $paddress),2)).padleft(32,[char]"0")

            } else {

                #Decimal

                return ([system.Convert]::ToString($paddress,2)).padleft(32,[char]"0")

            }

        }

 

        function SplitAddress {

            param([string]$paddress)

            $address = ($paddress.split("/")[0])

            $cidr = ([int]($paddress.split("/")[1]))

            if (($cidr -lt 0) -or ($cidr -gt 32)) {

                #invalid CIDR.

                throw "$_ is not a valid CIDR notation for a range of IP addresses."

            } else {

                write-Output $address

                write-Output $cidr

            }

        }

       

    }

   

    process {

       

        ################################################

        # Support both pipeline and argument input.

        if ($_) {

            # Pipeline Input

            $address,$cidr = SplitAddress $_

        } else {

            # Argument Input

            if (!$ipaddress) { Throw "You must specify an IP Range in CIDR notation (I.e. `"192.168.1.0/24`")" }

            $address,$cidr = SplitAddress $ipaddress

        }

 

        $binaddress = ToBinary ( ToDecimal $address )

        $binmask = ("1" * $cidr).padright(32,[char]"0")

   

        $binnetwork = ""

        $binbroadcast = ""

        for ($i = 0; $i -lt 32; $i++) {

            # faking a bitwise comparison since powershell's -BAND only handles Int32.

            # Determine the Network Address (first in range) by doing a bitwise AND

            # between the address and mask specified.

            $binnetwork += [string]( $binmask.Substring($i,1) -band $binaddress.substring($i,1) )

            # Determine the Broadcast Address by flipping only the HOST bits to 1

            if ($i -lt $cidr) {

                $binbroadcast += [string]( $binaddress.Substring($i,1) )

            } else {

                $binbroadcast += [string]"1"

            }

        }

       

        # Convert the binary results back to Decimal

        $longnetwork =  ToDecimal $binnetwork

        $longbroadcast =  ToDecimal $binbroadcast

       

        #Pipe each IP object up the pipeline:

        # I'm skipping the network address and the Broadcast address

        for ($i = $longnetwork+1; $i -lt $longbroadcast; $i++) {

            if ($AsString) {

                write-Output (ToIP $i).IPAddressToString

            } elseif ($AsDecimal) {

                write-Output $i

            } else {

                #AsIPAddress

                write-Output (ToIP $i)

            }

        }

    }

}

 

Published Thursday, March 29, 2007 4:31 AM by Gaurhoth
Filed under: , ,

Comments

Anonymous comments are disabled