Windows batch script to see if a sequence of server/ports is open?

11,492

Solution 1

Here you go. Pay it forward. :) To answer your question directly, just use a for loop to loop through your servers and perform a portqry on each. Edit: That PowerShell snippet you found is useful for getting rid of the PortQry dependency.

@echo off
setlocal

set "servers=dev1 dev2 dev3 test1 test2 test2:8080 prod prod:443"

for %%I in (%servers%) do (
    for /f "tokens=1,2 delims=:" %%a in ("%%I") do (
        set "port=%%~b"
        if not defined port set "port=80"
        setlocal enabledelayedexpansion
        call :handshake "%%~a" "!port!" && (
            echo %%a port !port!: OK
        ) || (
            echo %%a port !port!: Error
        )
        endlocal
    )
)

goto :EOF

:handshake <server> <port>
powershell "$t=new-object Net.Sockets.TcpClient;$c=$t.BeginConnect('%~1',%~2,{},{});if($c.AsyncWaitHandle.WaitOne(1000)){$t.EndConnect($c);exit 0};exit 1"
exit /b %ERRORLEVEL%

Here's the original solution using PortQry 2.0:

@echo off
setlocal

set "servers=dev1 dev2 dev3 test1 test2 test2:8080 prod prod:443"

for %%I in (%servers%) do (
    for /f "tokens=1,2 delims=:" %%a in ("%%I") do (
        set "port=%%~b"
        if not defined port set "port=80"
        setlocal enabledelayedexpansion
        portqry -n "%%~a" -e "!port!" >NUL 2>NUL && (
            echo %%a port !port!: OK
        ) || (
            echo %%a port !port!: Error
        )
        endlocal
    )
)

If all you are testing are web services, it might make more sense to go about this in a different way. You can use the Microsoft.XMLHTTP COM object to get rid of that portqry dependency; and the responses acquired thusly will be more relevant to HTTP services. (For example, if you've got a VNC server running on port 8080 where you expect a web service to be listening instead, portqry would probably return success when you'd need it to return fail.)

Anyway, save this as a .bat script and salt to taste.

@if (@CodeSection == @Batch) @then

@echo off
setlocal

set "servers=dev1 dev2 dev3 test1 test2 test2:8080 prod prod:443"

for %%I in (%servers%) do (
    for /f "tokens=1,2 delims=:" %%a in ("%%I") do (
        set "port=%%~b"
        if not defined port set "port=80"
        setlocal enabledelayedexpansion
        cscript /nologo /e:JScript "%~f0" "%%~a" "!port!" && (
            echo %%a port !port!: OK
        ) || (
            echo %%a port !port!: Error
        )
        endlocal
    )
)

goto :EOF

@end // end batch / begin JScript chimera

var server = WSH.Arguments(0),
    port = WSH.Arguments(1),
    protocol = port == 443 ? 'https' : 'http',
    URL = protocol + '://' + server + ':' + port + '/',
    XHR = WSH.CreateObject('Microsoft.XMLHTTP');

XHR.open('GET', URL);
XHR.setRequestHeader('User-Agent','XMLHTTP/1.0');
XHR.send('');
while (XHR.readyState != 4) WSH.Sleep(25);
WSH.Quit(XHR.status - 200);

Solution 2

This is what I ended up replacing the VBScript above with - a file called porttest.ps1 which is run with powershell -f porttest.ps1

param(
    [string] $remoteHost = "arbitrary-remote-hostname",
    [int] $port = 23
     )

# Open the socket, and connect to the computer on the specified port
write-host "Connecting to $remoteHost on port $port"
$tcpobject = new-Object system.Net.Sockets.TcpClient 
$connect = $tcpobject.BeginConnect($remoteHost,$port,$null,$null) 
#Configure a timeout before quitting - time in milliseconds 
$wait = $connect.AsyncWaitHandle.WaitOne(1000,$false) 
If (-Not $Wait) {
    'Timeout'
    exit 1
} Else {
    $error.clear()
    $tcpobject.EndConnect($connect) | out-Null 
        If ($Error[0]) {
            Write-warning ("{0}" -f $error[0].Exception.Message)
            exit 1
        } Else {
            'Port open!'
            exit 0
        }
    }
Share:
11,492
user1544101
Author by

user1544101

Updated on June 09, 2022

Comments

  • user1544101
    user1544101 almost 2 years

    I can run a single command to see if a port is open:

    portqry -n servername -e 80
    

    I want to run this against a list of servers:

    1. DEV1 80
    2. DEV2 80
    3. DEV3 80
    4. TEST1 80
    5. TEST2 80
    6. PROD 80

    I want to test them all using a single Windows batch script and see which portsare open and which ones are closed. (And I don't want it to fall over on the first closed port).

    My question is: Is there a Windows batch script to see if a sequence of server/ports is open?

    Additional: I'm aware there are other questions asking how to check if a port is open. None of them are about scripting it for a sequence of ports in a reliable way.

  • user1544101
    user1544101 about 9 years
    I really like your answer - but it assumes I'm contacting an http server, when in fact I only wanted to see if the port was open. What would need to be modified to make it so?
  • rojo
    rojo about 9 years
    Try the first script in my edit. I left the second in case it's useful to someone else in the future, since it's pretty clever if I do say so myself.
  • user1544101
    user1544101 about 9 years
    Other one was definitely better - but just wanted to contribute some other thoughts to keep the ideas bubbling.
  • rojo
    rojo about 9 years
    Nice idea using PowerShell for Net.Sockets.TcpClient. I incorporated that into my answer, if you're interested.
  • user1544101
    user1544101 about 9 years
    Ok - the powershell one is awesome.
  • npocmaka
    npocmaka about 6 years
    so you are checking non http/https port with XMLHTTP object...?
  • rojo
    rojo about 6 years
    @npocmaka Not all web servers run on ports 80 and 443, and some users may wish to test whether a web server responds through a proxy. *shrug*
  • Kiran Maroju
    Kiran Maroju almost 6 years
    Hi Rojo, your script using Portquery is working like charm. But it gives only OK/Error as output, i need also whether port "Listening"/"Not listening". Could you please help me with that
  • rojo
    rojo almost 6 years
    @KiranMaroju OK = Listening, Error = Not listening?
  • Kiran Maroju
    Kiran Maroju almost 6 years
    @rojo "Filtered" ports also showing as Error. I need output in 3 different statuses for 3 different responses from portquery
  • rojo
    rojo almost 6 years
    @KiranMaroju Sorry, I've never actually used portqry and don't feel like downloading it. Does portqry have a different exit code between filtered and not listening? Use echo %ERRORLEVEL% to see after running a query. If not, you'll have to use a for /F loop to scrape the stdout output of portqry to determine listening, filtered, or closed. If you can't figure it out, create a new question post.