NSIS 脚本,安装时添加防火墙规则
场景
在 Windows 上运行需要访问网络或者提供网络服务的程序,需要防火墙放行。默认情况下,在首次运行程序时,可能会有如下弹窗,只有用户点击运行才能继续使用网络。部分情况,可能是直接被拦截,都没有这个提示。
Windows 防火墙规则 | Microsoft Learn
如果出现问题,手动处理的话,可以在 Windows 防火墙的高级设置中,添加入站或出站规则,或者配置 “允许应用或功能通过 Windows Defender 防火墙”。
这里介绍的是,如果在应用安装时(使用 NSIS 打包),自动添加防火墙规则,避免上述问题。
netsh advfirewall
基本思路是使用 netsh advfirewall
命令来进行防火墙规则的添加,
添加规则命令参考:
netsh advfirewall firewall add rule name="ruleName" program="C:\Program Files\7-Zip\7z.exe" action=allow dir=in enable=yes
移除规则命令参考(卸载时调用):
netsh advfirewall firewall delete rule name="ruleName"
关于 netsh advfirewall 的更多资料
Use netsh advfirewall firewall context - Windows Server | Microsoft Learn
在 NSIS 中集成上述 netsh 命令
在 NSIS 脚本中,可以通过 ExecWait 直接执行命令,参考如下
#define FIREWALL_NAME "my dicom viewer"
Function .onInstSuccess
ExecWait 'netsh advfirewall firewall add rule name="${FIREWALL_NAME}" program="$INSTDIR\DicomViewer.exe" dir=in action=allow'
ExecWait 'netsh advfirewall firewall add rule name="${FIREWALL_NAME}" program="$INSTDIR\DicomViewer.exe" dir=out action=allow'
FunctionEnd
Function un.onUninstSuccess
ExecWait 'netsh advfirewall firewall delete rule name="${FIREWALL_NAME}"'
HideWindow
MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) 已成功地从您的计算机移除"
FunctionEnd
上述写法能成功执行,但是有个问题,在执行时,会打开 CMD 命令行窗口。看起来的效果就是会有黑框框一闪而过,如果是内部使用的工程板软件,勉强可以接受,如果是面向用户的软件,这个问题还需要进一步处理。
改进 CMD 命令行窗口的闪烁
这里使用的方式是,在 NSIS 中,调用 vbs 脚本,可以做到没有命令行窗口。
添加规则的脚本如下
Dim arg1
arg1 = WScript.Arguments(0)
Dim shell
Set shell = CreateObject("WScript.Shell")
Dim ruleName
ruleName = "my dicom viewer"
Dim command1
command1 = "netsh advfirewall firewall add rule name=""" & ruleName & """ program=""" & arg1 & """ action=allow dir=in enable=yes"
Dim command2
command2 = "netsh advfirewall firewall add rule name=""" & ruleName & """ program=""" & arg1 & """ action=allow dir=out enable=yes"
shell.Run command1, 0, True ' 0 表示静默,True 表示等待命令执行完成
shell.Run command2, 0, True
删除规则的脚本如下
Dim shell
Set shell = CreateObject("WScript.Shell")
Dim ruleName
ruleName = "my dicom viewer"
Dim command1
command1 = "netsh advfirewall firewall delete rule name=""" & ruleName & """ "
shell.Run command1, 0, True ' 0 表示静默,True 表示等待命令执行完成
因为要在安装或者卸载时调用,所以这个文件要被放到安装包中。
Section "MainSection" SEC01
SetOutPath "$INSTDIR"
SetOverwrite ifnewer
File "Script\after-install.vbs"
File "Script\after-uninstall.vbs"
SectionEnd
在安装成功之后调用
; 安装成功之后调用
Function .onInstSuccess
ExecWait '"wscript.exe" "$INSTDIR\after-install.vbs" "$INSTDIR\DicomViewer.exe"'
FunctionEnd
在卸载删除全部文件之前调用。因为这里是调用安装目录下的文件,所以不能放在 Function un.onUninstSuccess 中处理,因为那时候,文件都已经被删除了,无法被调用。
Section Uninstall
Delete "$INSTDIR\uninst.exe"
Delete "$INSTDIR\DicomViewer.exe"
ExecWait '"wscript.exe" "$INSTDIR\after-uninstall.vbs" '
Delete "$INSTDIR\*.*"
RMDir /r "$INSTDIR"
SectionEnd
注意事项
netsh advfirewall 命令操作,需要管理员权限。通常安装程序会以管理员身份运行,如果不是,则需要注意这个问题。