Wenn ein App-V Paket Firewall Regeln mitbringen soll, beispielsweise um einen Port für einen eingehenden- oder ausgehenden Datenbankzugriff zu öffnen, gibt es mehrere Wege, um dies zu erreichen. Das größte Problem dabei ist jedoch, dass eine Anwendung sowohl global als auch lokal für einen Benutzer veröffentlicht werden kann. Auf Terminalservern kann es für die gleiche Anwendung sogar verschiedene Veröffentlichungspunkte für eine Anwendung im System geben. Nämlich wenn eine Anwendung gleichzeitig für mehrere Benutzer veröffentlicht wird.
Programmbezogene Firewalleinstellungen beziehen sich dabei immer auf einen Anwendungspfad. Nun, der kann sich je nach Integrationspunkt per User unterscheiden und schlimmer, das folgende Bild zeigt einen aktuellen Firefox, der einmalig für einen Benutzer veröffentlicht wurde und einmalig gestartet ist. Es gibt hier zwei unterschiedliche Pfade:

image001

Welcher Pfad soll nun verwendet werden? Ich habe dazu einen Blog gefunden, der hier den Pfad unter dem Integrationspunkt angibt und das mal direkt getestet:


image002
Leider ohne Erfolg. In dem Blog stand also vermutlich nicht die korrekte Lösung. Wenn man aber nun den Pfad im App-V Cache angibt, wird auch wirksam blockiert. Der Firefox kann keine Webseite mehr öffnen.

image003

Nun passiert das beispielsweise mit einer älteren Firefox Version nicht, dass mehrere Instanzen mit verschiedenen Pfaden gestartet werden und auch nicht mit vielen anderen App-V Paketen ist so ein Verhalten eher selten.
 (Get-Process -Name firefox).Path
C:\Users\\AppData\Local\Microsoft\AppV\Client\Integration\72017E9D-470F-45E5-B48A-475F20CD3493\Root\VFS\ProgramFilesX86\Mozilla Firefox\firefox.exe
Firefox 46 startet hier nur eine Instanz unter dem Integrationspunkt des Benutzers. Aber die Firewallregel zieht wiederum leider nicht! Wird wiederum der Pfad im App-V Cache (C:\ProgramData\App-V) genommen, blockiert auch die Windows Firewall. Also ist für jede Firewallregel mit App-V immer nur dieser Pfad wichtig und es wird auch nur eine Regel für eine App-V Anwendung benötigt, auch wenn es viele Integrationspunkte gibt. Das Ganze funktioniert natürlich auch für eine globale Veröffentlichung. Auch hier funktioniert der globale Integrationspfad nicht (C:\pOrgramData\Microsoft\...), sondern wiederum nur der Pfad auf den App-V Cache:
Korrekter Pfad für Firewallregeln mit App-V Anwendungen
C:\ProgramData\App-V\PACKAGEID\VERSIONID\....
Nun, wir benötigen ein Skript, welches die Regeln sauber in das System bringt, ohne doppelte Einträge zu erzeugen. Dazu sind vorhandene Regeln abzufragen und eine App-V Regel unter einer eindeutigen ID zu erzeugen. Ein Skript zur Erzeugung der Firewallregeln kann über den AddPackage Trigger aktiviert werden. Das Skript muss dabei unabhängig von der Packageversion den korrekten Pfad bestimmen, damit das Skript im Paket nicht bei jeder neuen Version geändert werden muss.
Ein Remove der Firewallregeln ist wünschenswert und kann beispielsweise über RemovePackage erfolgen.
Wir nutzen einen VBS Wrapper für Skripte, da dieses schneller und ressourcenschonender geladen werden kann als beispielsweise ein PowerShell. Weiterhin werden mit dem Wrapper Fenster versteckt, die beim Hinzufügen des Paketes ansonsten erscheinen. Im Grunde kann man damit aber auch ein PowerShell Skript vollständig verstecken. Das geht sicher auch alles eleganter. Beispielweise wenn die Parameter auch direkt dem VBS übergeben werden. Für Vorschläge bin ich hier offen.
runhidden-addFirewall.vbs zum Anlegen der Regeln. Das Skript wird versteckt gestartet:

' Andreas Nick 2017
' Hide Script

scriptdir = CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName)
'msgbox scriptdir ,0, "Script path" 

Set objShell = CreateObject("WScript.Shell")
execpath = "CMD /C " & scriptdir & "\SetFirewall.cmd -AddFirewallRule"  
objShell.Run execpath, 0, False
Set objShell = Nothing

 runhidden-delFirewall.vbs zum Löschen der Regeln. Das Skript wird versteckt gestartet:

' Andreas Nick 2017
' Hide Script

scriptdir = CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName)
'msgbox scriptdir ,0, "Script path" 

Set objShell = CreateObject("WScript.Shell")
execpath = "CMD /C " & scriptdir & "\SetFirewall.cmd -DelFirewallRule"  
objShell.Run execpath, 0, False
Set objShell = Nothing

Warum nun eine CMD Batch zum Setzen der Regeln? Warum nicht? CMD ist klein und wird wiederum sehr schnell ausgeführt. Der VBS Wrapper versteckt das Fenster. Fast jeder hat das Knowhow um eine CMD zu bearbeiten insbesondere langjährige Paketierungsexperten. Ich mag PowerShell aber ich bin auch ein Freund davon das Richtige an der richtigen Stelle zu nutzen.

Das folgende Batchskript zum setzen der Firewallregeln kennt die Parameter -AddFirewallRule zum Hinzufügen der Regel und -DelFirewallRule zum Entfernen. Im Kopfteil des Skripts muss der Name der Regel gesetzt werden. Unter diesem Namen taucht der Eintrag später in den Firewalleinstellungen auf:

