NSIS 指令碼,安裝時新增防火牆規則

J.晒太阳的猫發表於2024-08-30

場景

在 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 命令操作,需要管理員許可權。通常安裝程式會以管理員身份執行,如果不是,則需要注意這個問題。

原文連結:https://www.cnblogs.com/jasongrass/p/18389183

相關文章