Public/Asa/Get-PwAsaNatPolicy.ps1

function Get-PwAsaNatPolicy {
    [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-PwAsaNatPolicy:"

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

    # Get Network Objects to resolve network nat
    # Get interfaces to resolve pat statements
    if ($ConfigPath) {
        $Objects = Get-PwAsaObject -ConfigPath $ConfigPath -Verbose:$false
        $Interfaces = Get-PwAsaInterface -ConfigPath $ConfigPath -Verbose:$false
    } else {
        $Objects = Get-PwAsaObject -ConfigArray $ConfigArray -Verbose:$false
        $Interfaces = Get-PwAsaInterface -ConfigArray $ConfigArray -Verbose:$false
    }
    $NetworkObjects = $Objects | Where-Object { $_.GetType().Name -eq 'NetworkObject' }
    $NetworkObjectsWithNat = $NetworkObjects | Where-Object { $_.NatSourceInterface }
    $NetworkObjectsWithNatNeeded = $true

    Write-Verbose "$VerbosePrefix NetworkObjectsWithNat: $($NetworkObjectsWithNat.Count)"

    # Setup return Array
    $ReturnArray = @()

    $IpRx = [regex] "(\d+)\.(\d+)\.(\d+)\.(\d+)"
    $JustIpRx = [regex] '^(\d+)\.(\d+)\.(\d+)\.(\d+)$'

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

    :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 }

        #More prompts and blank lines
        $Regex = [regex] '^<'
        $Match = Get-RegexMatch $Regex $entry
        if ($Match) {
            continue
        }
        $Regex = [regex] '^\s+$'
        $Match = Get-RegexMatch $Regex $entry
        if ($Match) {
            continue
        }

        # Inject Network Nat
        $Regex = [regex] '^!$'
        $Match = Get-RegexMatch $Regex $entry
        if ($Match) {
            Write-Verbose "$VerbosePrefix matched !"
            if ($ReturnArray.Count -gt 0) {
                Write-Verbose "$VerbosePrefix ReturnArray -gt 0"
                if ($NetworkObjectsWithNat.Count -gt 0) {
                    Write-Verbose "$VerbosePrefix NetworkObjectsWithNat -gt 0"
                    if ($NetworkObjectsWithNatNeeded) {
                        Write-Verbose "$VerbosePrefix NetworkObjectsWithNatNeeded -eq $true"
                        foreach ($object in $NetworkObjectsWithNat) {
                            $n++
                            Write-Verbose "$VerbosePrefix adding object NAT"
                            $NewObject = [NatPolicy]::new("Asa")
                            $ReturnArray += $NewObject
                            Write-Verbose "$VerbosePrefix $entry"

                            $NewObject.Number = $n
                            $NewObject.Name = $object.Name
                            $NewObject.SourceInterface = $object.NatSourceInterface
                            $NewObject.DestinationInterface = $object.NatDestinationInterface
                            $NewObject.OriginalSource = $object.Member
                            if ($JustIpRx.Match($object.NatSourceAddress).Success) {
                                $NewObject.TranslatedSource = $object.NatSourceAddress + '/32'
                            } else {
                                $NewObject.TranslatedSource = $object.NatSourceAddress
                            }
                            $NewObject.SourceTranslationType = 'ObjectNat'
                            $NetworkObjectsWithNatNeeded = $false
                        }
                    }
                }
            }
        }

        # End object
        $Regex = [regex] "^[^\ ]"
        $Match = Get-RegexMatch $Regex $entry
        if ($Match) {
            $KeepGoing = $false
            $Protocol = $null
        }

        $EvalParams = @{ }
        $EvalParams.StringToEval = $entry

        # Single Line Nat
        #nat (inside,outside) after-auto source dynamic any pat-pool Outside_Pool inactive

        $EvalParams.Regex = [regex] "(?x)
                                     ^nat\ \((?<srcint>.+?),(?<dstint>.+?)\)
                                     (\ after-auto)?
                                     \ source\ (?<srctrantype>.+?)\ (?<src>.+?)(\ pat-pool)?\ (?<transrc>[^\ ]+)
                                     (\ destination\ (?<dsttrantype>.+?)\ (?<dst>.+?)\ (?<trandst>[^\ ]+))?
                                     (?<noproxyarp>\ no-proxy-arp)?
                                     (?<routelookup>\ route-lookup)?
                                     (?<inactive>\ inactive)?"


        $Eval = Get-RegexMatch @EvalParams
        if ($Eval) {
            $n++
            $NewObject = [NatPolicy]::new("Asa")
            $ReturnArray += $NewObject
            Write-Verbose "$VerbosePrefix $entry"

            $NewObject.Number = $n
            $NewObject.SourceInterface = $Eval.Groups['srcint'].Value
            $NewObject.DestinationInterface = $Eval.Groups['dstint'].Value
            $NewObject.OriginalSource = $Eval.Groups['src'].Value
            $NewObject.OriginalDestination = $Eval.Groups['dst'].Value
            $NewObject.TranslatedSource = $Eval.Groups['transrc'].Value
            $NewObject.TranslatedDestination = $Eval.Groups['trandst'].Value
            $NewObject.SourceTranslationType = $Eval.Groups['srctrantype'].Value
            $NewObject.DestinationTranslationType = $Eval.Groups['dsttrantype'].Value

            if ($Eval.Groups['noproxyarp'].Value) {
                $NewObject.ProxyArp = $false
            }

            if ($Eval.Groups['routelookup'].Value) {
                $NewObject.RouteLookup = $true
            }

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

        # static pat pre-8.3
        # static (inside,outside) tcp interface 3303 192.0.2.1 ssh netmask 255.255.255.255
        $EvalParams.Regex = [regex] "(?x)
                                     ^static\ \((?<srcint>.+?),(?<dstint>.+?)\)
                                     \ (?<protocol>tcp|udp)
                                     \ (?<transrc>.+?)
                                     \ (?<tranport>.+?)
                                     \ (?<src>.+?)
                                     \ (?<port>.+?)
                                     \ netmask
                                     \ (?<mask>[^\ ]+)
                                     (?<inactive>\ inactive)?"


        $Eval = Get-RegexMatch @EvalParams
        if ($Eval) {
            $n++
            $NewObject = [NatPolicy]::new("Asa")
            $ReturnArray += $NewObject
            Write-Verbose "$VerbosePrefix static nat: $entry"

            $NewObject.Number = $n
            $NewObject.SourceInterface = $Eval.Groups['srcint'].Value
            $NewObject.DestinationInterface = $Eval.Groups['dstint'].Value
            $NewObject.OriginalSource = $Eval.Groups['src'].Value + '/' + (ConvertTo-MaskLength $Eval.Groups['mask'].Value)
            if ($Eval.Groups['transrc'].Value -eq 'interface') {
                $InterfaceLookup = $Interfaces | Where-Object { $_.Nameif -eq $NewObject.DestinationInterface }
                $InterfaceLookup = $InterfaceLookup.Ipaddress -replace '\/\d+', "/$(ConvertTo-MaskLength $Eval.Groups['mask'].Value)"
                $NewObject.TranslatedSource = $InterfaceLookup
            } else {
                if ($IpRx.Match($Eval.Groups['transrc'].Value).Success) {
                    $NewObject.TranslatedSource = $Eval.Groups['transrc'].Value + '/' + (ConvertTo-MaskLength $Eval.Groups['mask'].Value)
                } else {
                    $NewObject.TranslatedSource = $Eval.Groups['transrc'].Value
                }
            }

            $Port = $Eval.Groups['port'].Value
            if ($Port -match '[a-z]') {
                $NewObject.OriginalService = $Port
            } else {
                $NewObject.OriginalService = $Eval.Groups['protocol'].Value + '/' + $Port
            }

            $TranslatedPort = $Eval.Groups['tranport'].Value
            if ($TranslatedPort -match '[a-z]') {
                $NewObject.TranslatedService = $TranslatedPort
            } else {
                $NewObject.TranslatedService = $Eval.Groups['protocol'].Value + '/' + $TranslatedPort
            }
            continue fileloop
        }

        # static single line nat from pre-8.3
        # static (dmz,outside) 198.51.100.1 192.0.2.1 netmask 255.255.255.255

        $EvalParams.Regex = [regex] "(?x)
                                     ^static\ \((?<srcint>.+?),(?<dstint>.+?)\)
                                     \ (?<src>.+?)
                                     \ (?<transrc>.+?)
                                     \ netmask
                                     \ (?<mask>[^\ ]+)
                                     (?<inactive>\ inactive)?"


        $Eval = Get-RegexMatch @EvalParams
        if ($Eval) {
            $n++
            $NewObject = [NatPolicy]::new("Asa")
            $ReturnArray += $NewObject
            Write-Verbose "$VerbosePrefix $entry"

            $NewObject.Number = $n
            $NewObject.SourceInterface = $Eval.Groups['srcint'].Value
            $NewObject.DestinationInterface = $Eval.Groups['dstint'].Value
            $NewObject.OriginalSource = $Eval.Groups['src'].Value + '/' + (ConvertTo-MaskLength $Eval.Groups['mask'].Value)

            if ($IpRx.Match($Eval.Groups['transrc'].Value).Success) {
                $NewObject.TranslatedSource = $Eval.Groups['transrc'].Value + '/' + (ConvertTo-MaskLength $Eval.Groups['mask'].Value)
            } else {
                $NewObject.TranslatedSource = $Eval.Groups['transrc'].Value
            }
        }
    }

    foreach ($nat in $ReturnArray) {
        # Nat Exempt Check
        if ($nat.OriginalSource -eq $nat.TranslatedSource) {
            if ($nat.OriginalDestination -eq $nat.TranslatedDestination) {
                if ($nat.OriginalService -eq $nat.TranslatedService) {
                    $global:NewObject = $nat
                    $nat.NatExempt = $true
                }
            }
        }
    }

    return $ReturnArray
}