\
User Contributions
FIREWALL.MMH - Adding and Removing Windows Firewall Exceptions
FIREWALL.MMH - Adding and Removing Windows Firewall Exceptions |
This information and/or code in this section was provided by Christoph Mockenhaupt (thank you).
The supplied sample code to exercise the new command:
;--- Firewall exception list entry for MyApp.exe -----------------------------
; create data to be passed to the firewall macro
#data "FwMyApp"
"FullPath" "[INSTALLDIR]MyApp.exe"
"FriendlyName" "<$ProdInfo.ProductName>"
"RemoteAddresses" "10.0.42.0/255.255.255.0" ;; this can be omitted or "*" for all
#data
<$CaAddApplicationToFirewallExceptionList "FwMyApp" DescriptionAdd="Adding MyApp to the firewall exception list" DescriptionRemove="Removing MyApp from the firewall exception list">
The required header code (also installed by MAKEMSI):
;----------------------------------------------------------------------------
;
; MODULE NAME: FireWall[ChristophMockenhaupt].mmh
;
; $Author: USER "Dennis" $
; $Revision: 1.3 $
; $Date: 18 Feb 2010 17:54:36 $
; $Logfile: C:/DBAREIS/Projects.PVCS/Win32/MakeMsi/FireWall[ChristophMockenhaupt].mmh.pvcs $
;
; This was supplied by Christoph Vogtlaender in email dated 27 Jan 2010,
; his comments:
;
; I created an macro to modify the MS Windows Firewall exception list
; at install time.
;
; The action is rollback aware, the macro can be called more than once
; to add more than one file, and can handle features.
;
; I think there is enough documentation in the code to understand what it does.
;----------------------------------------------------------------------------
; Description:
; Adds/removes a program from the windows firewall exception list on install/uninstall
;
#ifndef FIREWALL_MMH
#define FIREWALL_MMH
#NextId
#NextId LOCK "FIREWALL.MMH"
;----------------------------------------------------------------------------
;--- Define Feature and Component state queries
;--- for further information see "Conditions - Predefined by MAKEMSI" in
;--- the MAKEMSI doco
;----------------------------------------------------------------------------
#ifndef FeatureIs ;;The user may have already set thee up themselves...
;--- Nope they hadn't... ------------------------------------------------
#define FeatureIs (!{$#1} <$INSTALLCOMPARE_{$IS=^EQUAL^}> <$INSTALLSTATE_{$STATE=^LOCAL^}>) ;; Feature is already installed
#define FeatureWillBe (&{$#1} <$INSTALLCOMPARE_{$IS=^EQUAL^}> <$INSTALLSTATE_{$STATE=^LOCAL^}>) ;; Feature is being installed
#define ComponentIs (?{$#1} <$INSTALLCOMPARE_{$IS=^EQUAL^}> <$INSTALLSTATE_{$STATE=^LOCAL^}>) ;; Component is already installed
#define ComponentWillBe (${$#1} <$INSTALLCOMPARE_{$IS=^EQUAL^}> <$INSTALLSTATE_{$STATE=^LOCAL^}>) ;; Component is being installed
;--- Define valid "IS" parameter comparison types ---------------------------
#define INSTALLCOMPARE_EQUAL =
#define INSTALLCOMPARE_NOT_EQUAL <>
;--- Define valid "STATE" parameter values ----------------------------------
#define INSTALLSTATE_UNKNOWN -1 ;; No action to be taken on the feature or component.
#define INSTALLSTATE_ADVERTISED 1 ;; Advertised feature. This state is not available for components.
#define INSTALLSTATE_ABSENT 2 ;; Feature or component is not present.
#define INSTALLSTATE_LOCAL 3 ;; Feature or component on the local computer.
#define INSTALLSTATE_SOURCE 4 ;; Feature or component run from the source.
#endif
; The vbs code to add/remove an application to/from the firewall exception list
#( '<?NewLine>'
#define @@FirewallVbs
; first we need a VBScript custom action which uses the windows firewall manager api to add/remove a program
<$VbsCa Binary="Firewall.vbs" Pause="N">
<$VbsCaEntry "AddApplicationToExceptionList">
CaDebug 1, "Adding application to Windows firewall exception list..."
Const NET_FW_IP_VERSION_ANY = 2
Const NET_FW_SCOPE_ALL = 0
Dim objFirewall
Dim objAuthApp
Dim objProfile
Dim strRemoteAddresses : strRemoteAddresses = ""
' Enable Application
Err.Clear
On Error resume next 'on SP1 there is no firewall object
Set objFirewall = CreateObject("HNetCfg.FwMgr")
Set objAuthApp = CreateObject("HNetCfg.FwAuthorizedApplication")
Set objProfile = objFirewall.LocalPolicy.CurrentProfile
if 0 = Err.Number then
On Error Goto 0
CaDebug 2, "Setting friendly application name to " & VbsCaCadGet("FriendlyName")
objAuthApp.Name = VbsCaCadGet("FriendlyName")
CaDebug 2, "Setting image file name to " & VbsCaCadGet("FullPath")
objAuthApp.ProcessImageFileName = VbsCaCadGet("FullPath")
objAuthApp.Enabled = True
objAuthApp.IpVersion = NET_FW_IP_VERSION_ANY
objAuthApp.Scope = NET_FW_SCOPE_ALL ' the scope will be overwritten if RemoteAddress other than "" or "*" is specified
CaDebug 0, "If the following call of VbsCaCadGet(RemoteAddresses) fails, no addresses were specified in the data field. This is OK."
On Error Resume Next
strRemoteAddresses = VbsCaCadGet("RemoteAddresses")
Err.Clear
On Error Goto 0
if strRemoteAddresses <> "" then
CaDebug 2, "Setting remote addresses to " & strRemoteAddresses
objAuthApp.RemoteAddresses = strRemoteAddresses
end if
objProfile.AuthorizedApplications.Add objAuthApp
end if
Err.Clear
On Error Goto 0
CaDebug 2, "Done"
<$/VbsCaEntry>
<$VbsCaEntry "RemoveApplicationFromExceptionList">
CaDebug 1, "Removing application from Windows firewall exception list"
Const HKEY_LOCAL_MACHINE = 2
Dim oFirewall : Set oFirewall = Nothing
Dim oProfile : Set oProfile = Nothing
Dim oInstaller : Set oInstaller = Nothing
Dim strSharedComponentKey : strSharedComponentKey = ""
Dim iReferenceCount : iReferenceCount = 0
CaDebug 0, "creating windows installer object"
Set oInstaller = CreateObject("WindowsInstaller.Installer")
CaDebug 0, "done"
' Disable Application only if the shared reference count is 0
' (this applies even if we sequence the action before FileRemove)
On Error Resume Next
strSharedComponentKey = VbsCaCadGet("SharedComponentKey")
Err.Clear
On Error Goto 0
CaDebug 0, "strSharedComponentKey: " & strSharedComponentKey
if strSharedComponentKey <> "" then
CaDebug 0, "checking if reference count for " & strSharedComponentKey & " is greater than ""1"""
On Error Resume Next
iReferenceCount = oInstaller.RegistryValue(HKEY_LOCAL_MACHINE, "Software\Microsoft\Windows\CurrentVersion\SharedDLLs", strSharedComponentKey)
Err.Clear
On Error Goto 0
CaDebug 0, "Reference count is """ & iReferenceCount & """"
end if
if iReferenceCount <= 0 then
CaDebug 0, "Refcount is 0... deleting firewall entry"
On Error resume next 'on SP1 there is no firewall object
Set oFirewall = CreateObject("HNetCfg.FwMgr")
Set oProfile = oFirewall.LocalPolicy.CurrentProfile
if 0 = Err.Number then
On Error Goto 0
CaDebug 0, "Using path " & VbsCaCadGet("FullPath") & " for removal"
oProfile.AuthorizedApplications.Remove VbsCaCadGet("FullPath")
end if
Err.Clear
On Error Goto 0
else
CaDebug 0, "Refcount is > 0... firewall entry will NOT be deleted"
end if
CaDebug 2, "Done"
<$/VbsCaEntry>
<$/VbsCa>
#)
; include the Firewall.vbs code (must only be added once)
dim @@FirewallBinaryExists : @@FirewallBinaryExists = ""
<$Table "Binary">
<$Row @Where="Name = 'Firewall.vbs'" @Code="Y">
@@FirewallBinaryExists = <$COLSTR.Binary.Name>
<$/Row>
<$/Table>
if @@FirewallBinaryExists = "" then
say "Adding firewall vbs code to the binary table."
<$@@FirewallVbs>
end if
#( '<?NewLine>'
;###
;### This Macro is used to create a custom action to add an application to the Windows firewall execption list (Ports are not supported).
;### Parameters:
;### Data (positional) - the name of a two, three, or four column #data block with the Parameters "FullPath", "FriendlyName", "RemoteAddresses" (optional), and "SharedComponentKey" (optional)
;### * FullPath: The full path to the application (e.g. "[INSTALLDIR]TryMy.exe")
;### * FriendlyName: A friendly name for the application, this will be shown in the exception list (e.g. "TryMe (simple MAKEMSI test MSI)" or simply "<$ProdInfo.ProductName>")
;### * RemoteAddresses: RemoteAddresses property of the INetFwAuthorizedApplication Interface, use "" or "*" to disable (see http://msdn.microsoft.com/en-us/library/aa365270(VS.85).aspx)
;### * SharedComponentKey: The KeyFile of a shared component, the firewall entry will only be removed if the reference count will be "0" after removal
;### DescriptionAdd (optional) - This will appear in any MSI log as well as progress bar line #1 when an entry is added to the exception list, defaults to "Setting up Windows firewall"
;### DescriptionRemove(optional) - This will appear in any MSI log as well as progress bar line #1 when an entry is removed from the exception list, defaults to "Setting up Windows firewall"
;### Feature (optional) - The name of the feature the generated firewall rule belongs to
;###
;### This Macro can be called serveral times to add more than one file to the exception list. The name of the supplied data field must be unique!
;###
#define CaAddApplicationToFirewallExceptionList
;--- Do some parameter validations --------------------------------------
{$!KEYWORDS} ;;Don't expect any keywords
{$!:#1,DESCRIPTIONADD,DESCRIPTIONREMOVE,FEATURE} ;;List all valid parameters
#if ['<?Data:{$#1}>' == '']
#error ^The "{$#1}" data structure does not exist!^
#else
#if [<?Data:{$#1}.?> < 2]
#error ^Please pass a valid #data structure. It must have at least two rows defining the parameters "FullPath" and "FriendlyName". Parameter "RemoteAddresses" is optional.^
#endif
#endif
;--- Set up the deferred custom actions -----------------------------------
; these are the standard definitions, add to exception list on install, remove it on uninstall
#define+ @@CONDITION_FIREWALL_INSTALL <$CONDITION_INSTALL_ONLY> ;;condition for install and rollback during install
#define+ @@CONDITION_FIREWALL_UNINSTALL <$CONDITION_UNINSTALL_ONLY> ;;condition for uninstall and rollback during uninstall
#define+ @@SharedFeature {$Feature=^^} ;;Get "feature" parameter passed by invoker
#if ['<$@@SharedFeature>' = '']
;--- No feature passed, are we nested within one --------------------
#define+ @@SharedFeature <$Feature? QUERY="Y">
#endif
#if ['<$@@SharedFeature>' <> '']
; INFO: there could be more than one feature the custom action belongs to, adding all conditions in the sequence table may exceed the maximum string length
; we create a component which belongs to all these features (this works because component<->feature dependencies are set in the FeatureComponent-table and not just in a Condition-field)
; then we can use the <$ComponentWillBe> <$ComponentIs> macros and connect our custom action to the component
<$Component "{$#1}_Firewall" Feature="<$@@SharedFeature>" LM="Y" Directory_="<$AnyDir>">
; if this action is based on features, generate if the component connected to the features will be or is installed; remove it if the component will be uninstalled or becomes advertised
#define+ @@CONDITION_FIREWALL_INSTALL <$ComponentWillBe "{$#1}_Firewall" STATE="LOCAL">
#define+ @@CONDITION_FIREWALL_UNINSTALL <$ComponentIs "{$#1}_Firewall" STATE="LOCAL"> AND (<$ComponentWillBe "{$#1}_Firewall" STATE="ABSENT"> OR <$ComponentWillBe "{$#1}_Firewall" STATE="ADVERTISED">)
<$/Component>
#endif
; on rollback during install
<$VbsCaSetup Data="{$#1}" Binary="Firewall.vbs" Key="{$#1}_FirewallRollBackAdd" Entry="RemoveApplicationFromExceptionList" Seq="InstallFiles-" CONDITION=^<$@@CONDITION_FIREWALL_INSTALL>^ Type="Deferred Rollback System" Description="{$DescriptionRemove='Setting up Windows firewall'}">
; on install
<$VbsCaSetup Data="{$#1}" Binary="Firewall.vbs" Key="{$#1}_FirewallAdd" Entry="AddApplicationToExceptionList" Seq="InstallFiles-" CONDITION=^<$@@CONDITION_FIREWALL_INSTALL>^ Type="Deferred System" Description="{$DescriptionAdd='Setting up Windows firewall'}">
; on uninstall
<$VbsCaSetup Data="{$#1}" Binary="Firewall.vbs" Key="{$#1}_FirewallRemove" Entry="RemoveApplicationFromExceptionList" Seq="<-RemoveFiles" CONDITION=^<$@@CONDITION_FIREWALL_UNINSTALL>^ Type="Deferred System" Description="{$DescriptionRemove}">
; on rollback during uninstall
<$VbsCaSetup Data="{$#1}" Binary="Firewall.vbs" Key="{$#1}_FirewallRollBackRemove" Entry="AddApplicationToExceptionList" Seq="<-RemoveFiles" CONDITION=^<$@@CONDITION_FIREWALL_UNINSTALL>^ Type="Deferred Rollback System" Description="{$DescriptionAdd}">
#)
#NextId UNLOCK "FIREWALL.MMH"
#endif ;; !FIREWALL_MMH
Note that the above uses the
"$FeatureWillBe" and "FeatureIs" macros
which you'll also need to define.