在很大的池中有效地找到匹配的子网

时间:2018-09-19 15:47:30

标签: powershell

我一直在编写一个脚本,该脚本在给定IP地址的情况下收集IPAM信息。

它正在工作,但是我当前的实现效率很低。

我正在使用this script运行checkSubnet,它确定IP是否在子网中。

首先,我查询IPAM以收集此$allSubnets对象:

Address         CIDR Description                               VLAN                     
-------         ---- -----------                               ----                     
10.15.10.0        24 DMZ                                       3000                     
10.15.11.0        24 Voice                                     3010                     
10.15.12.0        24 Wireless                                  3020
10.15.13.0        28 Management                                3030
...              ... ...                                        ...

然后像这样搜索:

$testCon = Test-Connection hostname -Count 1

$allSubnets | ForEach-Object { 
  if((checkSubnet -addr1 ('{0}/{1}' -f $_.Address, $_.CIDR) -addr2 $testCon.IPV4Address.IPAddressToString).Condition -eq $true)
  {
    [pscustomobject]@{
      subnet = ('{0}/{1}' -f $_.Address, $_.CIDR)
      desc = $_.Description
    }
  }
}

这非常适合较小的查询。 但是,运行$allSubnets中的所有项目可能要花费很长时间!假设我要针对完整的2000个子网测试20个IP地址,突然此查询将花费整整2分钟的时间。

有人对提高效率有任何想法吗?

1 个答案:

答案 0 :(得分:1)

我无权访问子网的完整列表,但是针对发布的子网进行的测试表明,这样做速度更快:

首先是一个“简单”功能,以查看IP是否在特定范围内:

Function Find-Subnet ([IPAddress]$SubnetAddress,[byte]$CIDR,[IPAddress]$MatchIP){
    [IPAddress]$Mask = [System.Convert]::ToUInt64(('1'*$CIDR).PadRight(32,'0'),2)
    return (($SubnetAddress.Address -band $Mask.Address) -eq ($MatchIP.Address -band $Mask.Address))
}

这利用了移位的优点,[System.IPAddress]对象可能会影响性能,但是它似乎比链接函数要快得多,而且更为简洁,您可以随时重写[IPAddress]如果确实需要额外的性能,则将其转换为另一个二进制函数,因为最后我们仅使用地址的数字表示形式。

然后我希望限制搜索的数量,在2000个以上的子网中进行搜索时,这应该是一个巨大的性能提升,仅针对问题中的少数几个进行搜索,但这只是一个轻微的负数。

foreach ($Reg in ('(.*\.).*','(.*\.).*\..*','(.*\.).*\..*\..*')){
    $Prefix = $ToMatch -replace $Reg,'$1'
    Write-Host "Searching subnets beginning with '$($Prefix)'..." -Fore Yellow
    $AllSubnets | ? {$_.Address.StartsWith($Prefix)} | ForEach-Object {
        if (Find-Subnet -SubnetAddress $_.Address -CIDR $_.CIDR -MatchIP $ToMatch){
            $_ ; break
        }
    }
}

这会循环遍历正则表达式摘要'(.*\.).*''(.*\.).*\..*''(.*\.).*\..*\..*',当它们通过$Prefix = $ToMatch -replace $Reg,'$1'运行时,将产生以下内容:

'10.11.12.13' -> '(.*\.).*'         -> '10.11.12.'
'10.11.12.13' -> '(.*\.).*\..*'     -> '10.11.'
'10.11.12.13' -> '(.*\.).*\..*\..*' -> '10.'

然后我们遍历整个列表,并以地址开头的子网拉出子网,对于任何A类子网,这都会比不包括子网慢,对于B和C,它的性能大致相同或更快, B可能会更慢,而C可能会快得多。

您当前的功能在找到IP后也不会停止搜索。通过在返回匹配的IP对象之后包含;break,我们将立即返回它并停止搜索,如果您想将子网存储在变量中,则可以执行$Result = @(foreach ($Reg in ...) { ... })以在{ {1}}。