Free Monitoring, Port Test Community Update Module

Free Monitoring, Port Test Community Update Module

Free Monitoring, Port Test Community Update Module

This post has already been read 2658 times!

I have had a lot of requests for my free monitoring tool and am really glad to be getting some great feedback about how it’s all working.

That said, I can’t test everything and tend to test the scripts on Windows Server 2012 and up (my bad I know!). So today when I got an email from one of the users saying that it’s not working at all I was more than happy to help get it working.  We had a couple of emails digging into it and in the end I just sent over a GoToMeeting request. I figured it would be a great opportunity to talk face to face and get to the bottom of the issue.

Quite quickly (and over the phone) it became apparent that there was an issue with the module I was using to test the port connectivity.

So, let’s get it out there how to fix this.

The Issue

During the port test module I use a CommandLet called Test-NetConnection to test connectivity to a passed in port. Microsoft ship this as part of Windows 8, 8.1 and 10 as well as Windows Server 2012, 2012 R2 and 2016.

The user in question was using Windows 7 as their monitoring host and therefore the script was failing on the port test.

The Solution

When Deploying the script there will be a ps1 file in the modules directory called global.ps1. This file contains the functions that are used across all the individual monitoring modules and yep, you guessed it, the PortTest Function.

Open up this file in your Favourite script editor and replace the below code

First add the below code to the start of the global.ps1 file

 

