IP Calculator in PowerShell...with IP exclusion

Hola todos... que pasa?

It has been a while since i post i was really busy with so many stuff, bottom line, i had this strange requirement at work where i had to create a script to calculate the IP address from a subnet, now normally this means we have to create a bunch of scopes or subnets in the DHCP server, which was my case, i had to create more than 4 thousand scopes on Linux DHCP server.


now I was thinking how in the hell I am going to insert all these scopes in the configuration file, of course the first things I came up with was to provide the mandatory information (First IP, last IP, broadcast IP and number of hosts) which was not a big problem, I found this link :


This guy did a very good job and save my ass, but this was not the issue, in my situation, I had to exclude the first 48 IP addresses from each scope. Now in Linux DHCP configuration file, each scope was represented as a string, for example:

subnet 10.69.113.192 netmask 255.255.255.192
{
option routers 10.69.113.252;
#Default Gateway
option subnet-mask 255.255.255.192;
option Broadcast-address 10.69.113.255;
option option-150 10.75.192.10;
#TFTP Custom Option
next-server 10.75.192.10;
# TFTP Boot
range dynamic-bootp 10.69.113.193 10.69.113.241;
}




Now I am not gonna speak about Linux here because that's a different story, to generate the above string i had to create a script to read from a CSV file and put thing in the correct order.


In the last line "range dynamic-bootp" this option provides IP addresses for PXE-compliant network cards BEFORE any operating system starts. For more info, dig this link:



Now this is where my work comes i had to modify the script a little bit to provide my requirements.


The original script looked like this:


<# 
.SYNOPSIS 
ipcalc calculates the IP subnet information based 
upon the entered IP address and subnet.  
.DESCRIPTION 
ipcalc calculates the IP subnet information based 
upon the entered IP address and subnet. It can accept 
both CIDR and dotted decimal formats. 
By: Jason Wasser 
Date: 10/29/2013 
.PARAMETER IPAddress 
Enter the IP address by itself or with CIDR notation. 
.PARAMETER Netmask 
Enter the subnet mask information in dotted decimal  
form. 
.EXAMPLE 
ipcalc.ps1 -IPAddress 10.100.100.1 -NetMask 255.255.255.0 
.EXAMPLE 
ipcalc.ps1 10.10.100.5/24 
#> 
param ( 
    [Parameter(Mandatory=$True,Position=1)] 
    [string]$IPAddress
    [Parameter(Mandatory=$False,Position=2)] 
    [string]$Netmask 
    ) 

