为什么用它换算网段
Windows 运维机、跳板机上通常装不了 ipcalc 这类小工具,但 .NET 一直在:把 IPv4 地址读成整数后做除法取整,就能算出网络地址、广播地址与主机范围。适合把地址分配表、资产清单、防火墙规则做批量校验,也方便写进 Windows 侧巡检脚本里。
基本信息
| 适用平台 | Windows PowerShell 5.1 / PowerShell 7 |
|---|---|
| 依赖 | System.Net.IPAddress(.NET 自带,无需装模块) |
| 输入格式 | CIDR 字符串,如 192.168.1.130/27 |
| 权限要求 | 普通用户即可,只计算不改网络配置 |
| 局限 | 脚本仅处理 IPv4;IPv6 另用 ipaddress 模块或 .NET 的 IPv6 类型 |
典型使用场景
- 批量校验:把几十条网段配额一次算出网络地址与广播地址,避免手工归位出错
- 写巡检脚本:判断某台机器的 IP 是否落在预期子网内,越界即告警
- 核对工单:别人报的 x.x.x.x/25 是否与机房规划一致,当场算给对面看
- 生成配置片段:批量产出静态路由、DHCP 作用域所需的网络地址与范围
- 教学演示:在 Windows 环境直观展示“掩码决定块大小”的运算过程
换算函数(可直接粘贴)
换算函数(可直接粘贴)
function Get-Subnet([string]$cidr) {
$p = $cidr.Split('/'); $n = [int]$p[1]
$b = [System.Net.IPAddress]::Parse($p[0]).GetAddressBytes() # 转成 4 字节数组
$u = [uint64]$b[0]*16777216 + [uint64]$b[1]*65536 + [uint64]$b[2]*256 + [uint64]$b[3] # 合成 32 位整数
$size = [math]::Pow(2, 32 - $n) # 块大小 = 2 的 (32-前缀) 次方
$net = [math]::Floor($u / $size) * $size # 向下对齐到块起点
$last = $net + $size - 1 # 广播地址 = 起点 + 块大小 - 1
$fmt = { param($v) "$([math]::Floor($v/16777216) % 256).$([math]::Floor($v/65536) % 256).$([math]::Floor($v/256) % 256).$($v % 256)" }
[pscustomobject]@{ CIDR=$cidr; Network=(& $fmt $net); Broadcast=(& $fmt $last) }
}
Get-Subnet '192.168.1.130/27'
# Network: 192.168.1.128 Broadcast: 192.168.1.159关键步骤读法
| 步骤 | 作用 | 写错的表现 |
|---|---|---|
| GetAddressBytes | 取四字节原始地址 | 用字符串拆段拼数字,段位错乱 |
| $size | 块大小等于二的(32 减前缀)次方 | 写成二的(前缀)次方,大小反向 |
| Floor 取整 | 把地址压到块起点 | 四舍五入会让网络地址滑到下一块 |
| $last | 起点加块大小再减一 | 漏掉减一,广播地址多算一个 |
Windows PowerShell 5.1 对 uint32 位移会先转成 Int32 产生负数;用 64 位整数与除法(如上)比 -shl 更稳。
可用主机数是块大小减二,网络地址与广播地址各占一个;/31 与 /32 是特例,RFC 3021 下 /31 的两个地址都可用于点对点互联,脚本里需要单独判断。
扩展用法
- 把函数改成接收数组参数,一次传入整份地址清单,输出可以直接导入表格做对账
- 在结果里补上可用主机范围两个字段,巡检脚本判断在线主机是否越界时就不用再算
- 校验网段是否重叠:把两条网段的起点与终点都算出来,区间有交集就是冲突
- 判断地址是否属于某个网段:把地址与网络地址都转成整数,差值不超过块大小则在段内
写自动化脚本时优先用整数比较而不是字符串比较:地址转成整数后,区间判断、重叠判断都只是一次减法,既不容易错,也比逐段比对快得多。