MAKEMSI quickly and reliably creates MSI files in a non-programmatic way
Have your say! Join the MAKEMSI discussion list or view archive! Suggest improvements. No question too simple or too complex.
[Bottom][Contents][Prev]: CACLS.EXE - How to use Well Known SID[Next]: Patch Creation - Julian Onions
Have your say! Join the MAKEMSI discussion list or view archive! Suggest improvements. No question too simple or too complex.
\->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.


Microsoft awarded me an MVP (Most Valuable Professional award) in 2004, 2005, 2006, 2007, 2008 & 2009 for the Windows SDK (Windows Installer) area.Please email me any feedback, additional information or corrections.
See this page online (look for updates)

[Top][Contents][Prev]: CACLS.EXE - How to use Well Known SID[Next]: Patch Creation - Julian Onions


MAKEMSI© is (C)opyright Dennis Bareis 2003-2008 (All rights reserved).
Saturday May 28 2022 at 3:11pm
Visit MAKEMSI's Home Page
Microsoft awarded me an MVP (Most Valuable Professional award) in 2004, 2005, 2006, 2007, 2008 & 2009 for the Windows SDK (Windows Installer) area.