Powershell Receive-Job:调用命令作为作业时的配额违规

时间:2011-01-19 21:00:25

标签: powershell powershell-v2.0

我正在尝试使用后台作业机制并行地对多台计算机执行cmdlet(测试连接)。下面的函数很好,直到我抛出超过649个主机名(至少在这台机器上),然后抛出异常:

PS> 。\ test.ps1。\ 650_hostnames.txt

Receive-Job : Quota violation
At H:\Development\Powershell\test.ps1:13 char:13
+ Receive-Job <<<< |
+ CategoryInfo " InvalidResult: (:) [Receive-Job], ManagementException
+ FullyQualifiedErrorId : JobStateFailed,Microsoft.PowerShell.Commands.ReceiveJobCommand

出于性能原因,我仍希望将cmdlet作为后台作业执行,但是要控制在给定时间启动的作业数。我无法控制输入,所以我可以得到几千到几百的列表。任何建议都表示赞赏!

test.ps1

$wkslist = $args[0]

function IsAlive {
  param(
      [Parameter(
      Mandatory = $true,
      Position = 0)]
      $computername
  )
  test-connection -count 1 -ComputerName $computername -TimeToLive 30 `
  -ThrottleLimit 10 -asJob |
  Wait-Job |
  Receive-Job |
  Where-Object { $_.StatusCode -eq 0 } |
  Select-Object -ExpandProperty Address
}

$ips = [System.IO.File]::ReadAllLines("$wkslist")
IsAlive -computername $ips

3 个答案:

答案 0 :(得分:3)

看起来这与你正在使用工作的事实无关;它似乎与输入的大小传递给测试连接。我可以使用以下代码重现配额违规:

$ra = @(0..1000) | %{ $env:computername };
test-connection -computername $ra;

似乎是测试连接内部的东西,最终创建了Win32_Ping WMI对象。我也可以通过切出部分输入数组来获得代码:

$ra = @(0..1000) | %{ $env:computername };
test-connection -computername $ra[0..500];

请注意,650似乎不是一个神奇的数字 - 我可以查询多达800个主机名,而不会遇到错误。

由于异常是管理异常而不是PowerShell内部异常,我会说你已经找到了WMI的许多神奇限制之一。听起来像测试连接应该在内部管理,但事实并非如此。我已经在Connect上记录了一个问题,如果你想提出它:test-connection throws quota exception when passed large list of computernames

我会按原样尝试您的工作代码,但将主机名列表分成较小的部分:

$i = 100;
$j = 0;
while( $i -le $ra.length )
{ 
   test-connection -computername $ra[$j..$i] ... ;
   $j = $i + 1;
   $i += 100;
}

答案 1 :(得分:0)

我会稍微重新调整代码,看起来像这样:

将以下代码放入根profile.ps1 c:\ windows \ system32 \ windowspowershell \ v1.0 \ profile.ps1。如果它不存在,只需创建一个文本文件并重命名即可。启动PowerShell时,默认情况下会加载此profile.ps1文件。

Function Test-Connection()
{
param(
[Parameter(Mandatory = $true,Position = 0)]$Count,
[Parameter(Mandatory= $true,Position = 1)]$IP,
[Parameter(Mandatory= $true,Position = 2)]$TTL,
[Parameter(Mandatory= $true,Position = 3)]$ThrottleLimit
)
MyCommand $Count $IP $TTL $ThrottleLimit

}

然后使用以下代码运行作业,从我的博客http://www.poshpete.com/archives/27复制我的阈值例程:

$ips = Get-Content $wkslist
ForEach($IP in $ips)
{

    Threshold -MaxConcurrent 10 -PauseTime 5
    Start-Job -ScriptBlock {test-connection} -ArgumentList $Count,$IP,$TTL,$ThrottleLimit -Name $IP
    $CompletedJobs = Get-Job -State Completed
    If(($CompletedJobs | Measure-Object).Count -gt 0)
    {
        ForEach($Job in $CompletedJobs)
        {
            $Job | Receive-Job | Where-Object { $_.StatusCode -eq 0 } | Select-Object -ExpandProperty Address

        }

    }
}

我正在使用get-content从文本文件中获取数据,但您也可以使用.net对象。

希望这有意义!

答案 2 :(得分:0)

在努力提高配额限制后,我意识到无论如何我需要控制功能的输入量。某人或某物将通过比配额允许的更多主机,即使您提出它或超过机器的资源。配额用于保护本地计算机和/或远程计算机免受意外和恶意的过度资源使用。这是一件好事(尽管我仍然对如何控制数字感兴趣)。

根据about_Remote_Troubleshooting帮助解决错误:

  1. 更改远程命令以符合配额。 (谢谢上尉明显)
  2. 或者,确定配额的来源,然后增加配额以允许命令完成。
  3. 至于确定配额的来源,对我来说仍然是一个谜。当我找到主机提供程序进程的配置类_ProviderHostQuotaConfiguration时,我以为我越来越近了。此类允许在主机进程使用系统资源时设置限制。可用的不同属性是:

    • ThreadsPerHost:定义任何一台主机拥有的线程数
    • HandlesPerHost:定义每个主机可能具有的内核对象句柄数
    • ProcessLimitAllHosts:定义可以并发执行的主机进程总数
    • MemoryPerHost:定义每个主机可以拥有的私有内存量
    • MemoryAllHosts:定义所有主机可以保存的私有内存总量(以字节为单位)

    然而,在增加值后,我仍然收到相同的违规行为。如果有人知道要改变什么来提高可用于测试连接的主机数量,我相信该组会很感激。