#region GWL Mods
# Because Windows 7 is being used, this module was obtained from Microsoft's Gallery (Test-Port.ps1) and RENAMED to Test-NetConnection
function Test-NetConnection
{
<#   
.SYNOPSIS   
    Tests port on computer. 
.DESCRIPTION 
    Tests port on computer.
.PARAMETER computer 
    Name of server to test the port connection on.
.PARAMETER port 
    Port to test
.PARAMETER tcp 
    Use tcp port    
.PARAMETER udp 
    Use udp port  
.PARAMETER UDPTimeOut
    Sets a timeout for UDP port query. (In milliseconds, Default is 1000)      
.PARAMETER TCPTimeOut
    Sets a timeout for TCP port query. (In milliseconds, Default is 1000)              
.NOTES   
    Name: Test-Port.ps1
       Renamed by GWL
    Author: Boe Prox 
    DateCreated: 18Aug2010      
.LINK   
    https://boeprox.wordpress.org
#>    

       [cmdletbinding(
                              DefaultParameterSetName = '',
                              ConfirmImpact = 'low'
       )]
       Param (
              [Parameter(
                              Mandatory = $True,
                              Position = 0,
                              ParameterSetName = '',
                              ValueFromPipeline = $True)]
              [array]$ComputerName,
              [Parameter(
                              Position = 1,
                              Mandatory = $True,
                              ParameterSetName = '')]
              [array]$port,
              [Parameter(
                              Mandatory = $False,
                              ParameterSetName = '')]
              [int]$TCPtimeout = 1000,
              [Parameter(
                              Mandatory = $False,
                              ParameterSetName = '')]
              [string]$InformationLevel,
              [Parameter(
                              Mandatory = $False,
                              ParameterSetName = '')]
              [switch]$TCP,
              [Parameter(
                              Mandatory = $False,
                              ParameterSetName = '')]
              [switch]$UDP
       )
       Begin
       {
              If (!$tcp -AND !$udp) { $tcp = $True }
              #Typically you never do this, but in this case I felt it was for the benefit of the function 
              #as any errors will be noted in the output of the report         
              $ErrorActionPreference = "SilentlyContinue"
              $report = @()
       } # Begin
       Process
       {
              ForEach ($c in $ComputerName)
              {
                     ForEach ($p in $port)
                     {
                           If ($tcp)
                           {
                                  #Create temporary holder  
                                  $temp = "" | Select Server, Port, TypePort, Open, Notes
                                  #Create object for connecting to port on computer 
                                  $tcpobject = new-Object system.Net.Sockets.TcpClient
                                  #Connect to remote machine's port               
                                  $connect = $tcpobject.BeginConnect($c, $p, $null, $null)
                                  #Configure a timeout before quitting 
                                  $wait = $connect.AsyncWaitHandle.WaitOne($TCPtimeout, $false)
                                  #If timeout 
                                  If (!$wait)
                                  {
                                         #Close connection 
                                         $tcpobject.Close()
                                         Write-Verbose "Connection Timeout"
                                         #Build report 
                                         $temp.Server = $c
                                         $temp.Port = $p
                                         $temp.TypePort = "TCP"
                                         $temp.Open = $False
                                         $temp.Notes = "Connection to Port Timed Out"
                                  }
                                  Else
                                  {
                                         $error.Clear()
                                         $tcpobject.EndConnect($connect) | out-Null
                                         #If error 
                                         If ($error[0])
                                         {
                                                #Begin making error more readable in report 
                                                [string]$string = ($error[0].exception).message
                                                $message = (($string.split(":")[1]).replace('"', "")).TrimStart()
                                                $failed = $true
                                         }
                                         #Close connection     
                                         $tcpobject.Close()
                                         #If unable to query port to due failure 
                                         If ($failed)
                                         {
                                                #Build report 
                                                $temp.Server = $c
                                                $temp.Port = $p
                                                $temp.TypePort = "TCP"
                                                $temp.Open = $False
                                                $temp.Notes = "$message"
                                         }
                                         Else
                                         {
                                                #Build report 
                                                $temp.Server = $c
                                                $temp.Port = $p
                                                $temp.TypePort = "TCP"
                                                $temp.Open = $True
                                                $temp.Notes = ""
                                         }
                                  }
                                  #Reset failed value 
                                  $failed = $Null
                                  #Merge temp array with report             
                                  $report += $temp
                           }
                           If ($udp)
                           {
                                  #Create temporary holder  
                                  $temp = "" | Select Server, Port, TypePort, Open, Notes
                                  #Create object for connecting to port on computer 
                                  $udpobject = new-Object system.Net.Sockets.Udpclient
                                  #Set a timeout on receiving message
                                  $udpobject.client.ReceiveTimeout = $UDPTimeout
                                  #Connect to remote machine's port                
                                  Write-Verbose "Making UDP connection to remote server"
                                  $udpobject.Connect("$c", $p)
                                  #Sends a message to the host to which you have connected.
                                  Write-Verbose "Sending message to remote host"
                                  $a = new-object system.text.asciiencoding
                                  $byte = $a.GetBytes("$(Get-Date)")
                                  [void]$udpobject.Send($byte, $byte.length)
                                  #IPEndPoint object will allow us to read datagrams sent from any source. 
                                  Write-Verbose "Creating remote endpoint"
                                  $remoteendpoint = New-Object system.net.ipendpoint([system.net.ipaddress]::Any, 0)
                                  Try
                                  {
                                         #Blocks until a message returns on this socket from a remote host.
                                         Write-Verbose "Waiting for message return"
                                         $receivebytes = $udpobject.Receive([ref]$remoteendpoint)
                                         [string]$returndata = $a.GetString($receivebytes)
                                         If ($returndata)
                                         {
                                                Write-Verbose "Connection Successful"
                                                #Build report 
                                                $temp.Server = $c
                                                $temp.Port = $p
                                                $temp.TypePort = "UDP"
                                                $temp.Open = $True
                                                $temp.Notes = $returndata
                                                $udpobject.close()
                                         }
                                  }
                                  Catch
                                  {
                                         If ($Error[0].ToString() -match "\bRespond after a period of time\b")
                                         {
                                                #Close connection 
                                                $udpobject.Close()
                                                #Make sure that the host is online and not a false positive that it is open
                                                If (Test-Connection -comp $c -count 1 -quiet)
                                                {
                                                       Write-Verbose "Connection Open"
                                                       #Build report 
                                                       $temp.Server = $c
                                                       $temp.Port = $p
                                                       $temp.TypePort = "UDP"
                                                       $temp.Open = $True
                                                       $temp.Notes = ""
                                                }
                                                Else
                                                {
                                <#
                                It is possible that the host is not online or that the host is online, 
                                but ICMP is blocked by a firewall and this port is actually open.
                                #>                                               
                                                       Write-Verbose "Host maybe unavailable"
                                                       #Build report 
                                                       $temp.Server = $c
                                                       $temp.Port = $p
                                                       $temp.TypePort = "UDP"
                                                       $temp.Open = $False
                                                       $temp.Notes = "Unable to verify if port is open or if host is unavailable."
                                                }
                                         }
                                         ElseIf ($Error[0].ToString() -match "forcibly closed by the remote host")
                                         {
                                                #Close connection 
                                                $udpobject.Close()
                                                Write-Verbose "Connection Timeout"
                                                #Build report 
                                                $temp.Server = $c
                                                $temp.Port = $p
                                                $temp.TypePort = "UDP"
                                                $temp.Open = $False
                                                $temp.Notes = "Connection to Port Timed Out"
                                         }
                                         Else
                                         {
                                                $udpobject.close()
                                         }
                                  }
                                  #Merge temp array with report             
                                  $report += $temp
                           }

                    }
             }
      } # Process
      End
       {
              #Generate Report 
              if ($InformationLevel -eq 'Quiet')
              {
                     $report.Open
              } # if $informationLevel -eq 'Quiet'
              else
              {
                     $report
                     } # else $InformationLevel
       } # End
} # Test-NetConnection (replacement)
#endregion GWL Mods

