0

I'm just learning the basics of powershell and have a task - create pwsh script which accepts 3 incoming parameters (all are mandatory):

  1. first parameter, value address_1, it's IP address with the format x.x.x.x
  2. second parameter, value address_2, it's IP address with the format x.x.x.x
  3. third parameter, value mask, value in the format x.x.x.x or xx (255.0.0.0 or 8)

This script should check address_1 and address_2 belong to the same network or not. Results in output console, yes or no. As I mentioned before incoming parameters not allow to accept not valid arguments, it should show error.

Can someone explain, how I can do that. I will be very grateful for your help.

4
  • 1
    Have a look at ValidatePattern. Commented Nov 4, 2022 at 17:16
  • @zett42 thanks, i read the article, i'm sure it will help me. At the beginning, I need to understand how (or where) to start solving this task - script structure or something like that. Commented Nov 4, 2022 at 18:00
  • 1
    Parameter and variable validation attributes Commented Nov 4, 2022 at 18:12
  • @postanote thanks for your advice :) I can decompose task, and find examples for those little tasks, but I don’t know how to put them and work them together. Commented Nov 5, 2022 at 8:11

4 Answers 4

1

As per my comment. This stuff already exists for years now, thus no need to try and write this from scratch, unless it's a homework assignment, or you are pushing yourself to learn to do it.

Search is your friend.

'powershell ipv4 address range to cidr'

The first hit in the results...

https://www.kittell.net/code/powershell-ipv4-range

...and the author's examples:

# IPv4 Range
function New-IPRange ($start, $end)
{
    # created by Dr. Tobias Weltner, MVP PowerShell
    $ip1 = ([System.Net.IPAddress]$start).GetAddressBytes()
    [Array]::Reverse($ip1)
    $ip1 = ([System.Net.IPAddress]($ip1 -join '.')).Address
    $ip2 = ([System.Net.IPAddress]$end).GetAddressBytes()
    [Array]::Reverse($ip2)
    $ip2 = ([System.Net.IPAddress]($ip2 -join '.')).Address
  
    for ($x=$ip1; $x -le $ip2; $x++)
        {
            $ip = ([System.Net.IPAddress]$x).GetAddressBytes()
            [Array]::Reverse($ip)
            $ip -join '.'
        }
}


# IPv4 Range - Example
New-IPRange 192.168.10.10 192.168.10.20

# broadcast IPv4 address from a CIDR range
function Get-Broadcast ($addressAndCidr)
{
    $addressAndCidr = $addressAndCidr.Split("/")
    $addressInBin = (New-IPv4toBin $addressAndCidr[0]).ToCharArray()
    for($i=0;$i -lt $addressInBin.length;$i++)
        {
            if($i -ge $addressAndCidr[1])
                {
                    $addressInBin[$i] = "1"
                } 
        }
    [string[]]$addressInInt32 = @()
    for ($i = 0;$i -lt $addressInBin.length;$i++)
        {
            $partAddressInBin += $addressInBin[$i] 
            if(($i+1)%8 -eq 0)
                {
                    $partAddressInBin = $partAddressInBin -join ""
                    $addressInInt32 += [Convert]::ToInt32($partAddressInBin -join "",2)
                    $partAddressInBin = ""
                }
        }
    $addressInInt32 = $addressInInt32 -join "."
    return $addressInInt32
}

# IPv4 Broadcast - Example
Get-Broadcast 192.168.10.10/27


# detect if a specified IPv4 address is in the range

function Test-IPinIPRange ($Address,$Lower,$Mask)
{
    [Char[]]$a = (New-IPv4toBin $Lower).ToCharArray()
    if($mask -like "*.*")
        {
            [Char[]]$b = (New-IPv4toBin $Mask).ToCharArray()
        }
    else
        {
            [Int[]]$array = (1..32)
            for($i=0;$i -lt $array.length;$i++)
                {
                    if($array[$i] -gt $mask){$array[$i]="0"}else{$array[$i]="1"}
                }
            [string]$mask = $array -join ""
            [Char[]]$b = $mask.ToCharArray()
        }
    [Char[]]$c = (New-IPv4toBin $Address).ToCharArray()
    $res = $true
    for($i=0;$i -le $a.length;$i++)
        {
            if($a[$i] -ne $c[$i] -and $b[$i] -ne "0")
                {
                    $res = $false
                } 
        }
    return $res
}

# IPv4 In Range - Example
Write-Output "`r`nTest If IP In Range - 192.168.23.128/25"
Test-IPinIPRange "192.168.23.200" "192.168.23.12" "255.255.255.128"
Write-Output "`r`nTest If IP In Range - 192.168.23.127/24"
Test-IPinIPRange "192.168.23.127" "192.168.23.12" "24"

# convert an IPv4 address to a Bin
function New-IPv4toBin ($ipv4)
{
    $BinNum = $ipv4 -split '\.' | ForEach-Object {[System.Convert]::ToString($_,2).PadLeft(8,'0')}
    return $binNum -join ""
}

# IPv4 To Bin - Example
Write-Output "`r`nIP To Bin"
New-IPv4toBin 192.168.10.10

# convert a Bin to an IPv4 address
function New-IPv4fromBin($addressInBin)
{
    [string[]]$addressInInt32 = @()
    $addressInBin = $addressInBin.ToCharArray()
    for ($i = 0;$i -lt $addressInBin.length;$i++)
        {
            $partAddressInBin += $addressInBin[$i]
            if(($i+1)%8 -eq 0)
                {
                    $partAddressInBin = $partAddressInBin -join ""
                    $addressInInt32 += [Convert]::ToInt32($partAddressInBin -join "",2)
                    $partAddressInBin = ""
                }
        }
    $addressInInt32 = $addressInInt32 -join "."
    return $addressInInt32
}

