Натолкнулся в форумах на просьбу написать сканер сети работающий в несколько потоков, но на скриптах
Задачка показалась мне интересной и даже полезной, поэтому родился вот такой скриптик:
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, но я надеюсь все мои читатели уже до него обновились ![]()









12.7.2011 в 10:53
Отлично.
А дописать, чтобы порты сканировал?
12.7.2011 в 10:56
Легко, просто заменить адреса на порты и совместить с этим – http://poshcode.org/85
13.7.2011 в 16:47
Последний раз, когда я пытался пользовать пошевские джобы – я был разочарован потребляемыми ресурсами. Не по 30 ли метров оперативной отъедает каждый поток? Всё ж таки асинхронных пинг кажется и более резвым и менее грузным.
14.7.2011 в 8:08
Да, для каждого джоба запускается отдельный Runspace, который резервирует 30-40 мегабайт оперативки, примерно как и любой .NET процесс. Но тут надо иметь ввиду то что вопреки некоторым заблуждениям, как и в случае с другими .NET приложениями, это не реально протраченная память, а лишь кеш, который позволяет ускорить работу.
Хотя конечно запускать 100 одновременных джобов на компьютере с 1GB памяти – не очень разумно. Но я надеюсь что в наше время мало у кого есть рабочие компьютеры со столь слабой конфигурацией
14.7.2011 в 7:59
+5 =)
20.9.2011 в 14:12
А как можно сделать пинг с показом текущего времени?
Надо пинговать любой хост (f.ex mail.ru/ya.ru etc) по идее это будет
for (;;$i++){Get-Date|ping mail.ru -t}
Но на выходе получаю просто пинг. Понимаю что надо как-то сцепить вывод. Но как?
Сорри. я PS только день мучаю…