Then make the below modifications to the TestNetConnection funcation

Old Code

function TestNetConnection ($ServerName, $PortString) {
 #Log testing connection server and port
 LogVerbose "Testing Port Connectivity to $ServerName on Port $PortString" $VerboseFile "White"

#Convert Port to type Integer
 [int]$PortInt = [convert]::ToInt32($PortString, 10)
 LogVerbose "Convert Port to Integer: $PortString" $VerboseFile "White"

#Log and Test Port Connectivity
 LogVerbose "Testing Port Connectivity to $PortString" $VerboseFile "White"
 Return Test-NetConnection -ComputerName $ServerName -port $PortInt -InformationLevel Quiet
}

With the following

New Code

function TestNetConnection ($ServerName, $PortString) {
 #Log testing connection server and port
 LogVerbose "Testing Port Connectivity to $ServerName on Port $PortString" $VerboseFile "White"

#Convert Port to type Integer
 [int]$PortInt = [convert]::ToInt32($PortString, 10)
 LogVerbose "Convert Port to Integer: $PortString" $VerboseFile "White"

#Log and Test Port Connectivity
 LogVerbose "Testing Port Connectivity to $PortString" $VerboseFile "White"
 Return Test-NetConnection -ComputerName $ServerName -port $PortInt -InformationLevel Quiet -TCP
}

Long Term

So, how can we stop this happening long term. In short, more testing. As I have always said this is a community project and this has proved the value of the community and their input on this project.

I will test the scripts as much as I can but need your help!

If you are willing to be credited and assist in testing drop me an email and I will send the new scripts to you before releasing them to the upload site. This was we can all cover off as many different test scenarios within the community.

Drop me an email to dave@bretty.me.uk and a quick rundown of your test server, along with what your going to monitor. This way we can make sure we cover off as many scenarios as possible.

So, credit for this find.

Thanks Bill Rogge a Systems Administrator at Great-West Financial. Appreciate the feedback and the time taken to make this project better with some great community input.

Great chatting with you earlier and hope the monitoring is rocking for you now.

#CommunityRocks

If you just want an updated global.ps1 file then you can grab it from the ShareFile link you already have. If you don’t have it send me an email on dave@bretty.me.uk and I will send you the details.

Laters

b@m

3 thoughts on “Free Monitoring, Port Test Community Update Module

  1. Alex Spicola

    Was really excited to see you updated. However, I wish it wasn’t a requirement to reach out to Google…

    1. Bretty Post author

      I can always look at putting in a non-internet connection option – just means I would need to write the modules to output the graph

  2. Pingback: Free Monitoring, Port Test Community Update Module

Leave a Reply

Your email address will not be published. Required fields are marked *