# IPv4 From Bin - Example
Write-Output "`r`nIP From Bin - 192.168.23.250"
New-IPv4fromBin "11000000101010000001011111111010"
 
Write-Output "`r`nIP From Bin - 192.168.10.10"
New-IPv4fromBin "11000000101010000000101000001010"

# CIDR To IPv4 Range - Example
Write-Output "`r`nIP CIDR to Range"
New-IPRange "192.168.23.120" (Get-Broadcast "192.168.23.120/25")

You of course can refactor the above with the Validate code already provided to you by the others.

Sign up to request clarification or add additional context in comments.

1 Comment

Edited this script, it's okay, thanks for your help
1

Some of the documentation can seem over-whelming on frist read, so here's a working framework to study and get you started. The [ValidatePattern()] and [ValidateScript()] attributes validate IPv4 address format and valid value range and errors will be thrown if the conditions they specify aren't met.

Perform you domain comparision in the Process block and branch conditionally on the result. I leave that to you.

Function AddressTest
{
    Param(
        [Parameter(Mandatory,Position = 0)]
        [ValidatePattern('^(\d{1,3}\.){3}\d{1,3}$')]
        [ValidateScript({[Int[]](($_.Split('.')) -le 255).Count -eq 4})]
        [String]$address_1,

        [Parameter(Mandatory,Position = 1)]
        [ValidatePattern('^(\d{1,3}\.){3}\d{1,3}$')]
        [ValidateScript({[Int[]](($_.Split('.')) -le 255).Count -eq 4})]
        [String]$address_2,

        [Parameter(Mandatory,Position = 2)]
        [ValidatePattern('^((\d{1,3}\.){3})?\d{1,3}$')]
        [ValidateScript({(($_ -match '^\d+$') -and ([Int]$_ -le 255)) -or (($_.Split('.') -le 255).Count -eq 4)})]
        [String]$Mask
    )
    Process
    {
        echo $address_1
        echo $address_2
        echo $mask
    }
}

Read the documentation at the links others provided in the commnents while picking apart the code to understand how it works.

1 Comment

If i understand correctly, after validate, I can convert ip addresses into binary, and then compare last bits between ip and mask?
1

This is an example of how to use regex validation patterns to test if the two ip address and netmask are valid.

param (
    [Parameter(Mandatory, Position=0)][string] $ip1,
    [Parameter(Mandatory, Position=1)] [string] $ip2,
    [Parameter(Mandatory, Position=2)] [string] $mask
)
# you can use [Parameter(Mandatory, Position=0)][IPAddress] $ip1 as input instead of string
# ipaddress param can accept partial ip's like 192.168 and will convert it to 192.0.0.168
# string with test would probably be better

function IsValidIPv4 ($ip) {
    return ($ip -match '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$' -and [bool]($ip -as [ipaddress]))
}

# Validate IP's as actual IPv4
if (isValidIPv4 $ip1){
    write-host "$($ip1) IS a valid IPv4 Address"
} else {
    write-host "$($ip1) is not a valid IPv4 Address" -ForegroundColor Red
}
if (isValidIPv4 $ip2){
    write-host "$($ip2) IS a valid IPv4 Address"
} else {
    write-host "$($ip2) is not a valid IPv4 Address" -ForegroundColor Red
}
if (isValidIPv4 $mask){
    write-host "$($mask) IS a valid IPv4 Address"
} else {
    write-host "$($mask) is not a valid netmask" -ForegroundColor Red
}

Then check with the netmask that ip1 and ip2 are in the same network

Note :

As pointed out in my comments above you can use [Parameter(Mandatory, Position=0)][IPAddress] $ip1 as input instead of string

ipaddress param can accept partial ip's like 192.168 and will convert it to 192.0.0.168 so this will cause incorrect validation - DON'T USE IT

Comments

0

I find a answer, script, with strange validation pattern:

param (
    [parameter(Mandatory = $true, Position = 0)]
    [Net.IPAddress]
    $ip1,
     
    [parameter(Mandatory = $true, Position = 1)]
    [Net.IPAddress]
    $ip2,
     
    [parameter(Mandatory = $true, Position = 2)]
    [alias("SubnetMask")]
    [Net.IPAddress]
    $mask
)
     
if (($ip1.address -band $mask.address) -eq ($ip2.address -band $mask.address)) { $true } else { $false }

Working correct:

./script.ps1 -ip1 192.168.228.110 -ip2 192.168.228.190 -mask 255.255.255.128

But when I use network prefix it always give a true.

./script.ps1 -ip1 192.168.228.110 -ip2 192.168.228.190 -mask 30

How I can modify script, to working with prefix?

2 Comments

Because this ``` 30``` is not an appropriate mask relative to the code. That is CIDR notation, no Classful IP address, which is what the code does. To use CIDR notation, then you need to refactor it for that purpose. You appear to be trying to write an IPA calculator, and I'd ask why when there are so many that already exist online and as apps. Have you looked at the MSPowerShellGallery.com modules? Use PS to find them. Find-Module -Name '*ipaddress*'. There are many PS IPv4 to CIDR and CIDR to IPv4 sample scripts to use as is and or refactor as needed. You just need to search them out
@postanote Thanks for your help. As you mentioned before, it's a homework assignment, and I try do my best. Powershell not useful to me in the future, but I need do this assignment. I can find a answer how to convert CIDR to IPv4 (or subnet, because its a same here), but I didn't see any examples - how to use subnet or CIDR at the same time as a script parameter.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.