即使没有服务在远程机器上侦听,也要检查端口是否打开
Check if port is open even if no service is listening on remote machine
场景:我进入公司网络并需要自动执行一些网络检查。其中之一是验证特定端口是否未被防火墙阻止,但通常没有服务侦听远程计算机上的这些端口,据我了解,Test-NetConnection 和 portqry,return false/filtered如果对方没有响应,但实际上并不意味着防火墙阻止了端口,对吗?
思路:我先用Test-NetConnection看看有没有回复,这样测试就ok了。如果远程端在端口上没有响应:
- 我创建一个 TCPClient 对象
- 向远程计算机调用 ScriptBlock 以在特定端口上创建监听器
- 尝试从源计算机连接到目标计算机,以确保端口已打开
现在这是我想出的:
function Test-Port([string] $server, [int] $port) {
$out = $false;
if(Test-NetConnection -ComputerName $server -Port $port | Select-Object -ExpandProperty TcpTestSucceeded) {
$out = $true;
} else {
$TcpClient = New-Object System.Net.Sockets.TcpClient;
try {
$Session = New-PSSession -ComputerName $server -ErrorAction Stop;
if($null -ne $Session) {
$RemoteLastExitCode = Invoke-Command -Session $Session -ScriptBlock {
param($p)
try {
$Listener = [System.Net.Sockets.TcpListener]$p;
$Listener.Start();
while($true) {
$client = $Listener.AcceptTcpClient();
$client.Close();
Exit $p;
}
} catch [System.Net.Sockets.SocketException] {
Write-Host "Socket Error: $($_)";
} finally {
$Listener.Stop();
}
$LASTEXITCODE;
} -ArgumentList $port
try {
$TcpClient.Connect($server, $port);
} catch [System.Net.Sockets.SocketException] {
Write-Host "TCP Client Error: $($_)";
} finally {
if($RemoteLastExitCode -eq $port) { $out = $true; }
$TcpClient.Close();
}
}
} catch [System.Management.Automation.Remoting.PSRemotingTransportException] {
Write-Host "Error: Unable to open remote session to $($server). Skipping." -ForegroundColor Red;
} finally {
Remove-PSSession -Session $Session -ErrorAction SilentlyContinue;
}
}
return $out;
}
不过,好像不行。此外,当这个 运行s 在第一次之后再次出现时,我收到错误消息“通常只允许每个套接字地址 (protocol/network address/port) 的一次使用”。我想 Socket 侦听器或 TCPClient 没有正确获取 closed/Stopped。
我也不确定 Invoke-Command 是否正在执行阻塞。我还尝试使用 -AsJob 参数 运行 它,但端口测试失败。
只是说,我进行了手动测试(登录到目标计算机,创建了一个侦听器并从源连接)以确保端口已打开,以证明该测试应该 return True。
提前致谢。
我有相同的东西,但对于 azure 工作簿,它可以帮助你 - 它会从你的订阅中获取所有 public IP,并将远程登录到 3389 和 1433 端口,如果打开 -发送电子邮件。
workflow PortChecker
{
#RunAs account name
$connectionName = "AzureRunAsConnection"
#connect to azure subscription
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
$connectionResult = Connect-AzAccount -Tenant $servicePrincipalConnection.TenantID -ApplicationId $servicePrincipalConnection.ApplicationID -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint -ServicePrincipal
$exclude = "Not Assigned"
$publicIps = Get-AzPublicIpAddress | where -Property IpAddress -CNotMatch $exclude | Select -ExpandProperty IpAddress
function Test-Port
{
param
(
[Parameter(Position=0, Mandatory = $True, HelpMessage="Provide destination source", ValueFromPipeline = $true)]
$Address,
[Parameter(Position=1, Mandatory = $False, HelpMessage="Provide port numbers", ValueFromPipeline = $true)]
$Port
)
$ErrorActionPreference = "SilentlyContinue"
$Results = @()
ForEach ($A in $Address) {
$Object = New-Object PSCustomObject
$Object | Add-Member -MemberType NoteProperty -Name "Destination" -Value $A
ForEach ($P in $Port) {
try
{
$tcpClient = new-object Net.Sockets.TcpClient
$tcpClient.Connect("$A", $P)
$Object = "For IP: $Address Port $P is open"
}
catch
{
$Object = "For IP: $Address Port $P is closed"
}
finally
{
$tcpClient.Dispose()
}
$Results += $Object
}
If($Results){
$Results
}}}
$allinfo = foreach -parallel ($publicIps in $publicIps) {Test-Port $publicIps -Port 1433, 3389}
$username = "---"
$password = '---' | ConvertTo-SecureString -asPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($username,$password)
#write-output $allinfo
$alertIP = $allinfo | where-object {$_ -like '*open*'}
#write-output $alertIP
if ($allinfo -like '*open*') { Send-MailMessage -SmtpServer %email-server% -useSsl -Port 587 -Credential $cred -From %From% -To %to% -Subject "New open port detected" -Body "New open port detected $alertIP, please check the Azure Portal" }
else {}
}
我终于找到了解决办法。
我的问题是:
- 调用命令,即使是远程的,也是执行阻塞的
- 如果无法建立连接,则未关闭 TCPListener
- 我没有正确返回远程调用命令执行的结果
这是一个工作版本,它执行以下操作:
- 使用 Test-NetConnection 检查 $port 是否在 $server 上打开并且正在侦听;
- 如果没有,创建TCPClient + TCPListener
- 在启动 TCPlistener 的远程 $server 上启动 Invoke-Command 作业,这样我们就有了一个端点来测试防火墙是否阻止了 $port;
- 尝试将 TCPClient 连接到 $server
上指定的 $port
- 如果成功,调用命令作业 returns 端口号,否则为空;
- 如果没有连接,TCPListener 将在 10 秒后关闭;
P.S.: 在我的示例中,我寻找一个已经存在的特定会话名称,您可以更改该部分。
function Test-Port([string] $server, [int] $port) {
$out = $false;
if(Test-NetConnection -ComputerName $server -Port $port | Select-Object -ExpandProperty TcpTestSucceeded) {
$out = $true;
} else {
$removeSession = $false;
$TcpClient = New-Object System.Net.Sockets.TcpClient;
try {
$Session = Get-PSSession | Where-Object -FilterScript { $_.State -eq "Opened" -and ($_.Name -eq "$($env:COMPUTERNAME)$($server)" -or $_.Name -eq "$($server)$($env:COMPUTERNAME)") };
if($null -eq $Session) {
$Session = New-PSSession -ComputerName $server -ErrorAction Stop;
$removeSession = $true;
}
Invoke-Command -Session $Session -AsJob -JobName PortTest -ScriptBlock {
param($p)
$Script:return = $null;
try {
$IPAddress = Get-NetIPConfiguration | Where-Object -FilterScript { $null -ne $_.IPv4DefaultGateway } |
Select-Object -ExpandProperty IPv4Address | Select-Object -ExpandProperty IPAddress;
$Listener = [System.Net.Sockets.TcpListener]::new($IPAddress, $p);
$Listener.Start();
$counter = 0;
while($true) {
if(!$Listener.Pending()) {
if($counter -eq 20) {
$Listener.Stop();
break;
}
$counter++;
Start-Sleep -Milliseconds 500;
continue;
}
$client = $Listener.AcceptTcpClient();
$Script:return = $p;
$client.Close();
break;
}
} catch [System.Net.Sockets.SocketException] {
Write-Host "Socket Error: $($_)";
} finally {
$Listener.Stop();
}
return $Script:return;
} -ArgumentList $port
$TcpClient.ReceiveTimeout = 10000;
$TcpClient.SendTimeout = 10000;
$TcpClient.Connect($server, $port);
$RemoteReturn = Wait-Job -Name PortTest | Receive-Job;
} catch [System.Management.Automation.Remoting.PSRemotingTransportException] {
Write-Host "Error: Unable to open remote session to $($server). Skipping." -ForegroundColor Red;
} catch [System.Net.Sockets.SocketException] {
Write-Host "TCP Client Error: $($_)";
} finally {
if($RemoteReturn -eq $port) { $out = $true; }
$TcpClient.Close();
if($removeSession) { Remove-PSSession -Session $Session -ErrorAction SilentlyContinue; }
}
}
return $out;
}
场景:我进入公司网络并需要自动执行一些网络检查。其中之一是验证特定端口是否未被防火墙阻止,但通常没有服务侦听远程计算机上的这些端口,据我了解,Test-NetConnection 和 portqry,return false/filtered如果对方没有响应,但实际上并不意味着防火墙阻止了端口,对吗?
思路:我先用Test-NetConnection看看有没有回复,这样测试就ok了。如果远程端在端口上没有响应:
- 我创建一个 TCPClient 对象
- 向远程计算机调用 ScriptBlock 以在特定端口上创建监听器
- 尝试从源计算机连接到目标计算机,以确保端口已打开
现在这是我想出的:
function Test-Port([string] $server, [int] $port) {
$out = $false;
if(Test-NetConnection -ComputerName $server -Port $port | Select-Object -ExpandProperty TcpTestSucceeded) {
$out = $true;
} else {
$TcpClient = New-Object System.Net.Sockets.TcpClient;
try {
$Session = New-PSSession -ComputerName $server -ErrorAction Stop;
if($null -ne $Session) {
$RemoteLastExitCode = Invoke-Command -Session $Session -ScriptBlock {
param($p)
try {
$Listener = [System.Net.Sockets.TcpListener]$p;
$Listener.Start();
while($true) {
$client = $Listener.AcceptTcpClient();
$client.Close();
Exit $p;
}
} catch [System.Net.Sockets.SocketException] {
Write-Host "Socket Error: $($_)";
} finally {
$Listener.Stop();
}
$LASTEXITCODE;
} -ArgumentList $port
try {
$TcpClient.Connect($server, $port);
} catch [System.Net.Sockets.SocketException] {
Write-Host "TCP Client Error: $($_)";
} finally {
if($RemoteLastExitCode -eq $port) { $out = $true; }
$TcpClient.Close();
}
}
} catch [System.Management.Automation.Remoting.PSRemotingTransportException] {
Write-Host "Error: Unable to open remote session to $($server). Skipping." -ForegroundColor Red;
} finally {
Remove-PSSession -Session $Session -ErrorAction SilentlyContinue;
}
}
return $out;
}
不过,好像不行。此外,当这个 运行s 在第一次之后再次出现时,我收到错误消息“通常只允许每个套接字地址 (protocol/network address/port) 的一次使用”。我想 Socket 侦听器或 TCPClient 没有正确获取 closed/Stopped。
我也不确定 Invoke-Command 是否正在执行阻塞。我还尝试使用 -AsJob 参数 运行 它,但端口测试失败。 只是说,我进行了手动测试(登录到目标计算机,创建了一个侦听器并从源连接)以确保端口已打开,以证明该测试应该 return True。
提前致谢。
我有相同的东西,但对于 azure 工作簿,它可以帮助你 - 它会从你的订阅中获取所有 public IP,并将远程登录到 3389 和 1433 端口,如果打开 -发送电子邮件。
workflow PortChecker
{
#RunAs account name
$connectionName = "AzureRunAsConnection"
#connect to azure subscription
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
$connectionResult = Connect-AzAccount -Tenant $servicePrincipalConnection.TenantID -ApplicationId $servicePrincipalConnection.ApplicationID -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint -ServicePrincipal
$exclude = "Not Assigned"
$publicIps = Get-AzPublicIpAddress | where -Property IpAddress -CNotMatch $exclude | Select -ExpandProperty IpAddress
function Test-Port
{
param
(
[Parameter(Position=0, Mandatory = $True, HelpMessage="Provide destination source", ValueFromPipeline = $true)]
$Address,
[Parameter(Position=1, Mandatory = $False, HelpMessage="Provide port numbers", ValueFromPipeline = $true)]
$Port
)
$ErrorActionPreference = "SilentlyContinue"
$Results = @()
ForEach ($A in $Address) {
$Object = New-Object PSCustomObject
$Object | Add-Member -MemberType NoteProperty -Name "Destination" -Value $A
ForEach ($P in $Port) {
try
{
$tcpClient = new-object Net.Sockets.TcpClient
$tcpClient.Connect("$A", $P)
$Object = "For IP: $Address Port $P is open"
}
catch
{
$Object = "For IP: $Address Port $P is closed"
}
finally
{
$tcpClient.Dispose()
}
$Results += $Object
}
If($Results){
$Results
}}}
$allinfo = foreach -parallel ($publicIps in $publicIps) {Test-Port $publicIps -Port 1433, 3389}
$username = "---"
$password = '---' | ConvertTo-SecureString -asPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($username,$password)
#write-output $allinfo
$alertIP = $allinfo | where-object {$_ -like '*open*'}
#write-output $alertIP
if ($allinfo -like '*open*') { Send-MailMessage -SmtpServer %email-server% -useSsl -Port 587 -Credential $cred -From %From% -To %to% -Subject "New open port detected" -Body "New open port detected $alertIP, please check the Azure Portal" }
else {}
}
我终于找到了解决办法。 我的问题是:
- 调用命令,即使是远程的,也是执行阻塞的
- 如果无法建立连接,则未关闭 TCPListener
- 我没有正确返回远程调用命令执行的结果
这是一个工作版本,它执行以下操作:
- 使用 Test-NetConnection 检查 $port 是否在 $server 上打开并且正在侦听;
- 如果没有,创建TCPClient + TCPListener
- 在启动 TCPlistener 的远程 $server 上启动 Invoke-Command 作业,这样我们就有了一个端点来测试防火墙是否阻止了 $port;
- 尝试将 TCPClient 连接到 $server 上指定的 $port
- 如果成功,调用命令作业 returns 端口号,否则为空;
- 如果没有连接,TCPListener 将在 10 秒后关闭;
P.S.: 在我的示例中,我寻找一个已经存在的特定会话名称,您可以更改该部分。
function Test-Port([string] $server, [int] $port) {
$out = $false;
if(Test-NetConnection -ComputerName $server -Port $port | Select-Object -ExpandProperty TcpTestSucceeded) {
$out = $true;
} else {
$removeSession = $false;
$TcpClient = New-Object System.Net.Sockets.TcpClient;
try {
$Session = Get-PSSession | Where-Object -FilterScript { $_.State -eq "Opened" -and ($_.Name -eq "$($env:COMPUTERNAME)$($server)" -or $_.Name -eq "$($server)$($env:COMPUTERNAME)") };
if($null -eq $Session) {
$Session = New-PSSession -ComputerName $server -ErrorAction Stop;
$removeSession = $true;
}
Invoke-Command -Session $Session -AsJob -JobName PortTest -ScriptBlock {
param($p)
$Script:return = $null;
try {
$IPAddress = Get-NetIPConfiguration | Where-Object -FilterScript { $null -ne $_.IPv4DefaultGateway } |
Select-Object -ExpandProperty IPv4Address | Select-Object -ExpandProperty IPAddress;
$Listener = [System.Net.Sockets.TcpListener]::new($IPAddress, $p);
$Listener.Start();
$counter = 0;
while($true) {
if(!$Listener.Pending()) {
if($counter -eq 20) {
$Listener.Stop();
break;
}
$counter++;
Start-Sleep -Milliseconds 500;
continue;
}
$client = $Listener.AcceptTcpClient();
$Script:return = $p;
$client.Close();
break;
}
} catch [System.Net.Sockets.SocketException] {
Write-Host "Socket Error: $($_)";
} finally {
$Listener.Stop();
}
return $Script:return;
} -ArgumentList $port
$TcpClient.ReceiveTimeout = 10000;
$TcpClient.SendTimeout = 10000;
$TcpClient.Connect($server, $port);
$RemoteReturn = Wait-Job -Name PortTest | Receive-Job;
} catch [System.Management.Automation.Remoting.PSRemotingTransportException] {
Write-Host "Error: Unable to open remote session to $($server). Skipping." -ForegroundColor Red;
} catch [System.Net.Sockets.SocketException] {
Write-Host "TCP Client Error: $($_)";
} finally {
if($RemoteReturn -eq $port) { $out = $true; }
$TcpClient.Close();
if($removeSession) { Remove-PSSession -Session $Session -ErrorAction SilentlyContinue; }
}
}
return $out;
}