我想出了以下代码来改善对大量机器执行ping操作的性能。
目前,这是相当基本的操作,但是我认为在继续进行之前我应该​​先了解人们的想法。

NB :这是我第一次使用工作流,所以我可能在那里做了一些人造假操作。

cls
workflow Test-ConnectionQuickly {
    [cmdletbinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string[]]$computers
    )
    $computerGroups = InlineScript {
        #group computers to throttle the number of threads
        [psobject]$itemCounter = [pscustomobject]@{itemNo=0;groupSize=10} #alter groupSize per your preference
        $itemCounter | Add-Member -MemberType ScriptMethod -Name 'groupNo' -Value {
            [math]::Floor($this.itemNo++ / $this.groupSize)
        }
        write-output $using:computers | Group-Object -Property {$itemCounter.groupNo()}
    }
    ForEach -parallel ($computerGroup in $computerGroups) {
        $computerGroup | select -ExpandProperty group | %{
            $pingable = (Test-Connection $_ -Count 2 -Quiet -ErrorAction SilentlyContinue)
            write-output (new-object -type psobject -property @{Name=$_;Online=$pingable})
        }
    } 
}

[string[]]$computers = (1..100 | %{("Server{0:000}" -f $_)}) #here's where we'd read in the computere from file
Test-ConnectionQuickly $computers | select Name, Online #here's where we'd pipe the output to file


设计说明:


InlineScript用于将服务器分成小组(每组10个;任意大小),以期在小计算机的串行性能与在大型计算机的并行性能之间取得平衡。
$itemCounter变量是一个尝试使分组大小更易于阅读

-count 2上指定了test-connection,以便我们对网络故障有一定的容忍度,而又不会对性能造成太大影响。之所以指定,是因为我们不需要输出/并且没有输出将有助于提高性能。


评论

您看过ThrottleLimit吗?例如:ForEach -Parallel -ThrottleLimit 10(x in y){...}

我没意识到;将调查它;谢谢。

我一直在寻找快速的ping扫地机,并遇到了这个问题。我选择了以下脚本:gallery.technet.microsoft.com/scriptcenter/…

这是使用RunSpaces的另一种很棒的方法/工作流的替代方法:https://github.com/RamblingCookieMonster/Invoke-Parallel/blob/master/Invoke-Parallel/Invoke-Parallel.ps1。

#1 楼

首先,我也是工作流程的新手。在大多数情况下,您的代码是可靠的。您应该看到一些实际上可以提高性能的建议,尤其是在100台计算机上运行时。

分组逻辑

这更是一种赞美。根据我的阅读,我认为-ThrottleLimit是替换分组逻辑的简单答案。可能由于我的经验不足,但我的大部分测试表明,您所拥有的性能优于仅使用-ThrottleLimit进行的一些简单测试。我知道它确实有它的位置,但是在这里我认为您拥有的实际上更好。

使用参数进行分组/限制

对于$computers,您具有必要的属性,但我认为在GroupSize的工作流程中具有参数与好。

ScriptMethod的使用

虽然这是将计算机组组合在一起的一种好方法,但我认为这对于简单的计算机阵列来说是过大的。由于您已经知道如何对计算机进行分组,因此您可以真正避免将组对象全部在一起。相反,可以考虑仅使用一个简单的foreach-object循环,该循环将每个计算机块提取为各自的阵列。实际上,这里没有性能提升。如果它是简单的数组拆分,则更容易理解。

还有许多将数组拆分为较小块的不同方法。我试图避免在到达$groupsize时重置一个简单的计数器

顺便说一句,令我失望的是,如果您想轻松制作音符属性以外的其他内容,仍然需要Add-Member。我在这里阅读了另一种方法,但认为它不足以对您的情况提出建议。

新对象和[pscustomobject]

两种方法都可以用来创建对象。也可以坚持一个。当我将最终的对象创建更改为仅在哈希表上强制转换为[pscustomobject]时,它实际上提高了性能!

两次测试连接

我喜欢加强测试的想法。计算机可能没有响应第一次ping,而实际上没有响应时,可能会记录为宕机。因此,我可以进行两次测试很好。

但是,当您测试启动的计算机时,您应该对其进行ping操作两次。最好做两个单独的测试,并以这样的方式进行测试:如果成功,第一个测试将阻止再次检查,因为这将是多余的。

考虑以下非常简单的If语句。

if(1 -eq 1 -or 1/0 ){"Yo"}

乍一看,您应该看到第二个条件除以0并期望失败。由于1 -eq 1始终为true,因此将永远不会进行检查。由于第一个条件为true,因此PowerShell将忽略右侧条件,因为它不会更改结果。上一段中的about_logical_operators涵盖了此概念。

因此,我提出了这样的建议:如果第一个失败。因此,它仍然很坚固,但也应该有效。我想您可以吐出命令,因为它们是相同的,但是我试图将多余的逻辑置于循环之外以提高性能。


您完全不需要使用此代码,但我恳请您对我俩进行尝试,以查看是否至少在性能上有所改进。

 workflow Test-ConnectionQuickly {
    [cmdletbinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string[]]$computers,
        [Parameter(Mandatory = $false)]
        [int]$GroupSize = 10
    )
    $computerGroups = InlineScript {
        #group computers to throttle the number of threads
        $numberofGroups = [math]::Ceiling($using:Computers.Count / $using:groupSize)
        1..$numberofGroups | ForEach-Object{
            # Arrays are zero based which is why you will see -1 
            ,($using:computers | Select -Index ((($_ - 1) * $using:GroupSize)..($_ * $using:GroupSize - 1)))
            # Use the unary operator to ensure an array of computers is returned and not unrolled. 
    }

    }
    ForEach -parallel ($computerGroup in $computerGroups) {
        $computerGroup | ForEach-Object{
            $pingable = (Test-Connection $_ -Count 1 -Quiet -ErrorAction SilentlyContinue) -or 
                        (Test-Connection $_ -Count 1 -Quiet -ErrorAction SilentlyContinue)
            [pscustomobject]@{Name=$_;Online=$pingable}
        }
    } 
} 
 


我唯一推荐的要点是[pscustomobject]@{Name=$_;Online=$pingable},以及我的方式将ping测试分为2个单独的测试。

我的大多数测试都是使用5台和80台计算机的$GroupSize完成的。

$pingable = (Test-Connection $_ -Count 1 -Quiet -ErrorAction SilentlyContinue) -or 
                        (Test-Connection $_ -Count 1 -Quiet -ErrorAction SilentlyContinue)


您肯定需要尝试使用$GroupSize来找到最佳位置。