Get-PowerIPCIDR.ps1

<#
.SYNOPSIS
Provides CIDR Block information for provided CIDR Address block.
Provides Start/End IP for address list generation via Get-PowerIPRange.
.DESCRIPTION
Function utilized by Test-PowerPing to process CIDR Address block input.
.NOTES
Author: Hunter Hirsch
#>

function Get-PowerIPCIDR {
[CmdletBinding()]
[OutputType([System.Collections.ArrayList])]
    Param (
    [Parameter(Mandatory,ValueFromPipeline)]
    [string[]]
    $Range,
    [Parameter(ValueFromPipeline)]
    [switch]
    $AssignO,
    [Parameter(ValueFromPipeline)]
    [switch]
    $Calculator,
    [Parameter(ValueFromPipeline)]
    [string[]]
    $Filter
    )

Begin {
##CIDR calculation table, '#s' = startip and '#' = endip. Table calls on lines 106/107 below.##
##Still getting familiar with bit operations, researching cleaner method for calculations.##
    $cidrl = @{
        '0' = {'255.255.255.255'}
        '0s' = {'0.0.0.0'}
        '1' = {if ([int]$_.split('.')[0] -lt 128){$a = '127'}Else{$a = '255'}; [string]$a + '.255.255.255'}
        '1s' = {if ([int]$_.split('.')[0] -lt 128){'0.0.0.0'}Else{'128.0.0.0'}}
        '2' = {if ($_.split('.')[0] -ne '0'){$x = $_.split('.')[0]/64; if($x.gettype().name -eq 'Double'){$a = 64*([math]::Ceiling($_.split('.')[0]/64))-1}else {$a = 64*([math]::Ceiling(([int]$_.split('.')[0]+1)/64))-1}}else{$a = '63'};[string]$a + '255.255.255'}
        '2s' = {$a = 64*([math]::floor($_.split('.')[0]/64));[string]$a +'.0.0.0'}
        '3' = {if ($_.split('.')[0] -ne '0'){$x = $_.split('.')[0]/32; if($x.gettype().name -eq 'Double'){$a = 32*([math]::Ceiling($_.split('.')[0]/32))-1}else {$a = 32*([math]::Ceiling(([int]$_.split('.')[0]+1)/32))-1}}else{$a = '31'};[string]$a +'.255.255.255'}
        '3s' = {$a = 32*([math]::floor($_.split('.')[0]/32));[string]$a +'.0.0.0'}
        '4' = {if ($_.split('.')[0] -ne '0'){$x = $_.split('.')[0]/16; if($x.gettype().name -eq 'Double'){$a = 16*([math]::Ceiling($_.split('.')[0]/16))-1}else {$a = 16*([math]::Ceiling(([int]$_.split('.')[0]+1)/16))-1}}else{$a = '15'};[string]$a +'.255.255.255'}
        '4s' = {$a = 16*([math]::floor($_.split('.')[0]/16));[string]$a +'.0.0.0'}
        '5' = {if ($_.split('.')[0] -ne '0'){$x = $_.split('.')[0]/8; if($x.gettype().name -eq 'Double'){$a = 8*([math]::Ceiling($_.split('.')[0]/8))-1}else {$a = 8*([math]::Ceiling(([int]$_.split('.')[0]+1)/8))-1}}else{$a = '7'};[string]$a +'.255.255.255'}
        '5s' = {$a = 8*([math]::floor($_.split('.')[0]/8));[string]$a +'.0.0.0'}
        '6' = {if ($_.split('.')[0] -ne '0'){$x = $_.split('.')[0]/4; if($x.gettype().name -eq 'Double'){$a = 4*([math]::Ceiling($_.split('.')[0]/4))-1}else {$a = 4*([math]::Ceiling(([int]$_.split('.')[0]+1)/4))-1}}else{$a = '3'};[string]$a +'.255.255.255'}
        '6s' = {$a = 4*([math]::floor($_.split('.')[0]/4));[string]$a +'.0.0.0'}
        '7' = {if ($_.split('.')[0] -ne '0'){$x = $_.split('.')[0]/2; if($x.gettype().name -eq 'Double'){$a = 2*([math]::Ceiling($_.split('.')[0]/2))-1}else {$a = 2*([math]::Ceiling(([int]$_.split('.')[0]+1)/2))-1}}else{$a = '1'};[string]$a +'.255.255.255'}
        '7s' = {$a = 2*([math]::floor($_.split('.')[0]/2));[string]$a +'.0.0.0'}
        '8' = {$_.split('.')[0] + '.255.255.255'}
        '8s' = {$_.split('.')[0] + '.0.0.0'}
        '9' = {if ([int]$_.split('.')[1] -lt 128){$b = '127'}Else{$b = '255'}; $_.split('.')[0] + '.' + $b + '.255.255'}
        '9s' = {if ([int]$_.split('.')[1] -lt 128){$_.split('.')[0] + '.0.0.0'}Else{$_.split('.')[0] + '.128.0.0'}}
        '10' = {if ($_.split('.')[1] -ne '0'){$x = $_.split('.')[1]/64; if($x.gettype().name -eq 'Double'){$b = 64*([math]::Ceiling($_.split('.')[1]/64))-1}else {$b = 64*([math]::Ceiling(([int]$_.split('.')[1]+1)/64))-1}}else{$b = '63'};$_.split('.')[0]+".$b.255.255"}
        '10s' = {$b = 64*([math]::floor($_.split('.')[1]/64));$_.split('.')[0]+".$b.0.0"}
        '11' = {if ($_.split('.')[1] -ne '0'){$x = $_.split('.')[1]/32; if($x.gettype().name -eq 'Double'){$b = 32*([math]::Ceiling($_.split('.')[1]/32))-1}else {$b = 32*([math]::Ceiling(([int]$_.split('.')[1]+1)/32))-1}}else{$b = '31'};$_.split('.')[0]+".$b.255.255"}
        '11s' = {$b = 32*([math]::floor($_.split('.')[1]/32));$_.split('.')[0]+".$b.0.0"}
        '12' = {if ($_.split('.')[1] -ne '0'){$x = $_.split('.')[1]/16; if($x.gettype().name -eq 'Double'){$b = 16*([math]::Ceiling($_.split('.')[1]/16))-1}else {$b = 16*([math]::Ceiling(([int]$_.split('.')[1]+1)/16))-1}}else{$b = '15'};$_.split('.')[0]+".$b.255.255"}
        '12s'= {$b = 16*([math]::floor($_.split('.')[1]/16));$_.split('.')[0]+".$b.0.0"}
        '13' = {if ($_.split('.')[1] -ne '0'){$x = $_.split('.')[1]/8; if($x.gettype().name -eq 'Double'){$b = 8*([math]::Ceiling($_.split('.')[1]/8))-1}else {$b = 8*([math]::Ceiling(([int]$_.split('.')[1]+1)/8))-1}}else{$b = '7'};$_.split('.')[0]+".$b.255.255"}
        '13s' = {$b = 8*([math]::floor($_.split('.')[1]/8));$_.split('.')[0]+".$b.0.0"}
        '14' = {if ($_.split('.')[1] -ne '0'){$x = $_.split('.')[1]/4; if($x.gettype().name -eq 'Double'){$b = 4*([math]::Ceiling($_.split('.')[1]/4))-1}else {$b = 4*([math]::Ceiling(([int]$_.split('.')[1]+1)/4))-1}}else{$b = '3'};$_.split('.')[0]+".$b.255.255"}
        '14s' = {$b = 4*([math]::floor($_.split('.')[1]/4));$_.split('.')[0]+".$b.0.0"}
        '15' = {if ($_.split('.')[1] -ne '0'){$x = $_.split('.')[1]/2; if($x.gettype().name -eq 'Double'){$b = 2*([math]::Ceiling($_.split('.')[1]/2))-1}else {$b = 2*([math]::Ceiling(([int]$_.split('.')[1]+1)/2))-1}}else{$b = '1'};$_.split('.')[0]+".$b.255.255"}
        '15s' = {$b = 2*([math]::floor($_.split('.')[1]/2));$_.split('.')[0]+".$b.0.0"}
        '16' = {$_.split('.')[0] + '.' + $_.split('.')[1] + ".255.255"}
        '16s' = {$_.split('.')[0] + '.' + $_.split('.')[1] + ".0.0"}
        '17' = {if ([int]$_.split('.')[2] -lt 128){$c = '127'}Else{$c = '255'}; $_.split('.')[0] + '.' + $_.split('.')[1] + '.' + $c +'.255'}
        '17s' = {if ([int]$_.split('.')[2] -lt 128){$_.split('.')[0] + '.' + $_.split('.')[1] + '.0.0'}Else{$_.split('.')[0] + '.' + $_.split('.')[1] + '.128.0'}}
        '18' = {if ($_.split('.')[2] -ne '0'){$x = $_.split('.')[2]/64; if($x.gettype().name -eq 'Double'){$c = 64*([math]::Ceiling($_.split('.')[2]/64))-1}else {$c = 64*([math]::Ceiling(([int]$_.split('.')[2]+1)/64))-1}}else{$c = '63'};$_.split('.')[0] + '.' + $_.split('.')[1] + ".$c.255"}
        '18s' = {$c = 64*([math]::floor($_.split('.')[2]/64));$_.split('.')[0] + '.' + $_.split('.')[1] + ".$c.0"}
        '19' = {if ($_.split('.')[2] -ne '0'){$x = $_.split('.')[2]/32; if($x.gettype().name -eq 'Double'){$c = 32*([math]::Ceiling($_.split('.')[2]/32))-1}else {$c = 32*([math]::Ceiling(([int]$_.split('.')[2]+1)/32))-1}}else{$c = '31'};$_.split('.')[0] + '.' + $_.split('.')[1] + ".$c.255"}
        '19s' = {$c = 32*([math]::floor($_.split('.')[2]/32));$_.split('.')[0] + '.' + $_.split('.')[1] + ".$c.0"}
        '20' = {if ($_.split('.')[2] -ne '0'){$x = $_.split('.')[2]/16; if($x.gettype().name -eq 'Double'){$c = 16*([math]::Ceiling($_.split('.')[2]/16))-1}else {$c = 16*([math]::Ceiling(([int]$_.split('.')[2]+1)/16))-1}}else{$c = '15'};$_.split('.')[0] + '.' + $_.split('.')[1] + ".$c.255"}
        '20s' = {$c = 16*([math]::floor($_.split('.')[2]/16));$_.split('.')[0] + '.' + $_.split('.')[1] + ".$c.0"}
        '21' = {if ($_.split('.')[2] -ne '0'){$x = $_.split('.')[2]/8; if($x.gettype().name -eq 'Double'){$c = 8*([math]::Ceiling($_.split('.')[2]/8))-1}else {$c = 8*([math]::Ceiling(([int]$_.split('.')[2]+1)/8))-1}}else{$c = '7'};$_.split('.')[0] + '.' + $_.split('.')[1] + ".$c.255"}
        '21s' = {$c = 8*([math]::floor($_.split('.')[2]/8));$_.split('.')[0] + '.' + $_.split('.')[1] + ".$c.0"}
        '22' = {if ($_.split('.')[2] -ne '0'){$x = $_.split('.')[2]/4; if($x.gettype().name -eq 'Double'){$c = 4*([math]::Ceiling($_.split('.')[2]/4))-1}else {$c = 4*([math]::Ceiling(([int]$_.split('.')[2]+1)/4))-1}}else{$c = '3'};$_.split('.')[0] + '.' + $_.split('.')[1] + ".$c.255"}
        '22s' = {$c = 4*([math]::floor($_.split('.')[2]/4));$_.split('.')[0] + '.' + $_.split('.')[1] + ".$c.0"}
        '23' = {if ($_.split('.')[2] -ne '0'){$x = $_.split('.')[2]/2; if($x.gettype().name -eq 'Double'){$c = 2*([math]::Ceiling($_.split('.')[2]/2))-1}else {$c = 2*([math]::Ceiling(([int]$_.split('.')[2]+1)/2))-1}}else{$c = '1'};$_.split('.')[0] + '.' + $_.split('.')[1] + ".$c.255"}
        '23s' = {$c = 2*([math]::floor($_.split('.')[2]/2));$_.split('.')[0] + '.' + $_.split('.')[1] + ".$c.0"}
        '24' = {$_.split('.')[0] + '.' + $_.split('.')[1] + '.' + $_.split('.')[2] + ".255"}
        '24s' = {$_.split('.')[0] + '.' + $_.split('.')[1] + '.' + $_.split('.')[2] + ".0"}
        '25' = {if ([int]$_.split('.')[3] -lt 128){$d = '127'}Else{$d = '255'}; $_.split('.')[0] + '.' + $_.split('.')[1] + '.' + $_.split('.')[2] + ".$d"}
        '25s' = {if ([int]$_.split('.')[3] -lt 128){$_.split('.')[0] + '.' + $_.split('.')[1] + '.' + $_.split('.')[2] + '.0'}Else{$_.split('.')[0] + '.' + $_.split('.')[1] + '.' + $_.split('.')[2] + '.128'}}
        '26' = {if ($_.split('.')[3] -ne '0'){$x = $_.split('.')[3]/64; if($x.gettype().name -eq 'Double'){$d = 64*([math]::Ceiling($_.split('.')[3]/64))-1}else {$d = 64*([math]::Ceiling(([int]$_.split('.')[3]+1)/64))-1}}else{$d = '63'};$_.split('.')[0] + '.' + $_.split('.')[1] + '.' + $_.split('.')[2] + ".$d"}
        '26s' = {$d = 64*([math]::floor($_.split('.')[3]/64));$_.split('.')[0] + '.' + $_.split('.')[1] + '.' + $_.split('.')[2] + ".$d"}
        '27' = {if ($_.split('.')[3] -ne '0'){$x = $_.split('.')[3]/32; if($x.gettype().name -eq 'Double'){$d = 32*([math]::Ceiling($_.split('.')[3]/32))-1}else {$d = 32*([math]::Ceiling(([int]$_.split('.')[3]+1)/32))-1}}else{$d = '31'};$_.split('.')[0] + '.' + $_.split('.')[1] + '.' + $_.split('.')[2] + ".$d"}
        '27s' = {$d = 32*([math]::floor($_.split('.')[3]/32));$_.split('.')[0] + '.' + $_.split('.')[1] + '.' + $_.split('.')[2] + ".$d"}
        '28' = {if ($_.split('.')[3] -ne '0'){$x = $_.split('.')[3]/16; if($x.gettype().name -eq 'Double'){$d = 16*([math]::Ceiling($_.split('.')[3]/16))-1}else {$d = 16*([math]::Ceiling(([int]$_.split('.')[3]+1)/16))-1}}else{$d = '15'};$_.split('.')[0] + '.' + $_.split('.')[1] + '.' + $_.split('.')[2] + ".$d"}
        '28s' = {$d = 16*([math]::floor($_.split('.')[3]/16));$_.split('.')[0] + '.' + $_.split('.')[1] + '.' + $_.split('.')[2] + ".$d"}
        '29' = {if ($_.split('.')[3] -ne '0'){$x = $_.split('.')[3]/8; if($x.gettype().name -eq 'Double'){$d = 8*([math]::Ceiling($_.split('.')[3]/8))-1}else {$d = 8*([math]::Ceiling(([int]$_.split('.')[3]+1)/8))-1}}else{$d = '7'};$_.split('.')[0] + '.' + $_.split('.')[1] + '.' + $_.split('.')[2] + ".$d"}
        '29s' = {$d = 8*([math]::floor($_.split('.')[3]/8));$_.split('.')[0] + '.' + $_.split('.')[1] + '.' + $_.split('.')[2] + ".$d"}
        '30' = {if ($_.split('.')[3] -ne '0'){$x = $_.split('.')[3]/4; if($x.gettype().name -eq 'Double'){$d = 4*([math]::Ceiling($_.split('.')[3]/4))-1}else {$d = 4*([math]::Ceiling(([int]$_.split('.')[3]+1)/4))-1}}else{$d = '3'};$_.split('.')[0] + '.' + $_.split('.')[1] + '.' + $_.split('.')[2] + ".$d"}
        '30s' = {$d = 4*([math]::floor($_.split('.')[3]/4));$_.split('.')[0] + '.' + $_.split('.')[1] + '.' + $_.split('.')[2] + ".$d"}
        '31' = {if ($_.split('.')[3] -ne '0'){$x = $_.split('.')[3]/2; if($x.gettype().name -eq 'Double'){$d = 2*([math]::Ceiling($_.split('.')[3]/2))-1}else {$d = 2*([math]::Ceiling(([int]$_.split('.')[3]+1)/2))-1}}else{$d = '1'};$_.split('.')[0] + '.' + $_.split('.')[1] + '.' + $_.split('.')[2] + ".$d"}
        '31s' = {$d = 2*([math]::floor($_.split('.')[3]/2));$_.split('.')[0] + '.' + $_.split('.')[1] + '.' + $_.split('.')[2] + ".$d"}
        }
    $cidhsh = @{}
    }
Process {
##foreach loop to process each CIDR block provided with provided filters or 'AssignOnly' switch, generates list or provides CIDR calculator output.##
##if bits, '/#', not equal '32' (single address output), process cidr list or cidr calculator for given block.##
Try{
    [int]$cic = 0
    foreach ($cp in $Range){
        $cidhsh.Add($cic,([System.Collections.ArrayList]::new()))
        $Start = $cp.split('/')[0]
        [string]$cidn = $cp.split('/')[1]
        if ($cidn -ne '32'){
            $End = ($Start | Select-Object -Property $cidrl.$cidn).($cidrl.$cidn)
            $Start = ($Start | Select-Object -Property $cidrl.($cidn+'s')).($cidrl.($cidn+'s'))
            if (!$Calculator){
                if ($AssignO){
                    if ($cidn -ne '31'){
                        $cfir = [int]$start.Split('.')[3]+1
                        $Start = ($Start.Split('.')[0..2] -join '.') + ".$cfir"
                        $clas = [int]$End.Split('.')[3]-1
                        $End = ($End.Split('.')[0..2] -join '.') + ".$clas"
                        }
                    }
                $cparam = @{
                    Start = $Start
                    End = $End
                    }
                if ($Filter){
                    $cparam.Add('Filter',$Filter)
                    }
                $null = $cidhsh.$cic.AddRange((Get-PowerIPRange @cparam))
                }
            Else{
                [double]$cacnt = [math]::Pow(2,(32-[int]$cidn))
                if ($cidn -ne '31'){
                    $cfir = [int]$start.Split('.')[3]+1
                    $clas = [int]$End.Split('.')[3]-1
                    $CFad = ($Start.Split('.')[0..2] -join '.') + ".$cfir"
                    $CLad = ($End.Split('.')[0..2] -join '.') + ".$clas"
                    }
                $null = $cidhsh.$cic.Add([PSCustomObject]@{"CIDR"=$cp;"BaseIP"=$Start;"BroadcastIP"=$End;"AddressCount"=$cacnt;"FirstAssignable"=if ($CFad){$CFad};"LastAssignable"=if ($CLad){$CLad};"AssignableAddresses"=$cacnt-2;"Netmask"=$csnl.$cidn})
                }
            }
        Else{
            if (!$Calculator){
                $null = $cidhsh.$cic.Add($Start)
                }
            Else{
                $null = $cidhsh.$cic.Add([PSCustomObject]@{"CIDR"=$cp;"BaseIP"=$Start;"BroadcastIP"="";"AddressCount"="1";"FirstAssignable"="";"LastAssignable"="";"AssignableAddresses"="0";"Netmask"=$csnl.$cidn})
                }
            }
        $cfir=$null;$clas=$null;$CFad=$null;$CLad=$null;$Start=$null;$End=$null;$cidn=$null
        $cic ++
        }
    }
Catch{
    Throw $_.Exception.errorrecord
    }
}
End{
##Each CIDR address request is added to hashtable '$cidhsh', line 127 above, with queue number. $rng calls queue number for each hash entry to return address values in the order CIDR blocks are provided.##
Try{
    $rng = 0..($cidhsh.Count -1)
    $rng | ForEach-Object {$cidhsh.$_}
    }
Catch{
    Throw $_.Exception.errorrecord
    }
Finally{
    $cidhsh = $null; $cidrl = $null;$Start = $null;$End = $null; $cparam = $null;$csnl = $null
    }
}
}