【问题标题】:Speed up Test-Connection before Foreach在 Foreach 之前加速测试连接
【发布时间】:2014-08-18 00:38:56
【问题描述】:

我编写了一个脚本来检查用户的桌面文件夹是否在 cuota 限制下,如果他们在 cuota 限制下,将正确地备份到服务器。

每个用户都有他的电脑,所以源 CSV 看起来像:

pc1,user1
pc2,user2
pc800,user800

一些计算机是 Windows Xp 和一些 W7,路径可能不同,因为我使用的是 Test-Path

W7 = C:\users\$user\desktop
XP = C:\document and settings\$user\desktop

但是 Test-Path 非常慢,我开始在每个 Test-path 之前使用 Test-Connection -count 1

无论如何,脚本仍然很慢,在每次“糟糕的 ping 测试”中我都会浪费很多时间。

代码:

$csvLocation = '~\desktop\soourceReport.csv'
$csv = import-csv $csvLocation -Header PCName, User

$OuputReport = '~\desktop\newReport.csv'

# info:
# "209715200" Bytes = 200 MB

$cuota = "209715200"
$cuotaTranslate = "$($cuota / 1MB) MB"
Write-Host "Cuota is set to $cuotaTranslate"

$count=1

foreach($item in $csv)
{
    write-host "$count# Revisando" $item.User "en" $item.PCName "..." #For debug

    if (Test-Connection -Quiet -count 1 -computer $($item.PCname)){

        $w7path = "\\$($item.PCname)\c$\users\$($item.User)\desktop"
        #echo $w7path #debug

        $xpPath = "\\$($item.PCname)\c$\Documents and Settings\$($item.User)\Escritorio"
        #echo $xp #debug

                if(Test-Path $W7path){

                    $desktopSize = (Get-ChildItem -Recurse -force $w7path | Measure-Object -ErrorAction "SilentlyContinue" -property length -sum) 

                    write-host -ForegroundColor Green "access succeed"

                        if($($desktopSize.sum) -gt $cuota){


                            $newLine =  "{0},{1},{2}" -f $($item.PCname),$($item.User),"$("{0:N0}" -f $($desktopSize.sum / 1MB)) MB"
                            $newLine |  add-content $outputReport

                             Write-Host -ForegroundColor Yellow "cuota exceeded! -- added"
                         }

                        else{
                         Write-Host -ForegroundColor DarkYellow  "cuota OK"
                        }


                }

                elseif(Test-Path $xpPath){

                    $desktopSize = (Get-ChildItem -Recurse -force $xpPath | Measure-Object -ErrorAction "SilentlyContinue" -property length -sum) 

                    write-host -ForegroundColor Green "access succeed"

                        if($($desktopSize.sum) -gt $cuota){


                            $newLine =  "{0},{1},{2}" -f $($item.PCname),$($item.User),"$("{0:N0}" -f $($desktopSize.sum / 1MB)) MB"
                            $newLine |  add-content $outputReport

                             Write-Host -ForegroundColor Yellow "cuota exceeded! -- added"
                         }

                        else{
                         Write-Host -ForegroundColor DarkYellow  "cuota OK"
                        }
                else{
                     write-host -ForegroundColor Red "Error! - bad path"
                }
    }

    else{
        write-host -ForegroundColor Red "Error! - no ping"
    }
    $count++
}
Write-Host -ForegroundColor green -BackgroundColor DarkGray "All done! new report stored in $report"

为了改进它,在第一次提到的 SLOW-Foreach 循环之前,我使用另一个 Foreach 将所有计算机存储在 $list 中。

foreach($pcs in $csv){

    $alivelist += @( $pcs.PCName )
}

Test-Connection -quiet -count 2 -computer $alivelist

现在,我现在不知道如何在进入第二个 Foreach 之前从 SOURCE CSV 更新或删除行(“dead” pc、user)。

我需要你的一些“魔法”,或者至少是一些想法!

谢谢

【问题讨论】:

标签: powershell csv foreach


【解决方案1】:

使用 -asjob 参数的测试连接速度非常快,在 4 秒内 ping 了大约 200 台计算机:

$list = cat hp.txt
test-connection $list -AsJob ; job | receive-job -wait -AutoRemoveJob

【讨论】:

    【解决方案2】:

    为了加快您的脚本,您需要并行运行检查(正如其他人已经提到的)。将您的检查和工作代码放在一个脚本块中:

    $sb = {
        Param($computer, $username)
    
        if (Test-Connection -Quiet -Count 2 $computer) { return }
    
        $w7path = "\\$computer\c$\users\$username\desktop"
        $xpPath = "\\$computer\c$\Documents and Settings\$username.TUITRA..."
    
        if (Test-Path $W7path) {
            #...
        } elseif (Test-Path $xpPath) {
            #...
        } else {
            #...
        }
    }
    

    然后将脚本块作为并行作业运行:

    $csv | ForEach-Object {
        Start-Job -ScriptBlock $sb -ArgumentList $_.PCName, $_.User
    }
    
    # wait for completion
    do {
        Start-Sleep -Milliseconds 100
    } while (Get-Job -State 'Running')
    
    # cleanup
    Get-Job | ForEach-Object {
        Receive-Job -Id $_.Id
        Remove-Job -Id $_.Id
    } | Out-File $outputReport
    

    如果您需要限制并行作业的数量,请使用 queue

    【讨论】:

    • 但现在输出 CSV 不起作用,错误 - 是一个零路径,我将 $Outputreport 移到 $sb 内...现在 csv 已部分创建,不再说正在被其他进程使用.没有线索。
    • @pedaleo:您遇到了范围界定问题。脚本块中的$outputReport 是与脚本其余部分中的$outputReport 不同的变量。如果你想在那里使用它,你需要通过-ArgumentList 参数将报告路径传递到脚本块中。但是,这不是一个好主意,因为它会产生其他问题(例如并发文件访问)。当您通过Receive-Job 检索它时,最好从脚本块中删除| Add-Content $outputReport 并重定向成功输出流上的输出。请参阅我的更新答案。
    猜你喜欢
    • 2011-05-03
    • 1970-01-01
    • 2019-05-13
    • 1970-01-01
    • 2015-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多