如何多线程 PowerShell Ping 脚本

问题描述 投票:0回答:4

我最近完成了一个脚本,用于 ping 列表中的每台计算机/工作站并以良好的格式输出。

下一个列表中有数千台计算机需要 ping,因此需要一段时间才能正常运行。我如何能够对其进行多线程处理,以便可以在合理的时间范围内完成工作?

multithreading powershell ping
4个回答
6
投票
workflow Ping
{
  param($computers)

    foreach -parallel ($computer in $computers)
    {
        $status = Test-Connection -ComputerName $computer -Count 1 -Quiet

        if (!$status)
            { Write-Output "Could not ping $computer" }
    }
}

$computers = @(
    "wd1600023",
    "sleipnir"
)

Ping $computers

3
投票

你可以产生多个工作 或者您可以使用 workflowForeach 并行循环


2
投票

我发现并使用此脚本作为类似函数的基线Ping-IPRange

我对原来的内容进行了修改,并将其包含在下面。

如果您正在使用主机名,您可以轻松地对其进行调整以接受主机名列表。

Ping-IPRange.ps1

function Ping-IPRange 
{
    <#
    .SYNOPSIS
        Sends ICMP echo request packets to a range of IPv4 addresses between two given addresses.

    .DESCRIPTION
        This function lets you sends ICMP echo request packets ("pings") to 
        a range of IPv4 addresses using an asynchronous method.

        Therefore this technique is very fast but comes with a warning.
        Ping sweeping a large subnet or network with many switches may result in 
        a peak of broadcast traffic.
        Use the -Interval parameter to adjust the time between each ping request.
        For example, an interval of 60 milliseconds is suitable for wireless networks.
        The RawOutput parameter switches the output to an unformatted
        [System.Net.NetworkInformation.PingReply[]].

    .INPUTS
        None
        You cannot pipe input to this function.

    .OUTPUTS
        The function only returns output from successful pings.

        Type: System.Net.NetworkInformation.PingReply

        The RawOutput parameter switches the output to an unformatted
        [System.Net.NetworkInformation.PingReply[]].

    .NOTES
        Author  : G.A.F.F. Jakobs
        Created : August 30, 2014
        Version : 6

        Revision History: Kory Gill, 2016/01/09
            formatting
            added better error handling
            close progress indicator when complete

    .EXAMPLE
        Ping-IPRange -StartAddress 192.168.1.1 -EndAddress 192.168.1.254 -Interval 20

        IPAddress                                 Bytes                     Ttl           ResponseTime
        ---------                                 -----                     ---           ------------
        192.168.1.41                                 32                      64                    371
        192.168.1.57                                 32                     128                      0
        192.168.1.64                                 32                     128                      1
        192.168.1.63                                 32                      64                     88
        192.168.1.254                                32                      64                      0

        In this example all the ip addresses between 192.168.1.1 and 192.168.1.254 are pinged using 
        a 20 millisecond interval between each request.
        All the addresses that reply the ping request are listed.

    .LINK
        http://gallery.technet.microsoft.com/Fast-asynchronous-ping-IP-d0a5cf0e

    #>
    [CmdletBinding(ConfirmImpact='Low')]
    Param(
        [parameter(Mandatory = $true, Position = 0)]
        [System.Net.IPAddress]$StartAddress,
        [parameter(Mandatory = $true, Position = 1)]
        [System.Net.IPAddress]$EndAddress,
        [int]$Interval = 30,
        [Switch]$RawOutput = $false
    )

    $timeout = 2000

    function New-Range ($start, $end) {

        [byte[]]$BySt = $start.GetAddressBytes()
        [Array]::Reverse($BySt)
        [byte[]]$ByEn = $end.GetAddressBytes()
        [Array]::Reverse($ByEn)
        $i1 = [System.BitConverter]::ToUInt32($BySt,0)
        $i2 = [System.BitConverter]::ToUInt32($ByEn,0)
        for ($x = $i1;$x -le $i2;$x++)
        {
            $ip = ([System.Net.IPAddress]$x).GetAddressBytes()
            [Array]::Reverse($ip)
            [System.Net.IPAddress]::Parse($($ip -join '.'))
        }
    }

    $ipRange = New-Range $StartAddress $EndAddress

    $IpTotal = $ipRange.Count

    Get-Event -SourceIdentifier "ID-Ping*" | Remove-Event
    Get-EventSubscriber -SourceIdentifier "ID-Ping*" | Unregister-Event

    $ipRange | ForEach-Object {

        [string]$VarName = "Ping_" + $_.Address

        New-Variable -Name $VarName -Value (New-Object System.Net.NetworkInformation.Ping)

        Register-ObjectEvent -InputObject (Get-Variable $VarName -ValueOnly) -EventName PingCompleted -SourceIdentifier "ID-$VarName"

        (Get-Variable $VarName -ValueOnly).SendAsync($_,$timeout,$VarName)

        Remove-Variable $VarName

        try
        {

            $pending = (Get-Event -SourceIdentifier "ID-Ping*").Count

        } 
        catch [System.InvalidOperationException]
        {
            $pending = 0
        }

        $index = [array]::indexof($ipRange,$_)

        Write-Progress -Activity "Sending ping to" -Id 1 -status $_.IPAddressToString -PercentComplete (($index / $IpTotal)  * 100)

        $percentComplete = ($($index - $pending), 0 | Measure-Object -Maximum).Maximum

        Write-Progress -Activity "ICMP requests pending" -Id 2 -ParentId 1 -Status ($index - $pending) -PercentComplete ($percentComplete/$IpTotal * 100)

        Start-Sleep -Milliseconds $Interval
    }

    Write-Progress -Activity "Done sending ping requests" -Id 1 -Status 'Waiting' -PercentComplete 100 

    while ($pending -lt $IpTotal) {

        Wait-Event -SourceIdentifier "ID-Ping*" | Out-Null

        Start-Sleep -Milliseconds 10

        try
        {

            $pending = (Get-Event -SourceIdentifier "ID-Ping*").Count

        }
        catch [System.InvalidOperationException]
        {
            $pending = 0
        }

        $percentComplete = ($($IpTotal - $pending), 0 | Measure-Object -Maximum).Maximum

        Write-Progress -Activity "ICMP requests pending" -Id 2 -ParentId 1 -Status ($IpTotal - $pending) -PercentComplete ($percentComplete/$IpTotal * 100)
    }

    Write-Progress -Completed -Id 2 -ParentId 1 -Activity "Completed"
    Write-Progress -Completed -Id 1 -Activity "Completed"

     $Reply = @()

    if ($RawOutput)
    {
        Get-Event -SourceIdentifier "ID-Ping*" | ForEach { 
            if ($_.SourceEventArgs.Reply.Status -eq "Success")
            {
                $Reply += $_.SourceEventArgs.Reply
            }
            Unregister-Event $_.SourceIdentifier
            Remove-Event $_.SourceIdentifier
        }
    }
    else
    {
        Get-Event -SourceIdentifier "ID-Ping*" | ForEach-Object { 
            if ($_.SourceEventArgs.Reply.Status -eq "Success")
            {
                $pinger = @{
                    IPAddress = $_.SourceEventArgs.Reply.Address
                    Bytes = $_.SourceEventArgs.Reply.Buffer.Length
                    Ttl = $_.SourceEventArgs.Reply.Options.Ttl
                    ResponseTime = $_.SourceEventArgs.Reply.RoundtripTime
                }
                $Reply += New-Object PSObject -Property $pinger
            }
            Unregister-Event $_.SourceIdentifier
            Remove-Event $_.SourceIdentifier
        }
    }

    if ($Reply.Count -eq 0)
    {
        Write-Verbose "Ping-IPRange : No IP address responded" -Verbose
    }

    return $Reply
}

0
投票

这是在 powershell 5.1 中 ping 大型列表的一种疯狂快速的方法,一次可以执行的数量有一个奇怪的限制。

$all = cat all.txt
$up = $(test-connection $all[0..713] -count 1 -asjob; 
  test-connection $all[714..733] -count 1 -asjob) | 
  receive-job -wait -auto | ? responsetime | % address
© www.soinside.com 2019 - 2024. All rights reserved.