在PowerShell中能否通过try..catch批量获取SNMP值并更新至数据库?
批量获取SNMP值并更新数据库的PowerShell方案
首先直接给你明确答案:完全可以一次性调用Invoke-SNMPget获取多个OID的值,不需要为每个OID单独写try/catch块,不过你给出的调用写法参数顺序有问题,得调整一下。
下面一步步给你梳理正确的实现方式:
1. 正确的批量SNMP调用姿势
大多数SNMP工具的Invoke-SNMPget(包括常见的第三方模块实现)都支持一次性传入多个OID,你只需要把OIDs放到一个数组里,按正确的参数顺序传递就行。修正后的调用代码如下:
# 先统一变量名,你代码里的$ups_mgmt_ip应该是$ups_ip,避免变量错误 if ($ping_reply.status -eq "Success") { try { # 注意参数顺序:IP、社区字符串、OID数组(不同模块参数名可能有差异,比如有的是-IP,有的是直接位置参数) $snmpResults = Invoke-SNMPget $ups_ip "community" $UPS_Temp_oid, $Battery_Load_oid # 如果你的模块需要显式参数名,就改成: # $snmpResults = Invoke-SNMPget -IP $ups_ip -Community "community" -OID $UPS_Temp_oid, $Battery_Load_oid } catch { Write-Host "$ups_ip SNMP Get error: $_" # 这里不要用return null,不然整个脚本会直接退出,用continue跳过当前UPS继续处理下一个 continue } }
这样一次调用就能拿到两个OID的结果,既减少了网络请求次数,也简化了错误处理逻辑。
2. 解析SNMP返回的结果
接下来需要从返回的$snmpResults里提取对应OID的数值。不同模块返回的格式可能略有不同,比如有的返回对象数组,每个对象包含OID和Value属性,你可以这样解析:
# 提取温度值 $ups_temp_value = ($snmpResults | Where-Object { $_.OID -match [regex]::Escape($UPS_Temp_oid) }).Value # 提取电池负载值 $battery_load_value = ($snmpResults | Where-Object { $_.OID -match [regex]::Escape($Battery_Load_oid) }).Value # 检查是否成功获取到两个值,避免更新空数据 if (-not $ups_temp_value -or -not $battery_load_value) { Write-Host "$ups_ip 未能获取完整的SNMP数据,跳过更新" continue }
用[regex]::Escape是为了避免OID里的点号被正则表达式当成通配符,确保匹配准确。
3. 把SNMP值更新到数据库
拿到数值后,就可以执行数据库更新了,这里一定要用参数化查询,避免SQL注入风险,补充你的代码:
# 构建更新SQL语句 $updateSql = "UPDATE ups SET temp = @Temp, batteryload = @BatteryLoad WHERE upsid = @UpsId" $updateCmd = New-Object System.Data.SqlClient.SqlCommand($updateSql, $conn) # 添加参数,自动处理数据类型和转义 $updateCmd.Parameters.AddWithValue("@Temp", $ups_temp_value) $updateCmd.Parameters.AddWithValue("@BatteryLoad", $battery_load_value) $updateCmd.Parameters.AddWithValue("@UpsId", $ups_id) try { $rowsUpdated = $updateCmd.ExecuteNonQuery() Write-Host "UPS $ups_id ($ups_ip) 更新成功,共更新 $rowsUpdated 行" } catch { Write-Host "UPS $ups_id ($ups_ip) 更新数据库失败:$_" }
4. 几个关键的优化点
- 变量一致性:你代码里的
$ups_mgmt_ip和前面定义的$ups_ip要统一,不然会出现Ping了一个IP,却去请求另一个IP的SNMP的错误。 - 资源释放:使用
SqlDataReader后,记得调用$rows.Close()和$rows.Dispose(),或者用using语句自动释放资源,避免连接泄漏:using ($cmd = New-Object System.Data.SqlClient.SqlCommand($sql, $conn)) using ($rows = $cmd.ExecuteReader()) { while ($rows.Read()) { # 你的处理逻辑 } } - 错误处理逻辑:catch块里不要用
return null,这会直接终止整个脚本,用continue跳过当前UPS,继续处理下一个才是合理的。
内容的提问来源于stack exchange,提问作者Celestialchippy
相关产品推荐
相关产品推荐

