VBScript - Check Network by Web

Environment
  • Microsoft Windows XP
  • Microsoft Windows Server 2003
  • Nagios 3.X
  • NSClient++ 0.3.5
  • Wget 1.10.X
Introduction
Write this to monitor network via Nagios. It is because can't find one can on Windows, just find some can via Linux

Basically, these need four parts - VBScript, Batch, Wget and NSClient++
  • VBScript: analyse and report the netwokr result
  • Batch: run Wget to get the performance result, due to there is a problem of getting the result directly on VBScript. If directly, would be report the wrong result to Nagios
  • Wget: download the data from the target
Wget can be downloaded from http://users.ugent.be/~bpuype/wget/

Version
2009MAY07
  • Solve some bugs
  • Improve the coding
2009FEB11
  • Add status - OK, WARNING, CRITICAL
  • Handle can't read the result file, mostly due to speed is too slow
2008DEC28
  • Add checking intranet
2008OCT27
  • The first version is just for proxy
Codes
The VBScript code
'Which folder of this
'Due to VBScript bug, can't run a application which folder name is with space,
'therefore, use the name is DOS format which the most easy way
DEFAULT_DIR = "C:\Progra~1\NSClient++\scripts\"

'Run which WGET
DEFAULT_WGET = DEFAULT_DIR & "wget.exe"

'Batch file for running wget
'Due to running WGET at servcice is difficult - set to use which proxy server and run it,
'run it via a batch
DEFAULT_WGET_BAT = DEFAULT_DIR & "RunWget.bat"

'WGET result
DEFAULT_RESULT = DEFAULT_DIR & "result.txt"

'Default value
Const DEFAULT_NOTUSEPROXY = "TRUE"
Const DEFAULT_TRUE = 1
Const DEFAULT_FALSE = -1

'Char for splitting
Const DEFAULT_CHAR_FOR_SPLIT = "***"

'Open text file mode
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8

'Status of result report - OK, Warning or Critical
Const DEFAULT_RESULT_OK = 0
Const DEFAULT_RESULT_WARNING = 1
Const DEFAULT_RESULT_CRITICAL = 2

'What speed - Direct or Proxy
Const DEFAULT_DIRECT_SPEED = "Direct"
Const DEFAULT_PROXY_SPEED = "Proxy"

'Use which one units pre seconds
Const DEFAULT_UNIT_KB = "KB/s"
Const DEFAULT_UNIT_MB = "MB/s"
Const DEFAULT_UNIT_GB = "GB/s"

'Filter what
Dim DEFAULT_FILTER_WHAT(3)
DEFAULT_FILTER_WHAT(0) = "HTTP request sent" 'Success request, waiting response
DEFAULT_FILTER_WHAT(1) = "saved" 'Success to visit the site
DEFAULT_FILTER_WHAT(2) = "failed" ' Fail to connect

'Filter for checking what status
Dim DEFAULT_FILTER_STATUS(3)
DEFAULT_FILTER_STATUS(0) = "awaiting response... "
DEFAULT_FILTER_STATUS(1) = "OK"
DEFAULT_FILTER_STATUS(2) = "failed: "

'The default unit if no provide use which one
DEFAULT_UNIT = DEFAULT_UNIT_KB

'For get argument
Set args = WScript.Arguments.Named

'Change the speed unit to the one wanted
'Result format is XXX.XX
'If the formated result < 0.0.1, wil be reutrn 0.00001
'Only accept GB/s, MB/s, KB/s
'Param Double speed
'Param String unit
'Param String finalUnit
'Return Double changeUnit
Function changeUnit(speed, unit, finalUnit)
    Dim changedUnit
  
    If unit = finalUnit Then
            changedUnit = CDbl(FormatNumber(speed, 2))
        Else
            Select Case unit
                Case DEFAULT_UNIT_KB
                    If finalUnit = DEFAULT_UNIT_MB Then
                        changedUnit = CDbl(FormatNumber(speed / 1024, 2, 0, -1 , -1))
                    Else
                        changedUnit = CDbl(FormatNumber(speed / 1024 / 1024, 2, 0, -1 , -1))
                    End If
                Case DEFAULT_UNIT_MB
                    If finalUnit = DEFAULT_UNIT_KB Then
                        changedUnit = CDbl(FormatNumber(speed * 1024, 2, 0, -1 , -1))
                    Else
                        changedUnit = CDbl(FormatNumber(speed / 1024, 2, 0, -1 , -1))
                    End If
                Case DEFAULT_UNIT_GB
                    If finalUnit = DEFAULT_UNIT_KB Then
                        changedUnit = CDbl(FormatNumber(speed * 1024 * 1024, 2, 0, -1 , -1))
                    Else
                        changedUnit = CDbl(FormatNumber(speed * 1024, 2, 0, -1 , -1))
                    End If
            End Select
    End If
  
    'If the wanted unit is too special
    If changedUnit = 0.00 Then
        changeUnit = 0.00001
    Else
        changeUnit = changedUnit
    End If
