PowerShell .NET regex to validate IPv6 address (RFC-compliant)

From Svendsen Tech PowerShell Wiki
Jump to: navigation, search

I borrowed the algorithm to create the regex from the Perl module Regexp::IPv6 and ported the code to PowerShell, to produce a .NET-compatible regular expression for validating IPv6 addresses according to the RFC 2373 standard.

I have verified that the regex the (slightly modified) Perl code produces, and the regex my PowerShell code produces are in fact equal - and I see no features used that should make it behave differently (to my knowledge; there are a few differences in the engines, but none of them should come into play here).

The author of the Perl code, Salvador Fandino, claims that This module exports the $IPv6_re regular expression that matches any valid IPv6 address as described in "RFC 2373 - 2.2 Text Representation of Addresses" but ::. Any string not compliant with such RFC will be rejected.

Since validating IPv4 addresses is part of validating an IPv6 address, you can find a regex for that in the code as well, but I have a more thorough article on validating or extracting IPv4 addresses from text here.



Example PowerShell function for validating an IPv6 address

This is the Perl code to generate the regex, ported to PowerShell.

function Test-IsValidIPv6Address {
    param(
        [Parameter(Mandatory=$true,HelpMessage='Enter IPv6 address to verify')] [string] $IP)
    $IPv4Regex = '(((25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})\.){3}(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))'
    $G = '[a-f\d]{1,4}'
    # In a case sensitive regex, use:
    #$G = '[A-Fa-f\d]{1,4}'
    $Tail = @(":",
        "(:($G)?|$IPv4Regex)",
        ":($IPv4Regex|$G(:$G)?|)",
        "(:$IPv4Regex|:$G(:$IPv4Regex|(:$G){0,2})|:)",
        "((:$G){0,2}(:$IPv4Regex|(:$G){1,2})|:)",
        "((:$G){0,3}(:$IPv4Regex|(:$G){1,2})|:)",
        "((:$G){0,4}(:$IPv4Regex|(:$G){1,2})|:)")
    [string] $IPv6RegexString = $G
    $Tail | foreach { $IPv6RegexString = "${G}:($IPv6RegexString|$_)" }
    $IPv6RegexString = ":(:$G){0,5}((:$G){1,2}|:$IPv4Regex)|$IPv6RegexString"
    $IPv6RegexString = $IPv6RegexString -replace '\(' , '(?:' # make all groups non-capturing
    [regex] $IPv6Regex = $IPv6RegexString
    if ($IP -imatch "^$IPv6Regex$") {
        $true
    } else {
        $false
    }
}

Example use

PS C:\> Test-IsValidIPv6Address -IP fe80::a584:1246:389b:fff
True

PS C:\> Test-IsValidIPv6Address -IP fe80::a584:1246:389b:
False

The actual regex (it's a big one)

This is the regex that's generated from the code in the function above. Remember that you need to use anchors, "^" at the start, and "$" at the end for a complete match when verifying. This also requires case-insensitive matching (can usually be accomplished by starting the regex with "(?i)" or by passing in a flag, or similar).

Also see my main PowerShell regular expressions article.

:(?::[a-f\d]{1,4}){0,5}(?:(?::[a-f\d]{1,4}){1,2}|:(?:(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})\.){3}(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})))|[a-f\d]{1,4}:(?:[a-f\d]{1,4}:(?:[a-f\d]{1,4}:(?:[a-f\d]{1,4}:(?:[a-f\d]{1,4}:(?:[a-f\d]{1,4}:(?:[a-f\d]{1,4}:(?:[a-f\d]{1,4}|:)|(?::(?:[a-f\d]{1,4})?|(?:(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})\.){3}(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))))|:(?:(?:(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})\.){3}(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))|[a-f\d]{1,4}(?::[a-f\d]{1,4})?|))|(?::(?:(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})\.){3}(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))|:[a-f\d]{1,4}(?::(?:(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})\.){3}(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))|(?::[a-f\d]{1,4}){0,2})|:))|(?:(?::[a-f\d]{1,4}){0,2}(?::(?:(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})\.){3}(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))|(?::[a-f\d]{1,4}){1,2})|:))|(?:(?::[a-f\d]{1,4}){0,3}(?::(?:(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})\.){3}(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))|(?::[a-f\d]{1,4}){1,2})|:))|(?:(?::[a-f\d]{1,4}){0,4}(?::(?:(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})\.){3}(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))|(?::[a-f\d]{1,4}){1,2})|:))