Check Logging Status of Palo Alto Firewalls


Posted on November 12, 2020 by

Logs are at the heart of any firewall. So making sure that logs are available to query at all times is important.

One of the features of the Palo Alto firewalls is the ability to forward logs to a Panorama or the Cortex Data Lake service. But it’s important to confirm that the firewall is actually forwarding logs and that some error hasn’t stopped log forwarding.

The easiest way to manually check this on individual firewalls is the “show logging-status” command. It will display the last time logs were forwarded.

But this can be very tedious in an environment with many firewalls. To help automate this process, I created a Powershell script to check the results of “show logging-status” on a given list of firewalls. If any of the firewalls have not forwarded logs in 2+ hours, the list is displayed and (optionally) an email can be sent with the results.

Get-LoggingStatus Powershell script

The script below uses the Palo Alto API to query a list of firewalls. So an API key needs to be configured on the firewalls for this script to work.

See this article to configure an API key on your firewalls.

    HelpMessage='Text file with list of Palo Alto firewalls.')]
    HelpMessage='If used, email will be sent.  If excluded, no email will be sent.')]
    [switch]$sendEmail = $false

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

if (-Not ("TrustAllCertsPolicy" -as [type]))
add-type @"
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    public class TrustAllCertsPolicy : ICertificatePolicy
        public bool CheckValidationResult
            ServicePoint srvPoint, X509Certificate certificate,
            WebRequest request, int certificateProblem
            return true;

    [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

$apiKey = "Your API Key"

$emailFrom = ""
$emailTo = ''
$emailSubject = "Palo Alto FW Logging Issues"
$smtpServer = ""

# How many hours the firewall's last log forward can be behind the current time.
$hourOffset = "2"

$fwLIst = Get-Content $list

$apiStem = "api/?type=op&cmd=%3Cshow%3E%3Clogging-status%3E%3C%2Flogging-status%3E%3C%2Fshow%3E"


$htmlMessage = New-Object System.Text.StringBuilder
$textMessage = New-Object System.Text.StringBuilder

foreach ($fw in $fwLIst){
    $url = "https://$fw/$apiStem&key=$apiKey"

    $WebRequestContent = $null
    $ErrResp = $null

        $WebRequestContent = Invoke-WebRequest -Uri "$url" -Method Get
        $streamReader = [System.IO.StreamReader]::new($_.Exception.Response.GetResponseStream())
        $ErrResp = $streamReader.ReadToEnd() | ConvertFrom-Json

    if ($WebRequestContent -ne $null)
        $JsonFromResponse = $WebRequestContent.Content

    if (($ErrResp) -or ($JsonFromResponse -eq $null))
        Write-Host "There was an error!" -ForegroundColor Red
        Write-Host $ErrResp -ForegroundColor Yellow
    elseif($JsonFromResponse.response.status -ne "success")
        Write-Host "There was an error!" -ForegroundColor Red
        Write-Host $JsonFromResponse.response.result -ForegroundColor Yellow
        Write-Host $JsonFromResponse.response.status -ForegroundColor Yellow
        #$trafficString = Select-String -InputObject $($JsonFromResponse.response.result) -SimpleMatch "traffic" | %{$_.Values}

        $trafficString = $JsonFromResponse.response.result | Where {$_ -match "traffic.*"} | Foreach {$Matches[0]}

        $logType,$logLastCreated,$logLastFwd,$seqNumFwd,$seqNumAck,$totalLogsFwd = $trafficString -split "\s{2,}"

#        Write-Host "Log Type: $logType"
#        Write-Host "Last Log Created: $logLastCreated"
#        Write-Host "Last Log Forwarded: $logLastFwd"

        # Add 12 hours to the Last Log Fwred datetime.  If this is less than the current datetime, logs are not being fowarded.  Add the firewall to the list.
        if ((Get-Date $logLastFwd).AddHours($hourOffset) -lt (Get-Date))
            $fwNotSendingLogs += $fw
            $null = $htmlMessage.AppendLine("<tr><td>$fw</td><td>$logLastFwd</td></tr>")
            $null = $textMessage.AppendLine("$fw last forwarded logs on $logLastFwd")

if ($fwNotSendingLogs)
    $htmlhead = "<html>
                BODY{font-family: Consolas; font-size: 10pt;}
                H1{font-size: 22px; font-family: 'Segoe UI Light','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif;}
                H2{font-size: 18px; font-family: 'Segoe UI Light','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif;}
                H3{font-size: 16px; font-family: 'Segoe UI Light','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif;}
                TABLE{border: 1px solid black; border-collapse: collapse; font-size: 9pt;}
                TH{border: 1px solid #969595; background: #dddddd; padding: 5px; color: #000000;}
                TD{border: 1px solid #969595; padding: 5px; }
                td.pass{background: #B7EB83;}
                td.warn{background: #FFF275;}
      {background: #FF2626; color: #ffffff;}
      {background: #85D4FF;}
				tr:hover {background-color: #85D4FF}
                <p>The following Palo Alto firewalls have stopped forwarding logs:</p>
                <tr><th>Firewall</th><th>Last Log Fowarded</th></tr>"
    $htmltail = "</table></body></html>"

    $body = $htmlhead + $htmlMessage + $htmltail

    If ($sendEmail)
        Send-MailMessage -To $emailTo -body $body -BodyAsHtml -From $emailFrom -Subject $emailSubject -Priority High -smtpServer $smtpServer

    Write-Host $textMessage -ForegroundColor Yellow
    Write-Host "All firewalls are forwarding logs."

Make sure to edit the highlighted lines to add your API key and email settings.

To use the script, save it as “Get-LoggingStatus.ps1” and run it with these command line parameters.

Get-LoggingStatus.ps1 -list "C:\PathTo\firewall.txt" [-sendEmail]

The “-sendEmail” parameter is optional. If used and any firewalls are not sending logs, it will send an email.

The variable “$hourOffset” sets a threshold on how many hours the firewall can be behind for log forwarding.

If you want to test the functionality of the script, set the “$hourOffset” variable to a negative number, like -2. The script will think that all firewalls are failing to forward logs and cause the script to display a list of results similar to the following.

firewall01 last forwarded logs on YYYY/MM/DD HH:MM:SS
firewall02 last forwarded logs on YYYY/MM/DD HH:MM:SS

Just make sure to change the variable back to 2 or whatever threshold you want to set before using the script.

If one or more firewalls are NOT forwarding logs, the best solution is probably to open a case with support. But at least the problem can be detected quickly before logs are lost.

Leave a Reply

Your email address will not be published. Required fields are marked *