End Function

'Filter the result according to split what is wanted
'Param String sResult
'Param Array aSplitWhat
'Return Dictionary filterResult
Function filterResult(sResult, aSplitWhat)
    Dim dicFiltered
  
    Set dicFiltered = CreateObject("Scripting.Dictionary")
  
    'Split by VBScript paragraph break
    aResult = Split(sResult, VBCrLf)
  
    For Each s in aSplitWhat
        For Each i In aResult
      
            'Split the result by the wanted filter
            aSplited = Split(i, s)
          
            If UBound(aSplited) >= 1 Then
                'If not exits on the result
                'Add it the return result
                If Not dicFiltered.Exists(i) Then
                    dicFiltered.Add s, i
                End If
            End If
        Next
    Next
  
    Set filterResult = dicFiltered
End Function

'Get a report for Nagios
'Only accept GB/s, MB/s, KB/s
'Param Double speed
'Param String unit
'Param String finalUnit
'Param String whatSpeed
'Param Double warning
'Param Double critical
'Return String getNagiosData -> using || to split performance and status
Function getNagiosData(speed, unit, finalUnit, whatSpeed, warning, critical)
    changedSpeedUnit = changeUnit(speed, unit, finalUnit)
    status = isWarningOrCritical(changedSpeedUnit, warning, critical)
  
    If warning = DEFAULT_FALSE Then
        warning = ""
    End If
  
    If critical = DEFAULT_FALSE Then
        critical = ""
    End If
  
    getNagiosData = whatSpeed & " Speed: " & changedSpeedUnit & finalUnit & " |speed=" & changedSpeedUnit & finalUnit & ";" & warning & ";" & critical & ";***" & status
End Function

'Check if it has a critical unit
'If not, return false
'Return int getCritical
Function getCritical()
    If args.Exists("c") Then
        critical = args.Item("c")
      
        If IsNumeric(critical) Then
            getCritical = CDbl(FormatNumber(critical, 2, 0, -1, -1))
        Else
            getCritical = DEFAULT_FALSE
        End If
    Else
        getCritical = DEFAULT_FALSE
    End If
End Function

'Show help options
Sub getOptions()
    WScript.Echo "Get network speed result for Nagios"
    WScript.Echo ""
    WScript.Echo "/?    Show help screen"
    WScript.Echo ""
    WScript.Echo "/c    CRITICAL status if leass than INTEGER units of network speed"
    WScript.Echo "    WARNING should be provided also"
    WScript.Echo ""
    WScript.Echo "/n    Select to use which unit. It is used for RESULT, WARNING and CRITICAL"
    WScript.Echo "    If not provide this, will use KB/s"
    WScript.Echo "      0: KB/S"
    WScript.Echo "      1: MB/S"
    WScript.Echo "      2: GB/S"
    WScript.Echo ""
    WScript.Echo "/p    Select to use proxy server"
    WScript.Echo "    If not provide this, will direct to visit"
    WScript.Echo "      e.g. /p:http://localhost:8080"
    WScript.Echo ""
    WScript.Echo "/u    Select to visit which site for target"
    WScript.Echo "      e.g. /u:http://localhost"
    WScript.Echo ""
    WScript.Echo "/w    WARNING status if leass than INTEGER units of network speed"
    WScript.Echo "    CRITICAL should be provided also"
    WScript.Echo ""
    WScript.Echo "Example"
    WScript.Echo "Direct - C:\cscript CheckNetworkByWeb.vbs /u:http://localhost /n:0 /w:5.5 /c:3.3"
    WScript.Echo "Proxy - C:\cscrtip CheckNetworkByWeb.vbs /p:http://localhost:8080 /u:http://localhost /n:0"
End Sub

'Get the speed and unit from the sucess result
'First element: speed
'Second element: unit
'Param String sRequest
'Return Array getSpeedAnUnit
Function getSpeedAndUnit(sRequest)
    Dim aRespond(2)
  
    'Split to like this: "09:42:07", "8.69 MB/s) - `index.html' saved [9632]"
    split1 = Split(sRequest, "(", 2)
  
    'Split to like this: "8.69 MB/s", " - `index.html' saved [9632]"
    split2 = Split(split1(1), ")", 2)
  
    'Split to like this: "8.69", DEFAULT_UNIT_MB
    split3 = Split(split2(0), " ", 2)
  
    aRespond(0) = split3(0)
    aRespond(1) = split3(1)
  
    getSpeedAndUnit = aRespond
