List and validate IPv4 subnet masks using PowerShell
In this article I show you how to generate a list of all valid IPv4 subnet masks, and how to validate that a provided subnet mask is valid. Generating the list of valid IPv4 subnet masks in dotted decimal notation can be done in several ways, as can validating a supplied subnet mask in both binary and dotted-decimal form.
With the small number of possible subnets, an array and the -Contains operator should be fine for most purposes (32 possible network lengths - or 33 if you toss in 0), but I'll show you other ways that will perform better too, for the sake of elucidation, and potentially to fulfill a rare need (if you have such a need you probably don't need this article).
(adsbygoogle = window.adsbygoogle || []).push({ google_ad_client: "ca-pub-5203802095278960", enable_page_level_ads: true });
Contents
Example screenshot of all IPv4 subnet masks
Example function for listing IPv4 subnet masks
Here's the source code for the function in the screenshot above.
function Get-IPv4SubnetMask { param([Parameter(ValueFromPipeline=$true)][int[]] $NetworkLength) process { foreach ($Length in $NetworkLength) { $MaskBinary = ('1' * $Length).PadRight(32, '0') $DottedMaskBinary = $MaskBinary -replace '(.{8}(?!\z))', '${1}.' $SubnetMask = ($DottedMaskBinary.Split('.') | foreach { [Convert]::ToInt32($_, 2) }) -join '.' $SubnetMask } } }
This code can be used to validate the subnet masks as you can see with the array and -contains, but I also demonstrate another way that should be a bit more efficient below. It really will not matter in 99.n % of the cases, and using the -Contains operator on an array should be enough.
I also talk a bit more about binary addresses if you read on.
PS C:\> $AllSubnetMasks = 1..32 | Get-IPv4SubnetMask PS C:\> $AllSubnetMasks -contains '255.0.0.0' True PS C:\> $AllSubnetMasks -contains '255.0.0.1' False
Validating a little more efficiently
Here's a pretty cool function for validating IPv4 subnet masks that returns true or false for whether it's respectively a valid or an invalid IPv4 subnet mask. Use the -Verbose parameter to see why the tests fail, if they fail.
It can parse and validate both a binary subnet mask and a dotted-decimal subnet mask (possibly in the same run).
function Test-IPv4SubnetMask { [CmdletBinding()] param( [string] $SubnetMaskBinary, [string] $SubnetMaskDottedDecimal) if ($SubnetMaskBinary) { if ($SubnetmaskBinary -match '01') { Write-Verbose -Message "Invalid binary IPv4 subnet mask: '$SubnetMaskBinary'. Matched pattern '01'." $false } elseif ($SubnetMaskBinary.Length -ne 32) { Write-Verbose -Message "Invalid binary IPv4 subnet mask: '$SubnetMaskBinary'. Length was different from 32." $false } elseif ($SubnetMaskBinary -match '[^01]') { Write-Verbose -Message "Invalid binary IPv4 subnet mask: '$SubnetMaskBinary'. Was not all ones and zeroes." $false } else { $true } } if ($SubnetMaskDottedDecimal) { function Convert-IPToBinary { param([string] $IP) $IP = $IP -replace '\s+' # remove whitespace for fun try { return ($IP.Split('.') | ForEach-Object { [System.Convert]::ToString([byte] $_, 2).PadLeft(8, '0') }) -join '' } catch { Write-Warning -Message "Error converting '$IP' to a binary string: $_" return $Null } } $Binary = Convert-IPToBinary -IP $SubnetMaskDottedDecimal if ($Binary) { Test-IPv4SubnetMask -SubnetMaskBinary $Binary } else { $false } } }
Example use
And here's how it works.
PS C:\> Test-IPv4SubnetMask -SubnetMaskBinary '11' -Verbose VERBOSE: Invalid binary IPv4 subnet mask: '11'. Length was different from 32. False PS C:\> Test-IPv4SubnetMask -SubnetMaskBinary (('1' * 30) + '00') -Verbose True PS C:\> Test-IPv4SubnetMask -SubnetMaskBinary (('1' * 30) + '01') -Verbose VERBOSE: Invalid binary IPv4 subnet mask: '11111111111111111111111111111101'. Matched pattern '01'. False PS C:\> Test-IPv4SubnetMask -SubnetMaskBinary (('1' * 30) + 'xx') -Verbose VERBOSE: Invalid binary IPv4 subnet mask: '111111111111111111111111111111xx'. Was not all ones and zeroes. False PS C:\> Test-IPv4SubnetMask -SubnetMaskDottedDecimal 128.0.0.0 True PS C:\> Test-IPv4SubnetMask -SubnetMaskDottedDecimal 128.0.0.1 -Verbose VERBOSE: Invalid binary IPv4 subnet mask: '10000000000000000000000000000001'. Matched pattern '01'. False PS C:\> Test-IPv4SubnetMask -SubnetMaskDottedDecimal 128.0.0.x -Verbose WARNING: Error converting '128.0.0.x' to a binary string: Cannot convert value "x" to type "System.Byte". Error: "Input string was not in a correct format." False
Verifying our own results
Why not throw one function at the other and see how it pans out? We should get 32 times "True" (stringified $true - a boolean value) for this, if everything is working correctly. Let's see.
PS C:\> Get-IPv4SubnetMask 1 | foreach { Test-IPv4SubnetMask -SubnetMaskDottedDecimal $_ } True PS C:\> Get-IPv4SubnetMask (1..32) | foreach { Test-IPv4SubnetMask -SubnetMaskDottedDecimal $_ } True True True True True True True True True True True True True True True True True True True True True True True True True True True True True True True True
A whole lot of truth!
A missing piece of the puzzle?
And for someone who might want to create a list of binary subnet masks, I leave that as an exercise for the reader, but here's an example "IPToBinary" function I conveniently ripped (and modified slightly) from my PSipcalc script, to help you along the way (use it on the generated list of dotted-decimal subnet masks in a foreach, or similar).
function Convert-IPToBinary { param([string] $IP) $IP = $IP -replace '\s+' # remove whitespace for fun/flexibility try { return ($IP.Split('.') | ForEach-Object { [System.Convert]::ToString([byte] $_, 2).PadLeft(8, '0') }) -join '' } catch { Write-Warning -Message "Error converting '$IP' to a binary string: $_" return $null } }