Adding multiple firewall rules in powershell without creating duplicate entries

Viewed 293

I am trying to create multiple firewall rules, but I don't want to create a duplicate rule if it already exists.

Currently, my script will create the first rule, but then as it goes through the loop, it will always say that there's already a duplicate rule, so it will stop. Is there a way to apply all the rules in my array?

$c = "wsbxlcfe101"

$fwNames = @("ECMP - OutSystems LifeTime", "ECMP - OutSystems Deployment Controller")

foreach($name in $fwNames){

    $session = New-PSSession -ComputerName $c

    $ifFirewallExists = Invoke-Command -Session $session -ScriptBlock {              
        Get-NetFirewallRule -Direction Inbound -ErrorAction SilentlyContinue | where DisplayName -Match "ECMP" | select DisplayName, Enabled, Direction, Action
    }
    if ($ifFirewallExists.DisplayName){
        Write-Host "firewall rules already created." -ForegroundColor Red  
    }            
    else {
        New-NetFirewallRule -DisplayName $name -Direction Inbound -RemoteAddress Any -Action Allow -Protocol TCP -LocalPort "80","443"
        Write-Host "Rules created." -ForegroundColor Green
    }
    Remove-PSSession -Session $session         
}

EDIT*****

Here's the updated code, looks to be working

try {

    $c = "wsbxlcfe101"
  
    $session = New-PSSession -ComputerName $c

    Invoke-Command -ScriptBlock { 
    
        $fwNames = @("ECMP - OutSystems LifeTime", "ECMP - OutSystems Deployment Controller")

        foreach($name in $fwNames){       
    
                $FirewallRules = Get-NetFirewallRule -Direction Inbound -ErrorAction SilentlyContinue 

                if ($FirewallRules.DisplayName -eq $name){
                    Write-Host "firewall rules already created." -ForegroundColor Red  
                }            
                else {
                    New-NetFirewallRule -DisplayName $name -Direction Inbound -RemoteAddress Any -Action Allow -Protocol TCP -LocalPort "80","443"
                    Write-Host "$name rule created." -ForegroundColor Green
                }
        }
       
    } -Session $session
}
catch {
    Write-Host $_ -ForegroundColor Red
}
finally {
    Get-PSSession | Remove-PSSession 
}
1 Answers

Without modifying too much of your code:

Try {

    #$c = "wsbxlcfe101"X
    $PSSession = New-PSSession -ComputerName "wsbxlcfe101" -ErrorAction Stop


    Invoke-Command -ScriptBlock {

        $FireWallRules = Get-NetFirewallRule -Direction Inbound

        $fwNames = @("ECMP - OutSystems LifeTime", "ECMP - OutSystems Deployment Controller")
            foreach ($Name in $fwNames) {

                foreach ($Rule in $FireWallRules) {

                    if ($Name -match $Rule.DisplayName) {

                        "Firewall Rule [$Name] already exists!"

                    }
                    else {
                        
                        New-NetFirewallRule -DisplayName $Name `
                                            -Direction Inbound `
                                            -RemoteAddress Any `
                                            -Action Allow `
                                            -Protocol TCP `
                                            -LocalPort "80","443"

                        "Firewall Rule [$Name] Created."

                    }

                }

            }

    } -Session $PSSession
} 
Catch [System.Management.Automation.Remoting.PSRemotingTransportException] {

    $Error[0].Exception.Message.Split('.')[1].Trim()

} 
Finally {

    Get-PSSession | Remove-PSSession

}

What you're doing is checking against "ECMP" using the -Match operator which will test true against anything with "ECMP" in the name. That's why you're getting the message that the fire wall rule is already created. Now, let's go back to some quick powershell basics.

  1. Let's wrap your code into a Try and Catch block to catch the exception thrown if you can't establish a connection to the remote PC.
  2. What you're currently doing with creating the PSSession the way you have it, is what we consider to be, "Computationally Expensive". Think about it this way... for each name in your array, create a new session for the same computer, and re-run the same command to check against it for each amount of values that are in your array. Creating one session is enough.
  3. You can send the entirety of the command over to the remote machine to do the work on that end, instead of it having to serialize it into objects, send it over to your machine, test against it, then repeat the process; this goes back to being "computationally expensive".

This allows you to create one PSSession, and send over the command just once without taking a toll on your computers resources. Please note that this hasn't been tested.

Related