Functions/Test-Port.ps1
# inspired by https://gallery.technet.microsoft.com/scriptcenter/97119ed6-6fb2-446d-98d8-32d823867131 Function Test-Port { <# .SYNOPSIS Tests a Port or a range of ports on a specific ComputerName(s). .DESCRIPTION Tests a Port or a range of ports on a specific ComputerName(s). Creates a custom object with the properties: ComputerName, Protocol, Port, Open, Notes. .PARAMETER ComputerName A single ComputerName or array of ComputerName to test the port connection on. .PARAMETER Port Port number to test ([int16] 0 - 65535), an array can also be passed .PARAMETER TCP Use TCP as the transport protocol .PARAMETER UDP Use UDP as the transport protocol .PARAMETER TimeOut Sets a timeout for TCP or UDP port query. (In milliseconds, Default is 1000) .EXAMPLE Test-Port -ComputerName 'server' -port 80 Checks port 80 on server 'server' to see if it is listening .EXAMPLE 'server' | Test-Port -Port 80 Checks port 80 on server 'server' to see if it is listening .EXAMPLE Test-Port -ComputerName @("server1","server2") -Port 80 Checks port 80 on server1 and server2 to see if it is listening .EXAMPLE @("server1","server2") | Test-Port -Port 80 Checks port 80 on server1 and server2 to see if it is listening .EXAMPLE (Get-Content hosts.txt) | Test-Port -Port 80 Checks port 80 on servers in host file to see if it is listening .EXAMPLE Test-Port -ComputerName (Get-Content hosts.txt) -Port 80 Checks port 80 on servers in host file to see if it is listening .EXAMPLE Test-Port -ComputerName (Get-Content hosts.txt) -Port @(1..59) Checks a range of ports from 1-59 on all servers in the hosts.txt file .OUTPUTS [psobject] An array of objects containing the fields: ComputerName A string containing the computer name or ip address that was passed to the function Protocol A string being either 'TCP' or 'UDP' Port An integer in the range 1 - 65535 Open A boolean Notes Any notes when attempting to make a connection .LINK about_Properties #> #region Parameter [CmdletBinding(ConfirmImpact = 'Low')] [OutputType('psobject')] Param( [Parameter(Mandatory, HelpMessage = 'Enter a ComputerName or IP address', Position = 0, ValueFromPipeline)] [string[]] $ComputerName, [Parameter(Position = 1, Mandatory, HelpMessage = 'Enter an integer port number (1-65535)')] [uint16[]] $Port, [int] $Timeout = 1000, [switch] $TCP, [switch] $UDP ) #endregion Parameter begin { Write-Verbose -Message "Starting $($MyInvocation.Mycommand)" 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 $oldEA = $ErrorActionPreference $ErrorActionPreference = 'SilentlyContinue' Write-Verbose -Message "Saving current value of `$ErrorActionPreference [$($oldEa)] and setting it to 'Stop'" $report = @() } process { foreach ($c in $ComputerName) { foreach ($p in $port) { if ($tcp) { #Create temporary holder #$temp = '' | Select-Object -Property ComputerName, Protocol, Port, Open, Notes $temp = New-Object -TypeName psobject -Property @{ Computername = ''; Protocol = ''; Port = 0; Open = $false; Notes = '' } #Create object for connecting to port on computer $tcpobject = New-Object -TypeName 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($Timeout, $false) #if timeout if (!$wait) { #Close connection $tcpobject.Close() Write-Verbose -Message 'Connection Timeout' #Build report $temp.ComputerName = $c $temp.Port = $p $temp.Protocol = 'TCP' $temp.Open = $false $temp.Notes = 'Connection to Port Timed Out' } else { $error.Clear() $null = $tcpobject.EndConnect($connect) #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.ComputerName = $c $temp.Port = $p $temp.Protocol = 'TCP' $temp.Open = $false $temp.Notes = "$message" } else { #Build report $temp.ComputerName = $c $temp.Port = $p $temp.Protocol = 'TCP' $temp.Open = $true $temp.Notes = "Successful link to $c $($temp.Protocol) port $p" } } #Reset failed value $failed = $Null #Merge temp array with report $report += $temp } if ($udp) { #$temp = '' | Select-Object -Property ComputerName, Protocol, Port, Open, Notes $temp = New-Object -TypeName psobject -Property @{ Computername = ''; Protocol = ''; Port = 0; Open = $false; Notes = '' } Write-Verbose -Message 'Making UDP connection to remote server' $Socket = New-Object -TypeName Net.Sockets.Socket -ArgumentList ( 'InterNetwork', 'Dgram', 'Udp' ) $Socket.SendTimeOut = $Timeout # ms $Socket.ReceiveTimeOut = $Timeout # ms try { $Socket.Connect( $C, $p ) $Buffer = New-Object -TypeName byte[] -ArgumentList 48 $Buffer[0] = 27 Write-Verbose -Message 'Sending message to remote host' $null = $Socket.Send( $Buffer ) $null = $Socket.Receive( $Buffer ) $temp.ComputerName = $c $temp.Port = $p $temp.Protocol = 'UDP' $temp.Open = $true $temp.Notes = '' } catch { Write-Verbose -Message 'Communication failed' Write-Error -Message $error[0] $temp.ComputerName = $c $temp.Port = $p $temp.Protocol = 'UDP' $temp.Open = $false $temp.Notes = $error[0].exception } $socket.dispose() Remove-Variable -Name socket #Merge temp array with report $report += $temp } } } } end { #Generate Report Write-Output -InputObject $report Write-Verbose -Message "Resetting value of `$ErrorActionPreference back to [$($oldEa)]" Write-Verbose -Message "Ending $($MyInvocation.Mycommand)" $ErrorActionPreference = $oldEA } } #EndFunction Test-Port |