function toBinary ($dottedDecimal){ 
 $dottedDecimal.split("."| %{$binary=$binary + $([convert]::toString($_,2).padleft(8,"0"))} 
 return $binary 
function toDottedDecimal ($binary){ 
 do {$dottedDecimal +"." + [string]$([convert]::toInt32($binary.substring($i,8),2)); $i+=8 } while ($i -le 24) 
 return $dottedDecimal.substring(1) 

function 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 

function NetMasktoWildcard ($wildcard) { 
    foreach ($bit in [char[]]$wildcard) { 
        if ($bit -eq "1") { 
            $wildcardmask +"0" 
            } 
        elseif ($bit -eq "0") { 
            $wildcardmask +"1" 
            } 
        } 
    return $wildcardmask 
    } 


# Check to see if the IP Address was entered in CIDR format 
if ($IPAddress -like "*/*") { 
    $CIDRIPAddress = $IPAddress 
    $IPAddress = $CIDRIPAddress.Split("/")[0] 
    $cidr = [convert]::ToInt32($CIDRIPAddress.Split("/")[1]) 
    if ($cidr -le 32 -and $cidr -ne 0) { 
        $ipBinary = toBinary $IPAddress 
        $smBinary = CidrToBin($cidr
        $Netmask = toDottedDecimal($smBinary
        $wildcardbinary = NetMasktoWildcard ($smBinary
        } 
    else { 
        Write-Warning "Subnet Mask is invalid!" 
        Exit 
        } 
    } 
else { 
    if (!$Netmask) { 
        $Netmask = Read-Host "Netmask" 
        } 
    $ipBinary = toBinary $IPAddress 
    if ($Netmask -eq "0.0.0.0") { 
        Write-Warning "Subnet Mask is invalid!" 
        Exit 
        } 
    else { 
        $smBinary = toBinary $Netmask 
        $wildcardbinary = NetMasktoWildcard ($smBinary
        } 
    } 

#how many bits are the network ID 
$netBits=$smBinary.indexOf("0"
if ($netBits -ne -1) { 
    $cidr = $netBits 
    #validate the subnet mask 
    if(($smBinary.length -ne 32) -or ($smBinary.substring($netBits).contains("1"-eq $true)) { 
        Write-Warning "Subnet Mask is invalid!" 
        Exit 
        } 
    #validate that the IP address 
    if(($ipBinary.length -ne 32) -or ($ipBinary.substring($netBits-eq "00000000"-or ($ipBinary.substring($netBits-eq "11111111")) { 
        Write-Warning "IP Address is invalid!" 
        Exit 
        } 
    #identify subnet boundaries 
    $networkID = toDottedDecimal $($ipBinary.substring(0,$netBits).padright(32,"0")) 
    $firstAddress = toDottedDecimal $($ipBinary.substring(0,$netBits).padright(31,"0"+ "1"
    $lastAddress = toDottedDecimal $($ipBinary.substring(0,$netBits).padright(31,"1"+ "0"
    $broadCast = toDottedDecimal $($ipBinary.substring(0,$netBits).padright(32,"1")) 
    $wildcard = toDottedDecimal ($wildcardbinary
    $networkIDbinary = $ipBinary.substring(0,$netBits).padright(32,"0"
    $broadCastbinary = $ipBinary.substring(0,$netBits).padright(32,"1"
    $Hostspernet = ([convert]::ToInt32($broadCastbinary,2) - [convert]::ToInt32($networkIDbinary,2)) - 1 
   } 
else { 
    #identify subnet boundaries 
    $networkID = toDottedDecimal $($ipBinary
    $firstAddress = toDottedDecimal $($ipBinary
    $lastAddress = toDottedDecimal $($ipBinary
    $broadCast = toDottedDecimal $($ipBinary
    $wildcard = toDottedDecimal ($wildcardbinary
    $Hostspernet = 1 
    } 


#Results 
Write-Host "`nAddress:`t`t$IPAddress" 
Write-Host "Netmask:`t`t$Netmask = $cidr" 
Write-Host "Wildcard:`t`t$wildcard" 
Write-Host "=>" 
Write-Host "Network:`t`t$networkID/$cidr" 
Write-Host "Broadcast:`t`t$broadCast" 
Write-Host "HostMin:`t`t$firstAddress" 
Write-Host "HostMax:`t`t$lastAddress" 
Write-Host "Hosts/Net:`t`t$Hostspernet`n"  


The output should be something like this :

Address:                10.10.100.5
Netmask:                255.255.255.0 = 24
Wildcard:               0.0.0.255
=>
Network:                10.10.100.0/24
Broadcast:              10.10.100.255
HostMin:                10.10.100.1
HostMax:                10.10.100.254
Hosts/Net:              254


In my situation i did some modification on the script to look like this :

param (
    [Parameter(Mandatory=$True,Position=1)]
    [string]$IPAddress,
    [Parameter(Mandatory=$False,Position=2)]
    [string]$Netmask
    )

function toBinary ($dottedDecimal){
 $dottedDecimal.split(".") | %{$binary=$binary + $([convert]::toString($_,2).padleft(8,"0"))}
 return $binary
}
function toDottedDecimal ($binary){
 do {$dottedDecimal += "." + [string]$([convert]::toInt32($binary.substring($i,8),2)); $i+=8 } while ($i -le 24)
 return $dottedDecimal.substring(1)
}

function 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
}

function NetMasktoWildcard ($wildcard) {
    foreach ($bit in [char[]]$wildcard) {
        if ($bit -eq "1") {
            $wildcardmask += "0"
            }
        elseif ($bit -eq "0") {
            $wildcardmask += "1"
            }
        }
    return $wildcardmask
    }


# Check to see if the IP Address was entered in CIDR format
if ($IPAddress -like "*/*") {
    $CIDRIPAddress = $IPAddress
    $IPAddress = $CIDRIPAddress.Split("/")[0]
    $cidr = [convert]::ToInt32($CIDRIPAddress.Split("/")[1])
    if ($cidr -le 32 -and $cidr -ne 0) {
        $ipBinary = toBinary $IPAddress
        $smBinary = CidrToBin($cidr)
        $Netmask = toDottedDecimal($smBinary)
        $wildcardbinary = NetMasktoWildcard ($smBinary)
        }
    else {
        Write-Warning "Subnet Mask is invalid!"
        Exit
        }
    }
else {
    if (!$Netmask) {
        $Netmask = Read-Host "Netmask"
        }
    $ipBinary = toBinary $IPAddress
    if ($Netmask -eq "0.0.0.0") {
        Write-Warning "Subnet Mask is invalid!"
        Exit
        }
    else {
        $smBinary = toBinary $Netmask
        $wildcardbinary = NetMasktoWildcard ($smBinary)
        }
    }

#how many bits are the network ID
$netBits=$smBinary.indexOf("0")
if ($netBits -ne -1) {
    $cidr = $netBits
    #validate the subnet mask
    if(($smBinary.length -ne 32) -or ($smBinary.substring($netBits).contains("1") -eq $true)) {
        Write-Warning "Subnet Mask is invalid!"
        Exit
        }
    #validate that the IP address
    if(($ipBinary.length -ne 32) -or ($ipBinary.substring($netBits) -eq "00000000") -or ($ipBinary.substring($netBits) -eq "11111111")) {
        Write-Warning "IP Address is invalid!"
        Exit
        }
    #identify subnet boundaries
    $networkID = toDottedDecimal $($ipBinary.substring(0,$netBits).padright(32,"0"))
    $firstAddress = toDottedDecimal $($ipBinary.substring(0,$netBits).padright(31,"0") + "1")
    $lastAddress = toDottedDecimal $($ipBinary.substring(0,$netBits).padright(31,"1") + "0")
    $broadCast = toDottedDecimal $($ipBinary.substring(0,$netBits).padright(32,"1"))
    $wildcard = toDottedDecimal ($wildcardbinary)
    $networkIDbinary = $ipBinary.substring(0,$netBits).padright(32,"0")
    $broadCastbinary = $ipBinary.substring(0,$netBits).padright(32,"1")
    $Hostspernet = ([convert]::ToInt32($broadCastbinary,2) - [convert]::ToInt32($networkIDbinary,2)) – 1

   # I added these lines
         $exclusionfirstAddresssep = $firstAddress.Split(".")[3].split(" ")
         $ipstart1 = $firstAddress.Split(".")[0].split("").trim()
         $ipstart2 = $firstAddress.Split(".")[1].split("").trim()
         $ipstart3 = $firstAddress.Split(".")[2].split("").trim()
         $excludelastip = [Convert]::ToInt32($exclusionfirstAddresssep,10) + [convert]::ToInt32("48",10)
         $startip = [Convert]::ToInt32($excludelastip,10) + [Convert]::ToInt32("1",10)
         $ipstart4 = $ipstart1 + "." + $ipstart2 + "." + $ipstart3 + "." + $startip
        
        
   }
else {
    #identify subnet boundaries
    $networkID = toDottedDecimal $($ipBinary)
    $firstAddress = toDottedDecimal $($ipBinary)
    $lastAddress = toDottedDecimal $($ipBinary)
    $broadCast = toDottedDecimal $($ipBinary)
    $wildcard = toDottedDecimal ($wildcardbinary)
    $Hostspernet = 1
    }


#Results
Write-Host "`nAddress:`t`t$IPAddress"
Write-Host "Netmask:`t`t$Netmask = $cidr"
Write-Host "Wildcard:`t`t$wildcard"
Write-Host "=>"
Write-Host "Network:`t`t$networkID/$cidr"
Write-Host "Broadcast:`t`t$broadCast"
Write-Host "HostMin:`t`t$firstAddress"
Write-Host "HostMax:`t`t$lastAddress"
Write-Host "Hosts/Net:`t`t$Hostspernet`n"
Write-Host "excluding from : $exclusionfirstAddresssep to $excludelastip `n"
Write-Host "boottp-Exclusion:`t$ipstart4 $lastAddress"

# show as csv file :

WriteHost

"$IPAddress,$Netmask,$cidr,$wildcard,$networkID/$cidr,$broadCast,$firstAddress,$lastAddress,$Hostspernet,$ipstart4 $lastAddress"


Now my output looked something like this :

Address:                10.10.100.5
Netmask:                255.255.255.0 = 24
Wildcard:               0.0.0.255
=>
Network:                10.10.100.0/24
Broadcast:              10.10.100.255
HostMin:                10.10.100.1
HostMax:                10.10.100.254
Hosts/Net:              254

excluding from : 1 to 49

boottp-Exclusion:       10.10.100.50 10.10.100.254

10.10.100.5,255.255.255.0,24,0.0.0.255,10.10.100.0/24,10.10.100.255,10.10.100.1,10.10.100.254,254,10.10.100.50 10.10.100.254


The part in the yellow was the added result after my modification, to make the first 48 IP addresses PXE.

This same way can be used to also exclude the IP addresses in DHCP, the exclusion will ask the DHCP not to provide these IP's to other devices.

The last line of the result can be copied and pasted in a CSV file, and from excel you can use the text to columns option to segregate each value in a separate column, this can help in creating the scopes in microsoft or linux based DHCP.


 Sadly I gotta go now, anyway saludos todos, hasta pronto todos....


Comments

Popular posts from this blog