Многопоточный сканер сети

Натолкнулся в форумах на просьбу написать сканер сети работающий в несколько потоков, но на скриптах Smile Задачка показалась мне интересной и даже полезной, поэтому родился вот такой скриптик:

ThreadPing.ps1

Param (            
[string[]]$Address = $(1..20 | %{"192.168.1.$_"}),            
[int]$Threads = 5            
)            
            
write-host "Distributing addresses around jobs"            
$JobAddresses = @{}            
$CurJob = 0            
$CurAddress = 0            
while ($CurAddress -lt $Address.count)            
{            
    $JobAddresses[$CurJob] += @($Address[$CurAddress])            
    $CurAddress++            
    if ($CurJob -eq $Threads -1)            
    {            
        $CurJob = 0            
    }            
    else            
    {            
        $CurJob++            
    }            
}            
            
$Jobs = @()            
foreach ($n in 0 .. ($Threads-1))            
{            
    Write-host "Starting job $n, for addresses $($JobAddresses[$n])"            
    $Jobs += Start-Job -ArgumentList $JobAddresses[$n] -ScriptBlock {            
        $ping = new-object System.Net.NetworkInformation.Ping            
        Foreach ($Ip in $Args)            
        {            
            trap {            
                new-object psobject -Property {            
                    Status = "Error: $_"            
                    Address = $Ip            
                    RoundtripTime = 0            
                }            
                Continue            
            }            
            $ping.send($Ip,100) | select `
                @{name="Status"; expression={$_.Status.ToString()}},             
                @{name = "Address"; expression={$Ip}}, RoundtripTime            
        }            
    }            
}            
            
write-host "Waiting for jobs"            
$ReceivedJobs = 0            
while ($ReceivedJobs -le $Jobs.Count)            
{            
    foreach ($CompletedJob in ($Jobs | where {$_.State -eq "Completed"}))            
    {            
        Receive-Job $CompletedJob | select status, address, roundtriptime            
        $ReceivedJobs ++            
        sleep 1            
    }            
}            
            
Remove-Job $Jobs            
write-host "Done."

 

У скрипта два аргумента:

  • Threads – число потоков
  • Address – диапазон ip-адресов в виде массива строк. Например чтобы просканировать адреса с 192.168.1.1 по 192.168.1.254 можно использовать следующую конструкцию: 1..254 | ${"192.168.1.$_"}

Пример использования:

PS > .\ThreadPing.ps1 -Address (1..20|%{"192.168.1.$_"}) -threads 5
Distributing addresses around jobs
Starting job 0, for addresses 192.168.1.1 192.168.1.6 192.168.1.11 192.168.1.16
Starting job 1, for addresses 192.168.1.2 192.168.1.7 192.168.1.12 192.168.1.17
Starting job 2, for addresses 192.168.1.3 192.168.1.8 192.168.1.13 192.168.1.18
Starting job 3, for addresses 192.168.1.4 192.168.1.9 192.168.1.14 192.168.1.19
Starting job 4, for addresses 192.168.1.5 192.168.1.10 192.168.1.15 192.168.1.20
Waiting for jobs

Done.
Status   Address      RoundtripTime
------   -------      -------------
TimedOut 192.168.1.2              0
TimedOut 192.168.1.7              0
Success  192.168.1.12             1
TimedOut 192.168.1.17             0
Success  192.168.1.1              0
Success  192.168.1.6              1
TimedOut 192.168.1.11             0
TimedOut 192.168.1.16             0
Success  192.168.1.3             10
TimedOut 192.168.1.8              0
TimedOut 192.168.1.13             0
TimedOut 192.168.1.18             0
TimedOut 192.168.1.4              0
TimedOut 192.168.1.9              0
TimedOut 192.168.1.14             0
TimedOut 192.168.1.19             0
TimedOut 192.168.1.5              0
TimedOut 192.168.1.10             0
TimedOut 192.168.1.15             0
TimedOut 192.168.1.20             0

Так как вывод полностью объектный, в лучших традициях PowerShell’а, то результатами легко оперировать. Например, чтобы получить лишь отзывающиеся на пинг хосты, можно использовать where:

.\ThreadPing.ps1 -Address (1..254|%{"192.168.1.$_"}) -threads 20 | 
	where {$_.status -eq "success"}

A что бы выбрать лишь адреса, достаточно добавить Select –ExpandProperty

$IPs = 1..3 | %{$s=$_; 1..254 | %{"192.168.$s.$_"}}
.\ThreadPing.ps1 -Address $Ips -threads 20 | 
	where {$_.status -eq "success"} | 
		Select -expandproperty Address

 

Да, кстати, сценарий использует фоновые работы, поэтому будет работать только в PowerShell 2.0, но я надеюсь все мои читатели уже до него обновились Smile

Опубликовано в 2.0, PowerShell, Scripting. Метки: , , . 6 комментариев »