Public/Asa/Get-PwAsaSecurityPolicy.ps1

function Get-PwAsaSecurityPolicy {
    [CmdletBinding()]
    <#
        .SYNOPSIS
            Gets named addresses from saved ASA config file.
    #>


    Param (
        [Parameter(Mandatory = $True, Position = 0, ParameterSetName = 'path')]
        [string]$ConfigPath,

        [Parameter(Mandatory = $True, Position = 0, ParameterSetName = 'array')]
        [array]$ConfigArray
    )

    # It's nice to be able to see what cmdlet is throwing output isn't it?
    $VerbosePrefix = "Get-PwAsaSecurityPolicy:"

    Write-Verbose "$VerbosePrefix Getting rules from $ConfigPath"

    # Check for path and import
    if ($ConfigPath) {
        if (Test-Path $ConfigPath) {
            $LoopArray = Get-Content $ConfigPath
        }
    } else {
        $LoopArray = $ConfigArray
    }

    # Setup return Array
    $ReturnArray = @()

    $IpRx = [regex] "(\d+)\.(\d+)\.(\d+)\.(\d+)"
    $n = 1

    $TotalLines = $LoopArray.Count
    $i = 0
    $StopWatch = [System.Diagnostics.Stopwatch]::StartNew() # used by Write-Progress so it doesn't slow the whole function down

    $ReturnObject = @()

    :fileloop foreach ($entry in $LoopArray) {
        $i++

        # Write progress bar, we're only updating every 1000ms, if we do it every line it takes forever

        if ($StopWatch.Elapsed.TotalMilliseconds -ge 1000) {
            $PercentComplete = [math]::truncate($i / $TotalLines * 100)
            Write-Progress -Activity "Reading Support Output" -Status "$PercentComplete% $i/$TotalLines" -PercentComplete $PercentComplete
            $StopWatch.Reset()
            $StopWatch.Start()
        }

        if ($entry -eq "") { continue }
        $entry = $entry.Trim()

        ###########################################################################################
        # Check for the Section

        $RegexIpOnly = [regex] "(?x)
            ^access-list\s
            (?<aclname>[^\ ]+?)\s

            (
                (?<type>extended)\s
                (?<action>[^\ ]+?)

                # protocol
                \ ((?<prottype>object-group|object)\ )?(?<protocol>[^\ ]+?)

                # source
                (
                    \s((?<srctype>host|object-group|object)\s)(?<source>[^\ ]+)|
                    \s((?<srcnetwork>[^\ ]+)\s(?<srcmask>$IpRx))|
                    \s(?<source>any)
                )

                # destination
                (
                    \s((?<dsttype>host|object-group|object|interface)\s)(?<destination>[^\ ]+)|
                    \s((?<dstnetwork>[^\ ]+)\s(?<dstmask>$IpRx))|
                    \s(?<destination>any)
                )

                # flags
                (?<log>\ log(\ (?<loglevel>\d+|warnings))?)?
                (?<inactive>\ inactive)?
            |
                (?<type>standard)\s
                (?<action>[^\ ]+?)\s
                (
                    ((?<srcnetwork>$IpRx)\ (?<srcmask>$IpRx))|
                    ((?<srctype>host|object-group|object)\ )?(?<source>[^\ ]+)
                )
            )`$
        "


        $RegexDestinationService = [regex] "(?x)
            ^access-list\s
            (?<aclname>[^\ ]+?)\s

            (
                (?<type>extended)\s
                (?<action>[^\ ]+?)

                # protocol
                \ ((?<prottype>object-group|object)\ )?(?<protocol>[^\ ]+?)

                # source
                (
                    \s((?<srctype>host|object-group|object)\s)(?<source>[^\ ]+)|
                    \s((?<srcnetwork>[^\ ]+)\s(?<srcmask>$IpRx))|
                    \s(?<source>any)
                )

                # destination
                (
                    \s((?<dsttype>host|object-group|object|interface)\s)(?<destination>[^\ ]+)|
                    \s((?<dstnetwork>[^\ ]+)\s(?<dstmask>$IpRx))|
                    \s(?<destination>any)
                )

                # service
                (
                    \ (?<svctype>object-group|eq)\ (?<service>[^\ ]+)|
                    \ (?<svctype>range)\ (?<service>\w+\ \w+)|
                    \ (?<service>echo)
                )?

                # flags
                (?<log>\ log(\ (?<loglevel>\d+))?)?
                (?<inactive>\ inactive)?
            |
                (?<type>standard)\s
                (?<action>[^\ ]+?)\s
                (
                    ((?<srcnetwork>$IpRx)\ (?<srcmask>$IpRx))|
                    ((?<srctype>host|object-group|object)\ )?(?<source>[^\ ]+)
                )
            )`$
        "


        $RegexSourceDestinationService = [regex] "(?x)
            ^access-list\s
            (?<aclname>[^\ ]+?)\s

            (
                (?<type>extended)\s
                (?<action>[^\ ]+?)

                # protocol
                \ ((?<prottype>object-group|object)\ )?(?<protocol>[^\ ]+?)

                # source
                (
                    \s((?<srctype>host|object-group|object)\s)(?<source>[^\ ]+)|
                    \s((?<srcnetwork>[^\ ]+)\s(?<srcmask>$IpRx))|
                    \s(?<source>any)
                )

                # sourceservice
                (
                    \s(?<srcsvctype>object-group|eq)\s(?<srcservice>[^\ ]+)|
                    \s(?<srcsvctype>range)\s(?<srcservice>\w+\s\w+)|
                    \s(?<srcservice>echo)
                )?

                # destination
                (
                    \s((?<dsttype>host|object-group|object|interface)\s)(?<destination>[^\ ]+)|
                    \s((?<dstnetwork>[^\ ]+)\s(?<dstmask>$IpRx))|
                    \s(?<destination>any)
                )

                # service
                (
                    \ (?<svctype>object-group|eq)\ (?<service>[^\ ]+)|
                    \ (?<svctype>range)\ (?<service>\w+\ \w+)|
                    \ (?<service>echo)
                )?

                # flags
                (?<log>\ log(\ (?<loglevel>\d+))?)?
                (?<inactive>\ inactive)?
            |
                (?<type>standard)\s
                (?<action>[^\ ]+?)\s
                (
                    ((?<srcnetwork>$IpRx)\ (?<srcmask>$IpRx))|
                    ((?<srctype>host|object-group|object)\ )?(?<source>[^\ ]+)
                )
            )`$
        "


        $RegexRemark = [regex] "(?x)
        access-list\s
        (?<aclname>[^\ ]+?)\s
            remark\s
            (?<remark>.+)
        "


        $MatchRemark = Get-RegexMatch $RegexRemark $entry
        $MatchIpOnly = Get-RegexMatch $RegexIpOnly $entry
        $MatchDestinationService = Get-RegexMatch $RegexDestinationService $entry
        $MatchSourceDestinationService = Get-RegexMatch $RegexSourceDestinationService $entry

        if ($MatchRemark) {
            Write-Verbose "$VerbosePrefix MatchRemark: $i`: $entry"
            $Match = $MatchRemark
        } elseif ($MatchIpOnly) {
            Write-Verbose "$VerbosePrefix RegexIpOnly: $i`: $entry"
            $Match = $MatchIpOnly
        } elseif ($MatchDestinationService) {
            Write-Verbose "$VerbosePrefix RegexDestinationService: $i`: $entry"
            $Match = $MatchDestinationService
        } elseif ($MatchSourceDestinationService) {
            Write-Verbose "$VerbosePrefix RegexSourceDestinationService: $i`: $entry"
            $Match = $MatchSourceDestinationService
        } else {
            $Match = $null
        }


        # access-list outside-in extended permit tcp any object-group DESTINATIONOBJECT eq www


        #$Match = Get-RegexMatch $Regex $entry
        if ($Match) {
            #Write-Verbose "$VerbosePrefix match: $i`: $entry"

            <# if ($Match.Groups['srcservice'].Success) {
                Write-Verbose "$VerbosePrefix SourceService found"
                if (-not $Match.Groups['dstnetwork'].Success) {
                    Write-Verbose "$VerbosePrefix dstnetwork not found"
                    if (-not $Match.Groups['destination'].success) {
                        Write-Verbose "$VerbosePrefix destination not found, updating match"
                        $Regex = [regex] "(?x)
                            access-list\s
                            (?<aclname>[^\ ]+?)\s
                            (
                                remark\s
                                (?<remark>.+)
                            |
                                (
                                    (?<type>extended)\s
                                    (?<action>[^\ ]+?)

                                    # protocol
                                    \ ((?<prottype>object-group|object)\ )?(?<protocol>[^\ ]+?)

                                    # source
                                    (
                                        \ ((?<srcnetwork>$IpRx)\ (?<srcmask>$IpRx))|
                                        \ ((?<srctype>host|object-group|object)\ )?(?<source>[^\ ]+)
                                    )

                                    # destination
                                    (
                                        \ ((?<dstnetwork>$IpRx)\ (?<dstmask>$IpRx))|
                                        \ ((?<dsttype>host|object-group|object|interface)\ )?(?<destination>[^\ ]+)
                                    )
                                    # service
                                    (
                                        \ (?<svctype>object-group|eq)\ (?<service>[^\ ]+)|
                                        \ (?<svctype>range)\ (?<service>\w+\ \w+)|
                                        \ (?<service>echo)
                                    )?

                                    # flags
                                    (?<log>\ log(\ (?<loglevel>\d+))?)?
                                    (?<inactive>\ inactive)?
                                |
                                    (?<type>standard)\s
                                    (?<action>[^\ ]+?)\s
                                    (
                                        ((?<srcnetwork>$IpRx)\ (?<srcmask>$IpRx))|
                                        ((?<srctype>host|object-group|object)\ )?(?<source>[^\ ]+)
                                    )
                                )
                            )
                        "
                        $Match = Get-RegexMatch $Regex $entry
                    } else {
                        Write-Verbose "$VerbosePrefix dstnetwork found, keeping current match"
                    }
                } else {
                    Write-Verbose "$VerbosePrefix destination found, keeping current match"
                }
            } else {
                Write-Verbose "$VerbosePrefix no SourceService found, keeping current match"
            } #>


            if ($Match.Groups['remark'].Success) {
                $Remark = $Match.Groups['remark'].Value
                #$NewObject.Comment = $Remark
                Write-Verbose "$VerbosePrefix Adding remark: $Remark"
                continue
            } else {
                # create new ace
                $NewObject = [SecurityPolicy]::new("")

                $NewObject.AccessList = $Match.Groups['aclname'].Value
                $NewObject.AclType = $Match.Groups['type'].Value

                # See if we need to increment the sequence number
                $CheckForAcl = $ReturnArray | Where-Object { $_.AccessList -eq $NewObject.AccessList }
                if ($CheckForAcl) {
                    $n++
                } else {
                    $n = 1
                    # had to add this to account for remarks that are leftover at the end of ACLs
                    $Remark = $null
                }

                # add remark
                if ($Remark) {
                    $NewObject.Comment = $Remark
                    $Remark = $null
                }

                $ReturnArray += $NewObject
                $NewObject.Number = $n

                Write-Verbose "$VerbosePrefix Creating new SecurityPolicy: $($NewObject.AccessList):$($NewObject.AclType):$n"
            }

            $NewObject.Action = $Match.Groups['action'].Value
            $NewObject.Protocol = $Match.Groups['protocol'].Value

            # Source
            if ($Match.Groups['srcnetwork'].Success) {
                $Source = $Match.Groups['srcnetwork'].Value
                if ($Match.Groups['srcmask'].Success) {
                    $Source += '/'
                    $Source += ConvertTo-MaskLength $Match.Groups['srcmask'].Value
                }
                $NewObject.Source = $Source
            } else {
                #$NewObject.SourceType = $Match.Groups['srctype'].Value
                $NewObject.Source = $Match.Groups['source'].Value
            }

            # Destination
            if ($Match.Groups['dstnetwork'].Success) {
                $Destination = $Match.Groups['dstnetwork'].Value
                if ($Match.Groups['dstmask'].Success) {
                    $Destination += '/'
                    $Destination += ConvertTo-MaskLength $Match.Groups['dstmask'].Value
                }
                $NewObject.Destination = $Destination
            } else {
                #$NewObject.DestinationType = $Match.Groups['dsttype'].Value
                $NewObject.Destination = $Match.Groups['destination'].Value
            }

            if ($Match.Groups['inactive'].Value) {
                $NewObject.Enabled = $false
            }

            #Service
            $NewObject.Protocol = $Match.Groups['protocol'].Value
            $NewObject.Service = $Match.Groups['service'].Value
            <# if ($ProtocolType -match 'object') {
                $NewObject.Service = $NewObject.Protocol
            } else { #>

            if ($NewObject.Service -match ".+\ .+") {
                $NewObject.Service = $NewObject.Protocol + '/' + ($NewObject.Service -replace ' ', '-')
            } elseif ($NewObject.Service -match '^\d+$') {
                $NewObject.Service = $NewObject.Protocol + '/' + $NewObject.Service
            }
            <# } #>

            #SourceService
            $NewObject.SourceService = $Match.Groups['srcservice'].Value
            if ($NewObject.SourceService -match ".+\ .+") {
                $NewObject.SourceService = $NewObject.Protocol + '/' + ($NewObject.SourceService -replace ' ', '-')
            } elseif ($NewObject.SourceService -match '^\d+$') {
                $NewObject.SourceService = $NewObject.Protocol + '/' + $NewObject.SourceService
            }

            continue
        }
    }
    return $ReturnArray
}