C#调用FirewallAPI.dll检查防火墙配置文件报ArgumentException异常
触发ArgumentException的核心原因是调用了错误的COM接口:INetFwMgr是Windows XP/Server 2003时期的遗留防火墙接口,其GetProfileByType方法仅支持旧版NET_FW_PROFILE_TYPE_枚举定义的2个配置文件类型(域、标准),完全不兼容Windows Vista及之后系统拆分出的专用、公用独立配置文件对应的NET_FW_PROFILE2_*枚举值。把新版枚举值强转后传给旧接口时,接口无法识别传入值就会抛出参数不在预期范围内的异常。
另外你的代码里存在笔误:NET_FW_PROFILE 2_DOMAIN中间多了空格,也会引发编译或运行错误。
你之前的实现本身也无法保证配置文件匹配正确:旧接口根本没有专用、公用配置文件的定义,哪怕不报错,读出来的结果也不是目标配置文件的真实状态。
要准确读取域、专用、公用三类配置文件的防火墙状态,必须使用Vista之后引入的INetFwPolicy2接口,这也是微软官方推荐的高级防火墙(advfirewall)操作接口,读取结果和你原PowerShell脚本调用netsh advfirewall拿到的结果完全一致,兼容从Vista到Win11、Server 2008到Server 2022的所有Windows系统,完全适配.NET 4.5 Windows Service的运行场景。
首先在项目中添加对NetFwTypeLib的COM引用(在添加引用窗口的COM列表中找到「Windows Firewall API」即可),然后使用如下代码读取状态:
using NetFwTypeLib; public bool AuditFirewallStatus() { // 实例化新版防火墙策略对象 Type policyType = Type.GetTypeFromProgID("HNetCfg.FwPolicy2", false); INetFwPolicy2 fwPolicy = (INetFwPolicy2)Activator.CreateInstance(policyType); // 直接读取三类配置文件的启用状态,无需跨枚举强转 bool domainOn = fwPolicy.FirewallEnabled[NET_FW_PROFILE_TYPE2_.NET_FW_PROFILE2_DOMAIN]; bool privateOn = fwPolicy.FirewallEnabled[NET_FW_PROFILE_TYPE2_.NET_FW_PROFILE2_PRIVATE]; bool publicOn = fwPolicy.FirewallEnabled[NET_FW_PROFILE_TYPE2_.NET_FW_PROFILE2_PUBLIC]; // 输出状态,服务场景下可替换为日志写入逻辑 Console.WriteLine($"域配置文件防火墙:{(domainOn ? "已启用" : "已关闭")}"); Console.WriteLine($"专用配置文件防火墙:{(privateOn ? "已启用" : "已关闭")}"); Console.WriteLine($"公用配置文件防火墙:{(publicOn ? "已启用" : "已关闭")}"); // 三类配置文件全部启用则审计通过 return domainOn && privateOn && publicOn; }
- 不要继续使用硬编码解析netsh输出的方案:不同系统语言、不同系统版本的netsh输出格式、行号都会变化,你原PowerShell脚本固定取第3、7、11行判断状态的逻辑,在非中英文系统、或者系统版本迭代后很容易出现误判,直接调用COM接口读取是稳定性最高的方案。
- Windows Service场景下,请将服务的运行身份设置为Local System,否则会因为权限不足无法读取防火墙配置。
- 旧版
INetFwMgr接口已经被微软标记为过时,不建议在新代码中使用。
内容的提问来源于stack exchange,提问作者Landon George