End Function

'Check if it has a unit selection
'If not, use the default unit
'Return String getUnit
Function getUnit()
    If args.Exists("n") Then
        unit = CInt(args.Item("n"))
      
        If unit = 2 Then
            getUnit = DEFAULT_UNIT_GB
        ElseIf unit = 1 Then
            getUnit = DEFAULT_UNIT_MB
        Else
            getUnit = DEFAULT_UNIT_KB
        End If
    Else
        getUnit = DEFAULT_UNIT_KB
    End If
End Function

'Check if it has a url target
'If not, return false
'e.g. http://hk.yahoo.com
'Return String getURL
Function getURL()
    If args.Exists("u") Then
        getURL = args.Item("u")
    Else
        getURL = DEFAULT_FALSE
    End If
End Function

'Check if it has a warning unit
'If not,  return false
'Retrun int getWarning
Function getWarning()
    If args.Exists("w") Then
        warning = args.Item("w")
      
        If IsNumeric(warning) Then
            getWarning = CDbl(FormatNumber(warning, 2, 0, -1, -1))
        Else
            getWarning = DEFAULT_FALSE
        End If
    Else
        getWarning = DEFAULT_FALSE
    End If
End Function

'Run WGET to get speed result
'WGET is run by batch as not get a easy way to use this on NSClient++
'Assum RunWget.bat at the same folder
'Param String wget: use which wget.exe
'Param String url: use which web site
'Param String useProxy: use which proxy server
'Param String result: where to save result
Function getWgetResult(runWget, wget, url, useProxy, result)
    Dim oShell
    Set oShell = WScript.CreateObject("WScript.Shell")
  
    'Assum RunWget.bat at the same location. Not use this likes parameter, due to can't run
    If useProxy = DEFAULT_NOTUSEPROXY Then
        oShell.Run "cmd /c " & runWget & " DIRECT """ & wget & """ """ & result & """ """ & url, 0, True
    Else
        oShell.Run "cmd /c " & runWget & " PROXY """ & wget & """ """ & result & """ " & url & " " & useProxy, 0, True
    End If
End Function

'To check needed parameters are prvodied
'Param String options
'Param String url
'Param int warning
'Param int critical
'Return boolean
Function goToOptions(options, url, warning, critical)
    If options = DEFAULT_TRUE Or url = DEFAULT_FALSE Then
        goToOptions = DEFAULT_TRUE
    ElseIf warning = DEAFULT_FALSE And critical = DEFAULT_FALSE Then
        goToOptions = DEFAULT_FALSE
    'Warning should be quicker than critical,  and critical should be provided
    ElseIf warning < critical And critical <= DEFAULT_FALSE Then
        goToOptions = DEFAULT_TRUE
    Else
        goToOptions = DEFAULT_FALSE
    End If
End Function

'Check if it is warning or crtical
'speed, arning and critical would be same unit
'0: OK
'1: Warning
'2: Critical
'Param Double speed
'Param Double warning
'Param Double critical
'Return int status
Function isWarningOrCritical(speed, warning, critical)
    If speed > warning Then
        isWarningOrCritical = DEFAULT_RESULT_OK
    ElseIf speed < warning And speed > critical Then
        isWarningOrCritical = DEFAULT_RESULT_WARNING
    Else
        isWarningOrCritical = DEFAULT_RESULT_CRITICAL
    End If
End Function

'Read the result file of web access
'VBScript paragraph break default is VBCrLf
'Param String result
Function readResult(result)
    Dim oFSO, oFile
  
    'Read the result of web speed
    Set oFSO = WScript.CreateObject("Scripting.FileSystemObject")
  
    readResult = DEFAULT_FALSE
  
    'To handle if the result is here
    If oFSO.FileExists(result) Then
        Set oFile = oFSO.GetFile(result)
        Set oReadFile = oFSO.OpenTextFile(result, ForReading)

        strContents = oReadFile.ReadAll()
        oReadFile.Close
      
        readResult = strContents
    End If
End Function

'Remove the result file that is saved before
'For not to read the history
'Param String result
Function removeWgetResult(result)
    Dim oShell
    Set oShell = WScript.CreateObject("WScript.Shell")
  
    'Remove result.txt
    oShell.Run "cmd /c del /q /f " & result, 0, True
End Function

'Check if wanna to show help
'Return boolean
Function showOptions()
    If args.Exists("?") Then
        showOptions = DEFAULT_TRUE
    Else
        showOptions = DEFAULT_FALSE
    End If
End Function

'Check if it has a use proxy parameter
'e.g. http://localhost:8080
'If not, return the default - Direct
'Return String useProxy
Function useProxy()
    If args.Exists("p") Then
        useProxy = args.Item("p")
    Else
        useProxy = DEFAULT_NOTUSEPROXY
    End If
End Function

'Find the one wanted in dictionary
'If not find, retrun DEFAULT_FALSE
'Param Dictionary dicRequest
'Param String sFind: find what
'Param String sSplit: split the finded by what
'Param int iPart: wanna return which part
'Return Array aResult
Function whatResult(dicRequest, sFind, sSplit, iPart)
    Dim aResult(3)
  
    aResult(0) = DEFAULT_FALSE

    If dicRequest.Exists(sFind) Then
        aResponse = Split(dicRequest.Item(sFind), sSplit, 2)
      
        'Handle if not have the wanted information
        If iPart > UBound(aResponse) Then
            iPart = UBound(aResponse)
        End If
      
        aResult(0) = DEFAULT_TRUE
        aResult(1) = aResponse(iPart)
    End If
  
    whatResult = aResult
End Function

'main
Function main()
    options = showOptions
    proxy = useProxy()
    unit = getUnit()
    url = getURL()
    critical = getCritical()
    warning = getWarning()
  
    'Handle still not receive performance data
    performance = "Not Received Performance"
    status = DEFAULT_RESULT_CRITICAL
  
    'Need to show options?
    If goToOptions(options, url, warning, critical) = DEFAULT_TRUE Then
        getOptions()
    Else
        'WGET and Result just uses the defaule one
        getWgetResult DEFAULT_WGET_BAT, DEFAULT_WGET, url, proxy, DEFAULT_RESULT
      
        'Wait for the result due to there is running WGET
        WScript.Sleep 5000
      
        'Read the result file
        sResult = readResult(DEFAULT_RESULT)
      
        Set filteredResult = filterResult(sResult, DEFAULT_FILTER_WHAT)
      
        'Check if it is success
        res = whatResult(filteredResult, DEFAULT_FILTER_WHAT(1), DEFAULT_FILTER_STATUS(1), 0)
      
        'Checking Follow by which once is occured most
        If res(0) = DEFAULT_TRUE Then
            whatSpeed = ""
          
            aSpeedAndUnit = getSpeedAndUnit(res(1))
          
            'Select what speed - proxy / direct
            If proxy = DEFAULT_NOTUSEPROXY Then
                whatSpeed = DEFAULT_DIRECT_SPEED
            Else
                whatSpeed = DEFAULT_PROXY_SPEED
            End If
          
            'Get the final result for nagios
            nagiosData = getNagiosData(aSpeedAndUnit(0), aSpeedAndUnit(1), unit, whatSpeed, warning, critical)
          
            finalRes = Split(nagiosData, DEFAULT_CHAR_FOR_SPLIT)
          
            performance = finalRes(0)
            status = finalRes(1)
        Else
            'Check if it is down
            dow = whatResult(filteredResult, DEFAULT_FILTER_WHAT(2), DEFAULT_FILTER_STATUS(2), 1)
          
            If dow(0) = DEFAULT_TRUE Then
                performance = dow(1)
                status = DEFAULT_RESULT_CRITICAL
            Else
                'Check if visiting is error
                fau = whatResult(filteredResult, DEFAULT_FILTER_WHAT(0), DEFAULT_FILTER_STATUS(0), 1)
          
                If fau(0) = DEFAULT_TRUE Then
                    performance = "Error: " & fau(1)
                    status = DEFAULT_RESULT_WARNING
                End If
            End If
        End If
      
        removeWgetResult(DEFAULT_RESULT)
  
        WScript.StdOut.WriteLine performance
      
        'Tell NSClinet++ which status
        WScript.Quit(status)
    End If
End Function

main()
The Batch code
@ECHO OFF

REM Check if via proxy or direct
IF "%1" == "PROXY" GOTO :PROXY

IF "%1" == "DIRECT" GOTO :DIRECT

:PROXY
set http_proxy=%5
"%2" -o %3 --delete-after -t 1 -T 10 %4
set http_proxy=
GOTO END

:DIRECT
"%2" -o %3 --delete-after -t 1 -T 10 %4
GOTO END

:END