powershell - 在非常大的池中有效地找到匹配的子网
问题描述
我一直在编写一个脚本,在给定 IP 地址的情况下收集 IPAM 信息。
它正在工作,但我目前的实施效率非常低。
我正在使用此脚本运行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 分钟才能完成。
有人对如何提高效率有任何想法吗?
解决方案
我无权访问子网的完整列表,但是针对发布的子网的测试表明这要快一些:
首先是一个“更简单”的函数来查看 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
}
}
}
this 循环通过 regex snippets '(.*\.).*'
,'(.*\.).*\..*'
并且'(.*\.).*\..*\..*'
在运行时$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 后也不会停止搜索。通过;break
在返回匹配的 IP 对象之后包含 ,我们会立即返回它并停止搜索,如果您想将子网存储在一个变量中,您可以$Result = @(foreach ($Reg in ...) { ... })
将它最终保存在$Result
.
推荐阅读
- vb.net - 使用 VB.NET 获取 sessionID 终端服务器(使用 .NET 框架)
- asp.net-core-3.1 - 功能管理 - 两个应用程序之间的内部缓存
- excel - 使用具有相同数据的多个选项卡的 VBA 或数据透视表创建表(不能 PowerPivot)
- javascript - 如何为属于夏令时的未来日期更正时区偏移
- draw - libreoffice Basic:绘图和表格形状:如何格式化单元格?
- javascript - 将 websocket ref 传递给子组件
- c++ - Google Kickstart 2020 Round A 2020 错误答案
- ios - UIvew 在不同位置使用相同的代码
- flutter - 访问 Cloud Firestore 会引发 NoSuchMethodError
- excel - VBA - 使用范围函数从一个工作表复制并粘贴到另一个工作表