Get-PowerIPRange.ps1

<#
.SYNOPSIS
Generates IPv4 address lists with the provided Start and End IPv4 address.
.DESCRIPTION
Function utilized by Test-PowerPing to generate IPv4 Address lists.
.NOTES
Author: Hunter Hirsch
#>

function Get-PowerIPRange {
[CmdletBinding()]
[OutputType([System.Collections.ArrayList],[System.Collections.Queue])]
    Param (
    [Parameter(Mandatory,ValueFromPipeline)]
    [string]
    $Start,
    [Parameter(Mandatory,ValueFromPipeline)]
    [string]
    $End,
    [Parameter(ValueFromPipeline)]
    [string[]]
    $Filter
    )
Begin {
##Creates variables for start/end addressbytes and compares them to see which is greater (if '$adbal' begins with '-' (negative #), Start is greater than end, requiring swap to retain count up (++) functionality).##
Try{
    $starr = ([ipaddress] $Start).GetAddressBytes()
    $edarr = ([ipaddress] $End).GetAddressBytes()
    [string]$adbal = ($edarr[0] - $starr[0]),($edarr[1] - $starr[1]),($edarr[2] - $starr[2]),($edarr[3] - $starr[3])
    $adbal = $adbal.Replace(" ",'')
    if ($adbal[0] -eq '-' -or $adbal -match "^[0]{1,3}-"){
        $starr = ([ipaddress] $End).GetAddressBytes()
        $edarr = ([ipaddress] $Start).GetAddressBytes()
        }
    $endip = [ipaddress]$edarr
##Filter function for provided filters. If generated address is '-like' a filter from filter list, loop returns before adding address to filter queue ($fqueue).##
##Filters are applied after address generation. Attempting to filter inline with address loop slowed generation significantly, targeted filtering functionality provided to reduce filters on larger sets##
    if ($Filter){
        $Filter = $Filter.Split(',')
        filter ppafilter {
            [uint32]$cnt = $Filter.Count -1
            for ($i = 0; $i -le $cnt; $i++){
                if ($_ -like $Filter[$i]){
                    return
                    }
                }
            $fqueue.enqueue($_)
            }
        }
    $address = [System.Collections.ArrayList]::new()
    $adqueue = [System.Collections.Queue]::new()
    }
Catch{
    $address = $null
    Throw $_.Exception.errorrecord
    }
    }
Process{
##Address generation loop. Uses limitations of Byte value (max 255) to apply counter logic. If count up hits error, max is reached, octet is set to zero, and preceding octet is counted up one time.##
##Errors are accounted for from try/catch progression. Parent function attempts to clear all errors if present to reduce log bloat. Error must match 'cannot convert value "256"', these are the only errors cleared.##
##Microsoft documentation advises there is no way to bypass the initial write to global $error variable. (https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-7.4).##
##No action is provided for catch in count up of index '0' due to parameter validation/ipv4 logic. No address can be provided to loop that would have a value greater than '255' in index '0'.##
Try{
    $adqueue.Enqueue([string][ipaddress]$starr)
    while ([ipaddress]$starr -ne $endip){
        Try{
            $starr[3]++
            }
        Catch{
            $starr[3] = 0
            Try{
                $starr[2]++
                }
            Catch{
                $starr[2] = 0
                Try{
                    $starr[1]++
                    }
                Catch{
                    $starr[1]=0
                    Try{
                        $starr[0]++
                        }
                    Catch{
                        }
                    }
                }
            }
        $adqueue.Enqueue([string][ipaddress]$starr)
        }
    $null = $address.AddRange($adqueue)
    $adqueue.Clear()
   }
Catch{
    $address = $null
    $adqueue = $null
    Throw $_.Exception.errorrecord
    [system.gc]::Collect()
    }
}
End {
##returns address arraylist or filter queue based on parameters. If filters are provided, address arraylist is processed through 'ppafilter'. Any unfiltered addresses are added to filter queue (fqueue) and then returned to parent function.##
Try{
    if ($Filter){
        $fqueue = New-Object System.Collections.Queue
        $address | ppafilter
        $address.clear()
        $fqueue
        }
    Else{
        $address
        }
    if ($Filter){
        $fqueue = $null
        }
    $address = $null; $adqueue = $null
    }
Catch{
    if ($Filter){
        $fqueue = $null
        }
    $address = $null
    [system.gc]::Collect()
    Throw $_.exception.errorrecord
    }
Finally{
    [system.gc]::Collect()
    }
}
}