SET RuleName=BlockAppVFirefox

image004

der relative Pfad im App-V Verzeichnis auf die Exe Datei gesetzt werden. Zum Beispiel:

SET PROGRAMRELATIVE=Root\VFS\ProgramFilesX86\Mozilla Firefox\firefox.exe

Der Pfad wird über eine Veröffentlichung des Paketes ermittelt oder beispielsweise durch Auspacken der .appv Datei mit einem Zipper (7Zip etc.).
Firewallregeln dürfen mehrfach unter dem gleichen Namen auftauchen. Das macht auch Sinn, wenn eine Anwendung mehrere Regeln benötigt. Wenn ein Firewallregel unter einem Namen nur einmal existieren soll muss eine Abfrage dafür existieren . Problematisch ist, wenn mehrfach die gleiche Regel erstellt wird und diese nach einem Remove des Paketes wieder gelöscht wird. Um das zu verhindern kann der Name pro Regel eindeutig gewählt werden und mit dem folgenden Blog wird abgefragt, ob es die Regel schon gibt. Ansonsten wird die Erstellung übersprungen:

::Firewall rule exist?
::Example - detect existing rule
::netsh advfirewall firewall show rule name="%RuleName%"
::if %ERRORLEVEL%==0 goto :RuleExist 

Wenn gewünscht hier die „::“ Doppelpunkte am Anfang der jeweiligen Zeilen entfernen.
Eine Firewallregel wird mit dem Befehl „netsh advfirewall firewall“ erzeugt. Hier einige Beispiele:
Erlauben des Programmes program= für die „In“ Regel (eingehender Datenverkehr) auf Domänenebene.

netsh advfirewall firewall add rule name="%RuleName%" dir=in action=allow program="%APPVROOT%\%PROGRAMRELATIVE%" profile=domain protocol=TCP

Blocken von Port 80 und 443 für eingehenden Datenverkehr (alle Programme), alle Ebenen:

netsh advfirewall firewall add rule name="%RuleName%" protocol=TCP dir=in localport=80,443 action=block

Blocken von Port 80 und 443 für ein bestimmtes Programm und den ausgehenden Datenverkehr. Beispielsweise wenn eine Anwendung „nach Hause telefonieren“ will. Die Blöcke sind entsprechend im Batch anzulegen. Hier das Batch zum Anlegen der Regeln.

@Echo Off
:: Andreas Nick 2017
:: Add a firewall rule for a App-V Package
::-AddFirewallRule - Insert a new firewall rule
::-DelFirewallRule - Remove a firewall rule
::
::Syntax: SetFirewall.cmd -AddFirewallRule

SET RuleName=BlockAppVFirefox
if "%1%"=="" goto Error
::we are in the script directory

SET SCRIPTDIR=%CD%
cd ..
SET APPVROOT=%CD%
cd %SCRIPTDIR%

::For example = Root\VFS\ProgramFilesX86\Mozilla Firefox\firefox.exe
SET PROGRAMRELATIVE=Root\VFS\ProgramFilesX86\Mozilla Firefox\firefox.exe

if "%1%"=="-DelFirewallRule" goto DelFirewallRule
if "%1%"=="-AddFirewallRule" goto AddFirewallRule
goto Error

::Add
:AddFirewallRule
Echo Insert firewall rule %RuleName%
::Firewall rule exist?
::Example - detect existing rule
::netsh advfirewall firewall show rule name="%RuleName%"
::if %ERRORLEVEL%==0 goto :RuleExist

:: Insert firewall rules
::

::Example Allow
::call netsh advfirewall firewall add rule name="%RuleName%" dir=in action=allow program="%APPVROOT%\%PROGRAMRELATIVE%" profile=domain protocol=TCP
:: Example Block
::netsh advfirewall firewall add rule name="%RuleName%" protocol=TCP dir=in localport=80,443 action=block
netsh advfirewall firewall add rule name="%RuleName%" program="%APPVROOT%\%PROGRAMRELATIVE%" protocol=TCP dir=out remoteport=80,443 action=block

goto Ende

::Delete
:DelFirewallRule
Echo Delete firewall rule %RuleName%
::Firewall rule exist?
::netsh advfirewall firewall show rule name="%RuleName%"
:: 1 it not exist!
::if %ERRORLEVEL%==1 goto :RuleExist

call netsh advfirewall firewall delete rule name="%RuleName%" 

goto ende

:RuleExist
Echo Error: The Rule %RuleName% exist

:Error
Echo Error Use -AddFirewallRule oder -DelFirewallRule 

:Ende

 Die Skripte sind in den „Scripts“ Ordner des App-V Paketes zu kopieren.

image005

In der DeploymentConfiguration kann anschließend im MaschinenSkript Teil der Aufruf zum Anlegen und zum Löschen der Regel definiert werden. Wichtig hierbei ist, dass die Aktion mit Systemrechten durchgeführt werden muss. Daher ist der Maschinenteil zwingend. Diese Skripte würden nicht für den Benutzer funktionieren:

image006

Wer die Skripte gerne im Paket mag und nicht außerhalb, kann jetzt auch über einen Export des Manifests diesen Teil direkt in das AppXManifest integrieren.

image007

Dazu muss dann jeweils ein „appv:“ vor die einzelnen Tags gesetzt werden.

image008

Wenn alles soweit korrekt angelegt wurde, erscheint beim Veröffentlichen die Firewallregel in den Systemeinstellungen und beim Remove wird diese wieder gelöscht. Das Löschen kann man sich wiederum ersparen, wenn man für ein Nonperstistend System veröffentlicht. Eventuell gibt es Probleme, wenn Integrationspunkte durch ein UEV Management einfach geladen werden. Dann muss das Paket global auf dem Server veröffentlich werden, damit die Regel existiert.