DavinciPS.psm1

Function Get-SubnetAddresses {
    Param ([IPAddress]$IP,[ValidateRange(0, 32)][int]$maskbits)

    # Convert the mask to type [IPAddress]
    #IP address is built backwards
    $mask = ([Math]::Pow(2, $MaskBits) - 1) * [Math]::Pow(2, (32 - $MaskBits))
    $maskbytes = [BitConverter]::GetBytes([UInt32] $mask)
    $DottedMask = [IPAddress]((3..0 | ForEach-Object { [String] $maskbytes[$_] }) -join '.')

    # bitwise AND them together to get the subnet ID
    $lower = [IPAddress] ( $ip.Address -band $DottedMask.Address )

    # Similar operation for the broadcast address
    # subnet mask bytes need to be inverted and reversed before adding
    $LowerBytes = [BitConverter]::GetBytes([UInt32] $lower.Address)
    [IPAddress]$upper = (0..3 | %{$LowerBytes[$_] + ($maskbytes[(3-$_)] -bxor 255)}) -join '.'

    # Make an object for use elsewhere
    Return [pscustomobject][ordered]@{
    Lower=$lower
    Upper=$upper
    }
}
Function Get-IPRange {
    param (
    [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName)][IPAddress]$lower,
    [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName)][IPAddress]$upper
    )

    $IPList = [Collections.ArrayList]::new()
    $null = $IPList.Add($lower)
    $i = $lower

    # increment ip until reaching $upper in range
    while ( $i -ne $upper ) { 
     # IP octet values are built back-to-front, so reverse the octet order
        $iBytes = [BitConverter]::GetBytes([UInt32] $i.Address)
        [Array]::Reverse($iBytes)

        #+1 the int value and reverse again
        $nextBytes = [BitConverter]::GetBytes([UInt32]([bitconverter]::ToUInt32($iBytes,0) +1))
        [Array]::Reverse($nextBytes)

        # Convert to IP and add to list
        $i = [IPAddress]$nextBytes
        $null = $IPList.Add($i)
    }

    return $IPList
    }

function Get-AvailableIPs {
    param (
        $networkAddress,
        $CIDR,
        $DNSZone,
        $serverName
    )

#Get a list of IP addresses
$referenceList = Get-SubnetAddresses $networkAddress $CIDR | Get-IPRange | Select-Object -ExpandProperty IPAddressToString

#Query DNS to get a list of entries
$result = Get-DnsServerResourceRecord -ZoneName $DNSZone -ComputerName $serverName | 
Where-Object {$_.RecordData.ipv4address -like "1*"} |
Select-Object -Property @{Name = "IP Address"; Expression={$_.RecordData.IPv4Address}} 

#Compare the two lists
$compare = Compare-Object -ReferenceObject $referenceList -DifferenceObject $result."IP Address" -IncludeEqual

#Format the list to show a friendly label
$compare | ForEach-Object{
    if($_.sideIndicator -eq '<='){
        $_.sideIndicator = " Avalible"
    }
    if($_.sideIndicator -eq '=>'){
        $_.sideIndicator = " In use "
    }
    if($_.sideIndicator -eq '=='){
        $_.sideIndicator = " In use "
    }
}

#Display the results of the comparison to the user
$compare | Select-Object @{Name="IP Address";Expression={$_.InputObject}}, @{Name="Status";Expression={$_.sideIndicator}}

}

Export-ModuleMember -Function Get-AvailableIPs