为特定设备循环 IP 的更有效方式

More efficient way of looping through IPs for specific devices

我有以下代码。 IT 或多或少起作用。就挂在离线 IP 上而言,它似乎很慢。

所以我的问题是这样的。

遍历 IP 进行快速 ping,然后遍历实时 IP 的理想方式是吗?

另一个想法是提取设备类型,但由于这些是 phone,您不能像使用计算机那样使用 WMI- 功能。

我的最终目标是 运行 脚本并强制重启网络上的每个 VoIP phone。

$ping = new-object system.net.networkinformation.ping
    1..255 | foreach { $IPS = "192.168.2.$_"
    $Res = $ping.send($IPS)
        if ($Res.Status -eq "Success") 
        { 
                 $user = 'admin'
                 $pass = 'admin'
                 $pair = "$($user):$($pass)"
                 $encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
                 $basicAuthValue = "Basic $encodedCreds"
                 $Headers = @{
                     Authorization = $basicAuthValue
                    }
            $URL = "http://"+$IPS+"/servlet?key=Reboot"
            Invoke-WebRequest -Uri $URL -Headers $Headers
        }
    }

更新

偶然发现 Powershell Workflows 作为 运行 并行作业的替代方案。

workflow Restart-Phones {
    Param( [string]$Phones )

    foreach -parallel ($phone in $phones) {

        sequence {
            $result = Test-Connection $Phone -Count 1 -Quiet

            if ($result) {

                $user = 'admin'
                $pass = 'admin'
                $pair = "$($user):$($pass)"
                $encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
                $basicAuthValue = "Basic $encodedCreds"
                $Headers = @{
                    Authorization = $basicAuthValue
                }
                $URL = "http://"+$IPS+"/servlet?key=Reboot"
                Invoke-WebRequest -Uri $URL -Headers $Headers
            }
        }
    }
}

$Phones = 1..255 | % { "192.168.2.$_" }

Restart-Phones $Phones

原创

您可以尝试这样的操作(注意:我没有 运行 全部)。这个想法是您将创建一个 powershell 作业 运行 为您要调用的每个 $IP 创建一个单独的 $RebootScript 实例。这样一来,您就不会被每个无响应的 ping 所阻碍,而只是脚本的那个实例。

$RebootScript = {
    Param($IP)

    $ping = new-object system.net.networkinformation.ping
    $res = $ping.send($IP)

    if ($res.Status -eq "Success") {

        $user = 'admin'
        $pass = 'admin'
        $pair = "$($user):$($pass)"
        $encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
        $basicAuthValue = "Basic $encodedCreds"
        $Headers = @{
            Authorization = $basicAuthValue
        }
        $URL = "http://"+$IPS+"/servlet?key=Reboot"
        Invoke-WebRequest -Uri $URL -Headers $Headers
    }
}

$jobs = @() #Empty array

1..255 | foreach { 
    $IP = "192.168.2.$_"

    $jobs += Start-Job -ScriptBlock $RebootScript -ArgumentList $IP

}

# Wait until all jobs are finished.
Get-Job | Wait-Job

# Get and display jobs.
Get-Job | Receive-Job

我不确定 ping 对象,但您可以使用 Test-Connection cmdlet 将 ping 计数限制为 1。我使用 Measure-Command 来测试差异,它似乎有所帮助。但是,您需要将条件更改为 ($res.statuscode -contains 0)

Test-Connection -ComputerName $IP -Count 1 -ErrorAction SilentlyContinue

终于找到了一个似乎可以正常工作的解决方案:

1..255 | %{
$IP = "192.168.2.$_"
    If (Test-Connection -count 1 -comp $IP -quiet) {
        $user = 'admin'
        $pass = 'admin'
        $pair = "$($user):$($pass)"
        $encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
        $basicAuthValue = "Basic $encodedCreds"
        $Headers = @{
            Authorization = $basicAuthValue
        }
        $URL = "http://"+$IP+"/servlet?key=Reboot"
        Invoke-WebRequest -Uri $URL -Headers $Headers
    }
}