Writing installers for applications requires a substantial effort, even when using tools like InstallShield. My challenge for today was to write as little code as possible (because I’m lazy) to configure Windows Firewall exception rules so that the game I’m working on wouldn’t “pop” a dialog box asking the user to configure firewall settings — this freaks out users and is generally considered a bad thing.
Of course I relied upon Google to find a solution, but boy did I have a tough time finding code to do the job. Many folks run external commands like “netsh” to configure firewall exceptions, but this sucks because the netsh.exe command has different syntax in different versions of Windows. Yuck!
Here’s my solution in visual basic (cscript.exe), which has the virtue of being installed on every modern (XP+) Windows computer in the world.
'configure-firewall.vbs
'Sets Windows firewall permissions for a specific application
'Grants full inbound/outbound access for TCP/UDP
'by Patrick Wyatt 12/22/2011
'MIT License - do with as you will; no warranty
option explicit
'**************************************
const NET_FW_IP_PROTOCOL_TCP = 6
const NET_FW_IP_PROTOCOL_UDP = 17
const NET_FW_RULE_DIR_IN = 1
const NET_FW_RULE_DIR_OUT = 2
'**************************************
sub UpdateFirewallRule (addRules, policy, groupName, ruleName, exePath, netProtocol, direction)
'Prettify the rule name
dim name
name = ruleName
name = name & " - Allow"
if netProtocol = NET_FW_IP_PROTOCOL_TCP then
name = name & " TCP"
elseif netProtocol = NET_FW_IP_PROTOCOL_UDP then
name = name & " UDP"
end if
if direction = NET_FW_RULE_DIR_IN then
name = name & " IN"
elseif direction = NET_FW_RULE_DIR_OUT then
name = name & " OUT"
end if
'Set rule parameters
dim rule
set rule = CreateObject("HNetCfg.FwRule")
rule.Enabled = true
rule.Grouping = groupName
rule.Name = name
rule.ApplicationName = exePath
rule.Protocol = netProtocol
rule.Direction = direction
'Remove old rule
if addRules < 0 then
Wscript.echo " Removing rule '" & name
end if
'Always remove old rule to prevent duplicates
policy.Rules.Remove rule.name
if Err.Number <> 0 then
Wscript.Echo " Removing rule '" & name & "'failed with error '" & Err.Description & "' (" & Err.Number & ")"
Wscript.Quit 1
end if
'Add new rule
if addRules > 0 then
Wscript.echo " Adding rule '" & name
policy.Rules.Add rule
if Err.Number <> 0 then
Wscript.Echo " Adding rule '" & name & "'failed with error '" & Err.Description & "' (" & Err.Number & ")"
Wscript.Echo " did you remember to run this script as administrator?"
Wscript.Quit 1
end if
end if
end sub
'**************************************
sub DisplayRules (policy, groupName)
dim RulesObject
set RulesObject = policy.Rules
Wscript.echo "Displaying firewall rules"
dim Rule
for each Rule in RulesObject
if Rule.Grouping = groupName then
Wscript.Echo " Rule: " & Rule.Name
end if
next
Wscript.echo ""
end sub
'**************************************
'Main program
dim command, groupName, ruleName, exePath
command = Wscript.Arguments.Named("Command")
groupName = Wscript.Arguments.Named("GroupName")
ruleName = Wscript.Arguments.Named("RuleName")
exePath = Wscript.Arguments.Named("ExePath")
Wscript.echo "Firewall rule update arguments:"
Wscript.echo " Command: " & command
Wscript.echo " Grouping: " & groupName
Wscript.echo " RuleName: " & ruleName
Wscript.echo " ExePath: " & exePath
Wscript.echo ""
'Parse command line
dim addRules
if command = "install" then
Wscript.echo "Installing firewall rules"
addRules = 1
elseif command = "remove" then
Wscript.echo "Removing firewall rules"
addRules = -1
elseif command = "display" then
addRules = 0
else
Wscript.echo "Unknown command: " & command
Wscript.Quit 1
end if
dim policy
set policy = CreateObject("HNetCfg.FwPolicy2")
if addRules <> 0 then
UpdateFirewallRule addRules, policy, groupName, ruleName, exePath, NET_FW_IP_PROTOCOL_TCP, NET_FW_RULE_DIR_IN
UpdateFirewallRule addRules, policy, groupName, ruleName, exePath, NET_FW_IP_PROTOCOL_TCP, NET_FW_RULE_DIR_OUT
UpdateFirewallRule addRules, policy, groupName, ruleName, exePath, NET_FW_IP_PROTOCOL_UDP, NET_FW_RULE_DIR_IN
UpdateFirewallRule addRules, policy, groupName, ruleName, exePath, NET_FW_IP_PROTOCOL_UDP, NET_FW_RULE_DIR_OUT
Wscript.echo ""
end if
DisplayRules policy, groupName
Wscript.echo "Success"
Wscript.Quit 0
And here’s a batch file to call this script. Now in real life you wouldn’t use a batch file; you would call the configure-firewall.vbs script directly from your installer script. That’s one of the reasons that the command-line validation of my script doesn’t do much error checking — it’s not for end-users, it’s for you programmer-types.
::sample-firewall-configuration.bat @echo off SETLOCAL EnableExtensions if "%1" == "" ( echo Usage: echo %0 display echo %0 install echo %0 remove exit /B 1 ) %SystemRoot%\System32\cscript.exe //nologo configure-firewall.vbs /GroupName:"!GroupNameHere" /RuleName:"!RuleNameHere" /ExePath:"C:\Windows\notepad.exe" /Command:%1
Use the code as you see fit!
Test message
Test
If you like NSIS http://nsis.sourceforge.net/NSIS_Simple_Firewall_Plugin
Thank you! This helped me out tremendously!
Thanks! This saved me a bunch of time and effort!