ThePirate42
ThePirate42

Reputation: 890

How can I verify that a string is a valid IPv4 or IPv6 address in batch?

I need to verify if a string is a valid IPv4 or IPv6 address in a Batch script, but apparently Batch doesn't have an easy way to parse an IP address.

How can I do this in Batch without using external tools? By "external tools" I mean things that aren't already present on a normal Windows installation.

By "valid IPv4 or IPv6 address" I mean a string that is in the format of an IP address, false positives with strings like 999.999.999.999 are OK (even if some basic filtering is welcome). As a rule of thumb, a solution should at least be able to distinguish an error message from an address.

I know that a similar question already exists, but that question doesn't take IPv6 into consideration and it's more strict in its definition of "valid IPv4 address" (something like 999.999.999.999 isn't acceptable).

Upvotes: 35

Views: 3450

Answers (4)

npocmaka
npocmaka

Reputation: 57252

Check for valid IPv4:

@if (@X)==(@Y) @end /* JScript comment
    @echo off
    cscript //E:JScript //nologo "%~f0"  %*
    exit /b %errorlevel%
@if (@X)==(@Y) @end JScript comment */
WScript.Quit(ValidateIPaddress(WScript.Arguments.Item(0)));
function ValidateIPaddress(ipaddress) {
 return !(/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(ipaddress))
}

For valid IPv6 address:

@if (@X)==(@Y) @end /* JScript comment
    @echo off
    cscript //E:JScript //nologo "%~f0"  %*
    exit /b %errorlevel%
@if (@X)==(@Y) @end JScript comment */
WScript.Quit(ValidateIPaddress(WScript.Arguments.Item(0)));
function ValidateIPaddress(ipaddress) {
 return !(/(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/gm.test(ipaddress))
}

Both are relying on the exit code, so here's how they can be used:

call validIPV4.bat 12.12.12.12 && (
   echo valid ipv4 
) || (
   echo invalid ipv4
)

call validIPV4.bat 12.12.12.6000 && (
  echo valid ipv4 
) || (
  echo invalid ipv4
)

The first will print valid ipv4 the second invalid ipv4.

Or you can check the errorlevel:

call validIPV6.bat "1200:0000:AB00:1234:0000:2552:7777:1313"
if %errorlevel% equ 0 ( 
  echo valid ipv6 
) else (
  echo invalid ipv6
)

Upvotes: 15

ChatoPaka
ChatoPaka

Reputation: 150

How can I do this in Batch without using external tools? By "external tools" I mean things that aren't already present on a normal Windows installation.

You can use powershell, which is bundled with all windows computers, i.e.:

ip_validate.bat

@echo off

powershell -Command "[ipaddress]::TryParse('192.168.1.1',[ref][ipaddress]::Loopback)"
powershell -Command "[ipaddress]::TryParse('192.168.1.256',[ref][ipaddress]::Loopback)"
powershell -Command "[ipaddress]::TryParse('2001:0db8:85a3:0000:0000:8a2e:0370:7334',[ref][ipaddress]::Loopback)"
powershell -Command "[ipaddress]::TryParse('20ddd01:0db8:85a3:0000:0000:8a2e:0370:7334',[ref][ipaddress]::Loopback)"

Output:

True
False
True
False

Upvotes: 6

ThePirate42
ThePirate42

Reputation: 890

After some experimenting (and googling) I managed to write a function that checks the validity of an address with the help of Powershell.

The function asks for a variable name and a string (enclosed in quotes). If the string is a valid IP, the value of the variable is set to True, else it's set to False.

set "_ip=127.0.0.1"
call :checkip _result "%_ip%"
echo %_result%

set "_ip=::1/128"
call :checkip _result "%_ip%"
echo %_result%

set "_ip=Not an ip address"
call :checkip _result "%_ip%"
echo %_result%

goto :eof

:checkip
setlocal
set _var=%1
set _ip=%~2
set _prefixlenght=%_ip:*/=%
call set _ip=%%_ip:/%_prefixlenght%=%%
for /F "usebackq tokens=*" %%g in (`powershell -c "$ipaddrobj = [ipaddress]::Any ; if (!([ipaddress]::TryParse('%_ip%', [ref]$ipaddrobj))){if (!([ipaddress]::TryParse('%_ip%'.split(':')[0], [ref]$ipaddrobj))){return $false}} ; return $true"`) do (set _ipvalid=%%g)
endlocal & set %_var%=%_ipvalid%
goto :eof

The Powershell line is a readaptation of a Powershell function that I found here in a comment.

Upvotes: 12

Hackoo
Hackoo

Reputation: 18827

Here is an attempt with Vbscript using RegEx to check both IPv4 or IPv6

RegEx Demo Here

Vbscript

Option Explicit
Dim  Title,IP,Array_IP
Title = "Test the validity of an IP address IPv4 Or IPv6"
ForceCScriptExecution(Title)

Array_IP = Array(_
    "1200:0000:AB00:1234:0000:2552:7777:1313",_
    "192.168.1.1",_
    "255.255.0.0",_
    "172.16.18.21",_
    "172.16.18.500",_
    "1600:0000:AB30:1234:0000:2552:7777:1313",_
    "172.16.300.21",_
    "172.16.18.23",_
    "172.256.18.21",_
    "255.255.255.0",_
    "255.255.255.255"_
)

For Each IP in Array_IP
    If Is_Valid(IP) = True Then
        Wscript.echo IP & " is a Valid IP Address"
    Else
        Wscript.echo IP & " is Not a Valid IP Address"
    End if
Next

Wscript.sleep 20000
'------------------------------------------------------------------------------------
Function Is_Valid(ip)
    Dim RegularExpressionObject
    Set RegularExpressionObject = New RegExp
    With RegularExpressionObject
        .Pattern = "(^((25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(25[0-5]|2[0-4]\d|1?\d?\d)$)|(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"
        .IgnoreCase = False
        If .Test(ip)= True then
            Is_Valid = True
        end if
    End With
End Function
'------------------------------------------------------------------------------------
Sub ForceCScriptExecution(Title)
    Dim Arg, Str, cmd
    cmd = "CMD /C Title " & Title &" & color 0A & Mode 80,30 & "
    If Not LCase( Right( WScript.FullName, 12 ) ) = "\cscript.exe" Then
        For Each Arg In WScript.Arguments
            If InStr( Arg, " " ) Then Arg = """" & Arg & """"
            Str = Str & " " & Arg
        Next
        CreateObject( "WScript.Shell" ).Run _
           cmd & "cscript //nologo """ & _
            WScript.ScriptFullName & _
            """ " & Str
        WScript.Quit
    End If
End Sub
'-------------------------------------------------------------------------------------

Batch File :

@echo off
Title Test the validity of an IP address IPv4 Or IPv6
set "_IP=1200:0000:AB00:1234:0000:2552:7777:1313"
Call :CheckIp "%_IP%" Validity
if [%Validity%] equ [0] ( 
    color 0A
    echo "%_IP%" is a valid ip
) else (
    Color 0C
    echo "%_IP%" is not a valid ip
)
Pause
set "_IP=192.168.500.300"
Cls
Call :CheckIp "%_IP%" Validity
if [%Validity%] equ [0] ( 
    color 0A
    echo "%_IP%" is a valid ip
) else (
    Color 0C
    echo "%_IP%" is not a valid ip
)
Pause
Exit
::--------------------------------------------------------------------------------------------------
:CheckIP <IP> <Validity>
Set "VbsFile=%Temp%\%~n0.vbs"
(
    echo WScript.Echo(Is_Valid("%~1"^)^)
    echo Function Is_Valid(ip^)
    echo    Dim RegularExpressionObject
    echo    Set RegularExpressionObject = New RegExp
    echo    With RegularExpressionObject
    echo        .Pattern = "(^((25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(25[0-5]|2[0-4]\d|1?\d?\d)$)|(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"
    echo        .IgnoreCase = False
    echo        If .Test(ip^)= True then
    echo            Is_Valid = 0
    echo        Else
    echo            Is_Valid = 1
    echo        End if
    echo    End With
    echo End Function
)>"%VbsFile%"
@for /f "delims=" %%a in ('cscript //nologo "%VbsFile%"') do set "%2=%%a"
Exit /B
::--------------------------------------------------------------------------------------------------

Upvotes: 6

Related Questions