I am configuring a process that checks IIS settings on a Web Server for net.tcp bindings for a particual Web Site, and if it does not exist, create it. I have this chunk of code to check
$Websites = Get-ChildItem IIS:\Sites
foreach ($Site in $Websites) {
if ($Site.name -eq "LOSSI") {
$Binding = $Site.bindings
foreach ($bind in $Binding.collection) {
if ($bind -eq "net.tcp 443:*")
{
Write-Host $bind
}
}
}
}
But I never fall into the last conditional. I have validated by hand that the binding is set to
LOSSI
3
Started
D:\LOSSI
http *:63211: net.tcp 443:
I imagine I am doing something silly wrong, but I cannot figure it out. Is there an easier way to check a website for tcp binding?
function Test-TcpPort {
<#
.SYNOPSIS
Determine if computers have the specified ports open.
.EXAMPLE
PS C:\> Test-TcpPort -ComputerName web01,sql01,dc01 -Port 5985,5986,80,8080,443
.NOTE
Example function from PowerShell Deep Dives 2013.
#>
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
[Alias("CN","Server","__Server","IPAddress")]
[string[]]$ComputerName = $env:COMPUTERNAME,
[int[]]$Port = 23,
[int]$Timeout = 5000
)
Process {
foreach ($computer in $ComputerName) {
foreach ($p in $port) {
Write-Verbose ("Checking port {0} on {1}" -f $computer, $p)
$tcpClient = New-Object System.Net.Sockets.TCPClient
$async = $tcpClient.BeginConnect($computer, $p, $null, $null)
$wait = $async.AsyncWaitHandle.WaitOne($TimeOut, $false)
if(-not $Wait) {
[PSCustomObject]#{
Computername = $ComputerName
Port = $P
State = 'Closed'
Notes = 'Connection timed out'
}
} else {
try {
$tcpClient.EndConnect($async)
[PSCustomObject]#{
Computername = $computer
Port = $p
State = 'Open'
Notes = $null
}
} catch {
[PSCustomObject]#{
Computername = $computer
Port = $p
State = 'Closed'
Notes = ("{0}" -f $_.Exception.Message)
}
}
}
}
}
}
}
Microsoft reference script for check port
add this function in
for powershell 64 bit
C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1
for powershell 32 bit
C:\Windows\SysWOW64\WindowsPowerShell\v1.0\profile.ps1
then open powershell use this
Test-TCPPort google.com -Port 80
output :
True
Related
I am in the process of re-writing the script below to be able to run in parallel, as can be seen in the code, an array of servers is passed to the script, and then it loads it onto a hash table, loops through each server at a time to do the deployment, for each server there are files to execute in a particular order (see array of files). Looking at the structure, I feel workspace is the way to go here but I could be wrong.
Where the performance gains can be seen in my opinion or having the code such that multiple servers can be executed at thesame time rather than waiting for each server to complete and move onto the next one. foreach parallel
I ran a test to call a function declared outside a workspace, it worked.Is this good practice to call a function declared outside a workspace ? I ask this because I would like to reuse some functions outside the workspace, or is it generally better to put all the code in the workspace even ones that are not intended for parallel workloads i.e one off calls to the code. ?
The below is the code I am testing with.
Function Check-Instance-Connection{
param
(
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=0)]
$sql_server,
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=1)]
$db_name
)
try
{
#Return extra useful info by using custom objects
$check_outcome = "" | Select-Object -Property log_date, stage, status, error_message
$check_outcome.log_date = (Get-Date)
$check_outcome.stage = 'Ping SQL instance for $sql_server'
#test connection for a sql instance
$connectionstring = "Data Source=$sql_server;Integrated Security =true;Initial Catalog=$db_name;Connect Timeout=5;"
$sqllconnection = New-Object System.Data.SqlClient.SqlConnection $connectionstring
$sqllconnection.Open();
$check_outcome.status = $true
$check_outcome.error_message = ''
return $check_outcome
}
Catch
{
$check_outcome.status = $false
$check_outcome.error_message = $_.Exception.Message
return $check_outcome
}
finally{
$sqllconnection.Close();
}
}
$file_list = #("deployment_1.sql","deployment_2.sql","deployment_3.sql","deployment_4.sql","deployment_5.sql")
$x = (1,"Server1",3,1),(4,"Server2",6,2),(3,"Server3",4,3)
$k = 'serverid','servername','locationid','appid' # key names correspond to data positions in each array in $x
$h = #{}
For($i=0;$i -lt $x[0].length; $i++){
$x |
ForEach-Object{
[array]$h.($k[$i]) += [string]$_[$i]
}
}
$folder = "F:\Files\"
$database_name = "Test"
foreach ($server_id in $all_server_ids)
{
$severid = $h["serverid"][$all_server_ids.indexof($server_id)]
$servername = $h["servername"][$all_server_ids.indexof($server_id)]
$locationid = $h["locationid"][$all_server_ids.indexof($server_id)]
$message = 'ServerID {0} has a servername of {1} and a location id of {2}' -f $server_id, $h["servername"][$all_server_ids.indexof($server_id)],$h["locationid"][$all_server_ids.indexof($server_id)]
Write-Output $message
Write-Output "This $severid and this $servername and this $locationid"
foreach ($file in $file_list)
{
$is_instance_ok = Check-Instance-Connection $servername $database_name
if ($is_instance_ok.check_outcome -eq $true){
invoke-sqlcmd -ServerInstance "$servername" -inputfile $folder$file -Database "$database_name" -Querytimeout 60 -OutputSqlErrors $true -ConnectionTimeout 10 -ErrorAction Continue -Errorvariable generated_error | Out-Null
}
}
}
Thanks, I did a lot more research and looked at a lot of examples on how workflows work. This is what I have come up with.
Workflow RunExecution
{
Function Check-Instance-Connection{
param
(
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=0)]
$sql_server,
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=1)]
$db_name
)
try
{
#Return extra useful info by using custom objects
$check_outcome = "" | Select-Object -Property log_date, stage, status, error_message
$check_outcome.log_date = (Get-Date)
$check_outcome.stage = 'Ping SQL instance for $sql_server'
#test connection for a sql instance
$connectionstring = "Data Source=$sql_server;Integrated Security =true;Initial Catalog=$db_name;Connect Timeout=5;"
$sqllconnection = New-Object System.Data.SqlClient.SqlConnection $connectionstring
$sqllconnection.Open();
$check_outcome.status = $true
$check_outcome.error_message = ''
return $check_outcome
}
Catch
{
$check_outcome.status = $false
$check_outcome.error_message = $_.Exception.Message
return $check_outcome
}
finally{
$sqllconnection.Close();
}
}
$file_list = #("deployment_1.sql","deployment_2.sql","deployment_3.sql","deployment_4.sql","deployment_5.sql")
$x = (1,"server1\DEV3",3,1),(4,"serer1\DEV2",6,2),(3,"serer2\DEV1",4,3)
$k = 'serverid','servername','locationid','appid'
$h = #{}
For($i=0;$i -lt $x[0].length; $i++){
$x |
ForEach-Object{
[array]$h.($k[$i]) += [string]$_[$i]
}
}
$folder = "C:\Temp\"
$database_name = "Test"
$all_server_ids = $h['serverid']
foreach -parallel ($server_id in $all_server_ids)
{
$severid = $h["serverid"][$all_server_ids.indexof($server_id)]
$servername = $h["servername"][$all_server_ids.indexof($server_id)]
$locationid = $h["locationid"][$all_server_ids.indexof($server_id)]
foreach ($file in $file_list)
{
# $check_fine = $is_instance_ok.check_outcome
# if ($check_fine = $true){
invoke-sqlcmd -ServerInstance "$servername" -inputfile $folder$file -Database "$database_name" -Querytimeout 60 -OutputSqlErrors $true -ConnectionTimeout 10 -ErrorAction Continue
write-output "invoke-sqlcmd -ServerInstance $servername -inputfile $folder$file -Database $database_name -Querytimeout 60 -OutputSqlErrors $true -ConnectionTimeout 10 -ErrorAction Continue "
# }
}
}
}
RunExecution
This is my first program in powershell, Im trying to get from the user input and then pinging the IP address or the hostname, Creating text file on the desktop.
But if the user wants the add more than one IP I get into infinite loop.
Here Im asking for IP address.
$dirPath = "C:\Users\$env:UserName\Desktop"
function getUserInput()
{
$ipsArray = #()
$response = 'y'
while($response -ne 'n')
{
$choice = Read-Host '
======================================================================
======================================================================
Please enter HOSTNAME or IP Address, enter n to stop adding'
$ipsArray += $choice
$response = Read-Host 'Do you want to add more? (y\n)'
}
ForEach($ip in $ipsArray)
{
createFile($ip)
startPing($ip)
}
}
Then I creating the file for each IP address:
function createFile($ip)
{
$textPath = "$($dirPath)\$($ip).txt"
if(!(Test-Path -Path $textPath))
{
New-Item -Path $dirPath -Name "$ip.txt" -ItemType "file"
}
}
And now you can see the problem, Because I want the write with TIME format, I have problem with the ForEach loop, When I start to ping, And I cant reach the next element in the array until I stop
the cmd.exe.
function startPing($ip)
{
ping.exe $ip -t | foreach {"{0} - {1}" -f (Get-Date), $_
} >> $dirPath\$ip.txt
}
Maybe I should create other files ForEach IP address and pass params?
Here's a old script I have. You can watch a list of computers in a window.
# pinger.ps1
# example: pinger yahoo.com
# pinger c001,c002,c003
# $list = cat list.txt; pinger $list
param ($hostnames)
#$pingcmd = 'test-netconnection -port 515'
$pingcmd = 'test-connection'
$sleeptime = 1
$sawup = #{}
$sawdown = #{}
foreach ($hostname in $hostnames) {
$sawup[$hostname] = $false
$sawdown[$hostname] = $false
}
#$sawup = 0
#$sawdown = 0
while ($true) {
# if (invoke-expression "$pingcmd $($hostname)") {
foreach ($hostname in $hostnames) {
if (& $pingcmd -count 1 $hostname -ea 0) {
if (! $sawup[$hostname]) {
echo "$([console]::beep(500,300))$hostname is up $(get-date)"
$sawup[$hostname] = $true
$sawdown[$hostname] = $false
}
} else {
if (! $sawdown[$hostname]) {
echo "$([console]::beep(500,300))$hostname is down $(get-date)"
$sawdown[$hostname] = $true
$sawup[$hostname] = $false
}
}
}
sleep $sleeptime
}
pinger microsoft.com,yahoo.com
microsoft.com is down 11/08/2020 17:54:54
yahoo.com is up 11/08/2020 17:54:55
Have a look at PowerShell Jobs. Note that there are better and faster alternatives (like thread jobs, runspaces, etc), but for a beginner, this would be the easiest way. Basically, it starts a new PowerShell process.
A very simple example:
function startPing($ip) {
Start-Job -ScriptBlock {
param ($Address, $Path)
ping.exe $Address -t | foreach {"{0} - {1}" -f (Get-Date), $_ } >> $Path
} -ArgumentList $ip, $dirPath\$ip.txt
}
This simplified example does not take care of stopping the jobs. So depending on what behavior you want, you should look that up.
Also, note there there is also PowerShell's equivalent to ping, Test-Connection
I would like to create a powershell script to perform a TCP port scanner that can list the open TCP ports for a given IP address.
here is what I did so far, this is not perfect and I would love some feedback and corrections
port = (80)
network = (192.168.0)
ErrorActionPreference= ‘silentlycontinue’
{ $ip = “{0}.{1}” –F $network,$add
If(Test-Connection –BufferSize 32 –Count 1 –quiet –ComputerName $ip)
{ $socket = new-object System.Net.Sockets.TcpClient($ip, $port)
the problem with this is doesn't scan all the TCP port, and I am not sure how to make it do that.
There are modules you can leverage for this use case.
Find-Module -Name '*nmap*' |
Format-Table -AutoSize
<#
Version Name Repository Description
------- ---- ---------- -----------
1.0.7 xNmap PSGallery Powershell DSC Configuration Script for installing Nmap versions 6.49 (Beta 4), 6.47, 6.46, 6.45, 6.40, and 6.25...
0.6.0 PoshNmap PSGallery A wrapper for NMAP Network Discovery
1.3.1 PSnmap PSGallery Svendsen Tech's PSnmap is an asynchronous Linux nmap look-alike for PowerShell. Ping sweeps and scans a network (accepts CIDR notation) for s...
...
#>
Why not use the purpose-built cmdlet for this use case?
# get function / cmdlet details
Get-Command -Name Test-NetConnection -Syntax
(Get-Command -Name Test-NetConnection).Parameters.Keys
Get-help -Name Test-NetConnection -Full
Get-help -Name Test-NetConnection -Online
Get-help -Name Test-NetConnection -Examples
Point of note:
Earlier Windows PowerShell versions do not have Test-NetConnection if that is your use case, but even then, why do this from scratch, vs leveraging existing samples and tweaking as needed?
Well, unless this is just a learning exercise. Even then that does not mean you'd not look to other examples first.
'powershell tcp port scanner'
Samples provided by the search string.
# Example 01
<#
Creating a Port Scanner with Windows PowerShell
https://devblogs.microsoft.com/scripting/creating-a-port-scanner-with-windows-powershell
#>
# Creating a Port Scanner with Windows PowerShell
$port = 80
$net = “192.168.0”
$range = 1..254
foreach ($r in $range)
{
$ip = “{0}.{1}” -F $net,$r
if(Test-Connection -BufferSize 32 -Count 1 -Quiet -ComputerName $ip)
{
$socket = new-object System.Net.Sockets.TcpClient($ip, $port)
If($socket.Connected)
{
"$ip listening to port $port"
$socket.Close() }
}
}
# Example 02
<#
Port scan subnets with PSnmap for PowerShell
https://www.powershelladmin.com/wiki/Port_scan_subnets_with_PSnmap_for_PowerShell
#>
# Port scan subnets with PSnmap for PowerShell
#$computer, $port = $args[0,1] # assign values to these
$mysock = new-object net.sockets.tcpclient
$IAsyncResult = [IAsyncResult] $mysock.BeginConnect($computer, $port, $null, $null)
measure-command { $succ = $iasyncresult.AsyncWaitHandle.WaitOne(3000, $true) } | % totalseconds
$succ
$mysock.Connected
$mysock.Dispose()
# Example 03:
<#
A Simple Network Port Scanner in PowerShell
https://www.nextofwindows.com/a-simple-network-port-scanner-in-powershell
#>
# #requires -Version 1
function Test-Port
{
Param([string]$ComputerName,$port = 5985,$timeout = 1000)
try
{
$tcpclient = New-Object -TypeName system.Net.Sockets.TcpClient
$iar = $tcpclient.BeginConnect($ComputerName,$port,$null,$null)
$wait = $iar.AsyncWaitHandle.WaitOne($timeout,$false)
if(!$wait)
{
$tcpclient.Close()
return $false
}
else
{
# Close the connection and report the error if there is one
$null = $tcpclient.EndConnect($iar)
$tcpclient.Close()
return $true
}
}
catch
{
$false
}
}
.
Hello, Team!
I have pretty nice solution.
Advances:
Parallel scan multiple ports
Support TCP, UDP protocols
Show banner from remote
Configured parameters
EXAMPLE:
Test-Port -ComputerName $ComputerName -Port $Port [-Protocol $Protocol="TCP"] [-Timeout $Timeout=1000] [-ThrottleLimit $ThrottleLimit=1024] [-ReceiveBufferSize $ReceiveBufferSize=2048] [-PortHelper $PortHelper] [-Banner $Banner]
PS. Tested on powershell 7
function Test-Port {
<#
.SYNOPSIS
Test port
.EXAMPLE
Test-Port -ComputerName $ComputerName -Port $Port [-Protocol $Protocol="TCP"] [-Timeout $Timeout=1000] [-ThrottleLimit $ThrottleLimit=1024] [-ReceiveBufferSize $ReceiveBufferSize=2048] [-PortHelper $PortHelper] [-Banner $Banner]
.NOTES
AUTHOR Alexk
CREATED 07.04.21
VER 1
#>
[CmdletBinding()]
param (
[Parameter( Mandatory = $true, Position = 0, HelpMessage = "Computer name." )]
[string] $ComputerName,
[Parameter( Mandatory = $true, Position = 1, HelpMessage = "Port number." )]
[int[]] $Port,
[Parameter( Mandatory = $false, Position = 2, HelpMessage = "Protocol name." )]
[ValidateSet("TCP","UDP")]
[string] $Protocol = "TCP",
[Parameter( Mandatory = $false, Position = 3, HelpMessage = "Connection timeout in milliseconds." )]
[int] $Timeout = 1000,
[Parameter( Mandatory = $false, Position = 4, HelpMessage = "Simultanius thread number." )]
[int] $ThrottleLimit = 1024,
[Parameter( Mandatory = $false, Position = 5, HelpMessage = "Receive buffer size in bytes." )]
[int] $ReceiveBufferSize = 2048,
[Parameter( Mandatory = $false, Position = 6, HelpMessage = "Port helper. Help object with details oboit ports." )]
[PSobject[]] $PortHelper,
[Parameter( Mandatory = $false, Position = 7, HelpMessage = "Get remote banner." )]
[switch] $Banner
)
begin {
$result = #()
}
process {
$result += $Port | ForEach-Object -Parallel {
try {
$ComputerName = $Using:ComputerName
$Protocol = $Using:protocol
$Timeout = $Using:Timeout
$Banner = $Using:Banner
$ReceiveBufferSize = $Using:ReceiveBufferSize
$Port = $_
$Result = $Null
if ( $protocol -eq "TCP" ){
$Client = [System.Net.Sockets.TcpClient]::new()
[void] $Client.ConnectAsync( $ComputerName, $Port ).Wait( $Timeout )
$Connected = $Client.Connected
}
Else {
$Client = [System.Net.Sockets.UdpClient]::new()
[void] $Client.Connect( $ComputerName, $Port )
$Connected = $True
}
$PSO = [PSCustomObject]#{
RemoteHostname = $ComputerName
Protocol = $protocol
RemotePort = $Port
Opened = $Connected
TimeoutInMillisecond = $Timeout
SourceHostname = $env:COMPUTERNAME
}
if ( $Banner -and $Connected -and ( $Protocol -eq "TCP" ) ){
$Stream = $Client.GetStream()
$Stream.ReadTimeOut = $Timeout
if ( $Stream.CanRead ){
$Data = [System.Byte[]]::new( $ReceiveBufferSize )
[void] $Stream.Read( $Data, 0, $Data.Length ) #| Out-Null
$BannerText = ( [System.Text.Encoding]::ASCII.GetString( $Data ) ).Trim( [char]$null )
}
$Stream.Dispose()
$PSO | Add-Member -NotePropertyName "Banner" -NotePropertyValue $BannerText
}
$Client.Dispose()
$result = $PSO
}
Catch {
switch ( $_.Exception.HResult ) {
-2146233087 {
#timeout
if ( $Stream ){
$Stream.Dispose()
}
$Client.Dispose()
$PSO | Add-Member -NotePropertyName "Banner" -NotePropertyValue ""
$result = $PSO
}
Default {
Add-ToLog -Message "Error while connecting [$ComputerName] on [$( $protocol ):$( $Port )].`n$_" -logFilePath $Global:gsScriptLogFilePath -Display -category "test-port" -Status "error"
$result = #()
}
}
}
return $result
} -ThrottleLimit $ThrottleLimit
}
end {
if ( $PortHelper ){
foreach ( $item in $result ){
$Selected = $PortHelper | Where-Object { ( $_.Port -eq $item.RemotePort ) -and ( $item.Protocol -in ($_.Protocol.split(',')) )}
if ( $Selected ){
$item | Add-Member -NotePropertyName 'Description' -NotePropertyValue "$($Selected.Description) ($($Selected.Status))"
}
}
}
return $result
}
}
This only prints the last server in the list, I'm looking to get all servers and print to screen
$machines = (Get-BrokerMachine -AdminAddress $adminaddress -DesktopGroupName $deliverygroup | Select-Object DNSname).DNSname
foreach($machine in $machines){
$machinelist = Get-BrokerMachine -HostedMachineName $machine
if($machinelist.InMaintenanceMode -eq $true){
$status = "$machine is in maintenance mode"
}else {
$status = "$machine is not in maintenance mode"
}
}
Write-Host $status
Here is a more PowerShell-like approach (not tested):
Get-BrokerMachine -AdminAddress $adminaddress -DesktopGroupName $deliverygroup | ForEach-Object {
$machineName = $_.DNSName
[PSCustomObject] #{
"MachineName" = $machineName
"MaintenanceMode" = (Get-BrokerMachine -HostedMachineName $machine).InMaintenanceMode
}
} | Export-Csv "C:\whatever\results.csv" -NoTypeInformation
$Status is constantly being overwritten by the current machine in your list.
You're looking for:
$Status+=
As opposed to:
$Status=
You'll also want to explicitly state that $Status will be an array at the beginning like so:
$Status=#()
Or when you create the variable and omit the line at the beginning.
[array]$Status +=
Otherwise, you'll get results that run together as it will be treated as a [String]
another funky mode :
function get-BrokerMachineMode
{
param (
[Parameter(Mandatory = $true)]
[string[]]$machines
)
begin
{
$ErrorActionPreference = 'Stop'
Add-Type -Language CSharp #"
public class BrokenBroker {
qpublic System.String MachineName;
public System.String MaintenanceMode;
public BrokenBroker (string MachineName, string MaintenanceMode)
{
this.MachineName = MachineName;
this.MaintenanceMode = IsInMaintenanceMode;
}
}
"#
$status = #()
Write-Verbose "Created objects..."
}
process
{
try
{
$machines = (Get-BrokerMachine -AdminAddress $adminaddress `
-DesktopGroupName $deliverygroup | Select-Object DNSname).DNSname
foreach ($machine in $machines)
{
Write-Verbose "Checking machine: $machine"
$machinelist = Get-BrokerMachine -HostedMachineName $machine
if ($machinelist.InMaintenanceMode -eq $true)
{
$status += New-Object BrokenBroker($machine, $true)
}
else
{
$status += New-Object BrokenBroker($machine, $false)
}
}
}
catch
{
Write-Error $error[0].Exception.Message
}
$status
}
end
{
Write-Verbose "Done"
}
}
this is a function you just must to load then you can launch it just by using this command:
$computers = get-content = {PATH TO TXT FILE}
$list = get-BrokerMachineMode -machines $computers -Verbose
I was trying to check whether the port is opened or not using powershell like follows.
(new-object Net.Sockets.TcpClient).Connect("10.45.23.109", 443)
This method works , but the output is not user-friendly. It means if there are no errors then it has access. Is there any way to check for success and display some message like " Port 443 is operational"?
If you're running Windows 8/Windows Server 2012 or newer, you can use the Test-NetConnection command in PowerShell.
Ex:
Test-NetConnection -Port 53 -ComputerName LON-DC1
I improved Salselvaprabu's answer in several ways:
It is now a function - you can put in your powershell profile and use anytime you need
It can accept host as hostname or as ip address
No more exceptions if host or port unavaible - just text
Call it like this:
Test-Port example.com 999
Test-Port 192.168.0.1 80
function Test-Port($hostname, $port)
{
# This works no matter in which form we get $host - hostname or ip address
try {
$ip = [System.Net.Dns]::GetHostAddresses($hostname) |
select-object IPAddressToString -expandproperty IPAddressToString
if($ip.GetType().Name -eq "Object[]")
{
#If we have several ip's for that address, let's take first one
$ip = $ip[0]
}
} catch {
Write-Host "Possibly $hostname is wrong hostname or IP"
return
}
$t = New-Object Net.Sockets.TcpClient
# We use Try\Catch to remove exception info from console if we can't connect
try
{
$t.Connect($ip,$port)
} catch {}
if($t.Connected)
{
$t.Close()
$msg = "Port $port is operational"
}
else
{
$msg = "Port $port on $ip is closed, "
$msg += "You may need to contact your IT team to open it. "
}
Write-Host $msg
}
Actually Shay levy's answer is almost correct but i got an weird issue as i mentioned in his comment column. So i split the command into two lines and it works fine.
$Ipaddress= Read-Host "Enter the IP address:"
$Port= Read-host "Enter the port number to access:"
$t = New-Object Net.Sockets.TcpClient
$t.Connect($Ipaddress,$Port)
if($t.Connected)
{
"Port $Port is operational"
}
else
{
"Port $Port is closed, You may need to contact your IT team to open it. "
}
You can check if the Connected property is set to $true and display a friendly message:
$t = New-Object Net.Sockets.TcpClient "10.45.23.109", 443
if($t.Connected)
{
"Port 443 is operational"
}
else
{
"..."
}
With the latest versions of PowerShell, there is a new cmdlet, Test-NetConnection.
This cmdlet lets you, in effect, ping a port, like this:
Test-NetConnection -ComputerName <remote server> -Port nnnn
I know this is an old question, but if you hit this page (as I did) looking for this information, this addition may be helpful!
I tried to improve the suggestion from mshutov.
I added the option to use the output as an object.
function Test-Port($hostname, $port)
{
# This works no matter in which form we get $host - hostname or ip address
try {
$ip = [System.Net.Dns]::GetHostAddresses($hostname) |
select-object IPAddressToString -expandproperty IPAddressToString
if($ip.GetType().Name -eq "Object[]")
{
#If we have several ip's for that address, let's take first one
$ip = $ip[0]
}
} catch {
Write-Host "Possibly $hostname is wrong hostname or IP"
return
}
$t = New-Object Net.Sockets.TcpClient
# We use Try\Catch to remove exception info from console if we can't connect
try
{
$t.Connect($ip,$port)
} catch {}
if($t.Connected)
{
$t.Close()
$object = [pscustomobject] #{
Hostname = $hostname
IP = $IP
TCPPort = $port
GetResponse = $True }
Write-Output $object
}
else
{
$object = [pscustomobject] #{
Computername = $IP
TCPPort = $port
GetResponse = $False }
Write-Output $object
}
Write-Host $msg
}
If you are using older versions of Powershell where Test-NetConnection isn't available, here is a one-liner for hostname "my.hostname" and port "123":
$t = New-Object System.Net.Sockets.TcpClient 'my.hostname', 123; if($t.Connected) {"OK"}
Returns OK, or an error message.
Great answer by mshutov & Salselvaprabu. I needed something a little bit more robust, and that checked all IPAddresses that was provided instead of checking only the first one.
I also wanted to replicate some of the parameter names and functionality than the Test-Connection function.
This new function allows you to set a Count for the number of retries, and the Delay between each try. Enjoy!
function Test-Port {
[CmdletBinding()]
Param (
[string] $ComputerName,
[int] $Port,
[int] $Delay = 1,
[int] $Count = 3
)
function Test-TcpClient ($IPAddress, $Port) {
$TcpClient = New-Object Net.Sockets.TcpClient
Try { $TcpClient.Connect($IPAddress, $Port) } Catch {}
If ($TcpClient.Connected) { $TcpClient.Close(); Return $True }
Return $False
}
function Invoke-Test ($ComputerName, $Port) {
Try { [array]$IPAddress = [System.Net.Dns]::GetHostAddresses($ComputerName) | Select-Object -Expand IPAddressToString }
Catch { Return $False }
[array]$Results = $IPAddress | % { Test-TcpClient -IPAddress $_ -Port $Port }
If ($Results -contains $True) { Return $True } Else { Return $False }
}
for ($i = 1; ((Invoke-Test -ComputerName $ComputerName -Port $Port) -ne $True); $i++)
{
if ($i -ge $Count) {
Write-Warning "Timed out while waiting for port $Port to be open on $ComputerName!"
Return $false
}
Write-Warning "Port $Port not open, retrying..."
Sleep $Delay
}
Return $true
}
boiled this down to a one liner sets the variable "$port389Open" to True or false - its fast and easy to replicate for a list of ports
try{$socket = New-Object Net.Sockets.TcpClient($ipAddress,389);if($socket -eq $null){$Port389Open = $false}else{Port389Open = $true;$socket.close()}}catch{Port389Open = $false}
If you want ot go really crazy you can return the an entire array-
Function StdPorts($ip){
$rst = "" | select IP,Port547Open,Port135Open,Port3389Open,Port389Open,Port53Open
$rst.IP = $Ip
try{$socket = New-Object Net.Sockets.TcpClient($ip,389);if($socket -eq $null){$rst.Port389Open = $false}else{$rst.Port389Open = $true;$socket.close();$ipscore++}}catch{$rst.Port389Open = $false}
try{$socket = New-Object Net.Sockets.TcpClient($ip,53);if($socket -eq $null){$rst.Port53Open = $false}else{$rst.Port53Open = $true;$socket.close();$ipscore++}}catch{$rst.Port53Open = $false}
try{$socket = New-Object Net.Sockets.TcpClient($ip,3389);if($socket -eq $null){$rst.Port3389Open = $false}else{$rst.Port3389Open = $true;$socket.close();$ipscore++}}catch{$rst.Port3389Open = $false}
try{$socket = New-Object Net.Sockets.TcpClient($ip,547);if($socket -eq $null){$rst.Port547Open = $false}else{$rst.Port547Open = $true;$socket.close();$ipscore++}}catch{$rst.Port547Open = $false}
try{$socket = New-Object Net.Sockets.TcpClient($ip,135);if($socket -eq $null){$rst.Port135Open = $false}else{$rst.Port135Open = $true;$socket.close();$SkipWMI = $False;$ipscore++}}catch{$rst.Port135Open = $false}
Return $rst
}
When scanning closed port it becomes unresponsive for long time. It seems to be quicker when resolving fqdn to ip like:
[System.Net.Dns]::GetHostAddresses("www.msn.com").IPAddressToString