Коллеги, приветствую. В этой небольшой статье-заметке я бы хотел представить несколько командлетов Powershell для работы с TCP и ICMP.

Зачем это нужно?

Время от времени возникает ситуация при которой необходимо проверить доступность различных узлов, как серверов, так и пользовательских ПК. Обычно для решения таких задач, может устанавливаться дополнительное ПО. Однако, есть и другие, более простые решения, не требующее инсталляции компонентов на компьютер. В этой статье мы рассмотрим проверку портов TCP и проверку через ICMP. Для работы потребуется только Powershell и умение его запускать. 🙂 Ниже будут представлены три вариации командлетов для проверки.

Как этим пользоваться

Если у Вас пока не было опыта работы с Powershell, ничего страшного. Для того, чтобы воспользоваться инструментами, которые мы рассматриваем в этой статье, понадобится выполнить несколько несложных действий.

  • Запустить Windows Powershell ISE и включить область сценариев (CTRL+R).
  • Скопировать код из этой статьи и вставить в область сценариев.
  • Выполнить код нажатием клавиши F5.

После выполнения этих действий, командлеты станут доступны для использования в консоли снизу, под областью сценариев.

После вставки и запуска кода в области сценариев, появляется возможность использования командлета в консоли ниже.

Проверка доступности TCP порта

Первый вариант содержит командлет, позволяющий проверить доступность одного порта для разных хостов.

function Test-Port 
{
[CmdletBinding()]
    param
    (
        [string[]]$Hostname='localhost',
        [int]$Port='80',
        [int]$Timeout='1000'
    )

    foreach ($h in $Hostname)
        { 
            $tab = "`t"
            $requestCallback = $state = $null 
            $client = New-Object System.Net.Sockets.TcpClient 
            $beginConnect = $client.BeginConnect($h, $Port, $requestCallback, $state) 
            Start-Sleep -milli $Timeout 

            if ($client.Connected) 
                { 
                    Write-Host $h':'$Port -ForegroundColor Green
                } 
            else 
                { 
                    Write-Host $h':'$Port -ForegroundColor Red
                } 
            $client.Close() 
        } 
}

Попробуем запустить командлет и проверить его выполнение. Для примера укажем несколько хостов и проверим доступность 80 TCP-порта.

Мы можем убедиться, что 80 TCP-порт доступен на трех хостах.

Теперь попробуем сделать тоже самое, но для 53 TCP-порта.

Мы можем убедиться, что 53 TCP-порт доступен на одном хосте.

Сканер открытых TCP портов

Второй вариант немного отличается тем, что здесь можно указывать несколько портов для проверки. Также у него снижено время ожидания ответа TCP, для того, чтобы нам не пришлось долго ждать результатов проверки большого количества портов и хостов.

function Check-Ports 
{
[CmdletBinding()]
    param
    (
        [string[]]$Hostname='localhost',
        [int[]]$Port=1..1000,
        [int]$Timeout='300'
    )
        
     foreach ($h in $Hostname)
     {
        foreach ($p in $Port)    
        { 
            $requestCallback = $state = $null 
            $client = New-Object System.Net.Sockets.TcpClient 
            $beginConnect = $client.BeginConnect($h, $p, $requestCallback, $state) 
            Start-Sleep -milli $Timeout

            if ($client.Connected) 
                { 
                    Write-Host $h':'$p -ForegroundColor Green
                }
            $client.Close()
        }   
    }
}

Давайте попробуем выполнить проверку портов для узла google.ru. По умолчанию командлет проверяет порты от 1 до 1000.

При проверке нашлось два открытых TCP-порта.

Если нам необходим другой диапазон портов, мы можем определить его при помощи переменной и подставить в параметр -Ports.

Во время выполнения командлета может показаться, что он завис. 🙂 Мы можем убедиться в обратном запустив TCPView или утилиту resmon.

Процесс powershell.exe будет генерировать SYN_SENT запросы.

Также мы можем указать несколько хостов через запятую.

В ходе работы с командлетом, может возникнуть ситуация, при которой время ожидания ответа будет настолько малым, что удаленный хост просто не успеет ответить, либо настолько большим, что нам придется долго ждать результаты проверки. Для того, чтобы мы могли сами указывать это время, мы можем воспользоваться параметром -Timeout, который указывается в миллисекундах.

Для наглядной демонстрации попробуем замерить время выполнения командлета (по умолчанию значение Timeout = 300).

На выполнение проверки 50 портов ушло 15 секунд

Теперь запустим командлет с параметром -Timeout 200.

На выполнение проверки 50 портов ушло 10 секунд

Сканируем хосты по ICMP

Третий командлет может пригодиться в случае, когда необходимо проверить доступность хостов не через TCP, а при помощи ICMP. Один из таких случаев — у нас есть устройство, которому был назначен статический IP-адрес и мы не знаем точно, какой именно адрес был определен, только подсеть.

#Allow run powershell scripts for current user
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

#Get subnet calculator powershell function
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$URL = "https://gallery.technet.microsoft.com/scriptcenter/PowerShell-Subnet-db45ec74/file/141596/2/Get-IPs.ps1"
$Path = "$env:HOMEPATH\Get-IPs.ps1"
(New-Object System.Net.WebClient).DownloadFile($URL, $Path)
. $Path

function Ping-Hosts 
{

[CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true)]
        [array]$Subnet
    )

    #Define subnet and ping hosts
    $Subnet = Get-IPs -Subnets $Subnet
    Write-Host "OK. Ping hosts in subnets starting. Be patient."
    foreach ($h in $Subnet)
        {
            $result = Test-Connection -Count 1 -ComputerName $h -ErrorAction SilentlyContinue
            if ($result)
                {
                    Write-Host $h 'is Online' -ForegroundColor Green 
                }
        }
}

Запустим командлет и определим сеть для поиска. Например, попробуем поискать устройства во внутренней сети моего провайдера связи. В качестве параметра командлета укажем сеть для ICMP сканирования в формате IP-адрес/маска.

В процессе поиска нам удалось связаться с 7 хостами.

Мы можем указать несколько сетей сразу. Для этого мы просто перечисляем их в параметре через запятую.

Поиск доступных хостов будет выполнен последовательно.

Итоги

Итак, мы посмотрели в действии на несколько командлетов позволяющие протестировать доступность хостов. Какой командлет выбрать и для какого сценария — дело конкретного случая. Коллеги, если у Вас есть замечания или дополнения, приглашаю обсудить это в комментариях.