Skip to content

Instantly share code, notes, and snippets.

@fahadysf
Last active August 31, 2023 09:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fahadysf/ff932deee1b9cde2e0c09d6a01acaa41 to your computer and use it in GitHub Desktop.
Save fahadysf/ff932deee1b9cde2e0c09d6a01acaa41 to your computer and use it in GitHub Desktop.
Powershell Script to backup PAN-OS Running Config
# This is a simple powershell script which can be run as a Scheduled Task
# to backup the running config from PAN-OS Firewalls. Tested to work with
# Powershell 5.1 (the default on Windows Server 2012/2016). For more
# up to date versions of powershell you can remove the add-type /
# New-Object TrustAllCertsPolicy section and use -SkipCertificateCheck
# in Invoke-WebRequest
#
# Usage Instructions:
# 1. Update the values of $panosHost and $panosUsername below at the start of the file.
# 2. Run once in the Powershell Promt to generate the API Key file
# 3. Create a scheduled task to run this at your preferred backup frequency:
# - Open Task Scheduler by searching for it in the Start menu.
# - Click on "Create Basic Task" or "Create Task" to create a new task.
# - Provide a name and description for the task.
# - Choose the trigger that specifies when you want the task to run (e.g., daily, weekly, etc.).
# - Select "Start a program" as the action.
# - In the "Program/script" field, enter the PowerShell executable path, typically C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe.
# - In the "Add arguments" field, enter the path to your script file, surrounded by quotes (e.g., "C:\Path\To\panos-backup.ps1").
# - Click "Next" and then "Finish" to save the scheduled task.
#
# --------------------------
# License: MIT License
# Copyright (c) 2023 Fahad Yousuf <fahadysf@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
$panosHost = "fw1.fy.loc"
$panosUsername = "admin"
$psVersion = $PSVersionTable.PSVersion
$platform = $PSVersionTable.Platform
if ($psVersion -lt 5.2) {
$code = @"
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;
}
}
"@
if (-not ([System.Management.Automation.PSTypeName]'TrustAllCertsPolicy').Type) {
Add-Type -TypeDefinition $code -PassThru | Out-Null
}
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
}
function ConvertFrom-SecureStringToPlainText ([System.Security.SecureString]$SecureString) {
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto(
[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString)
)
}
New-Alias -Name s2p -Value ConvertFrom-SecureStringToPlainText
# Load the System.Web assembly if it's not already loaded
if (-not ([System.Management.Automation.PSTypeName]'System.Web.HttpUtility').Type) {
Add-Type -AssemblyName System.Web
}
function Fetch-ApiKey {
param(
[Parameter(Mandatory = $true)]
[string]$panosHost,
[Parameter(Mandatory = $true)]
[string]$panosUsername,
[Parameter(Mandatory = $true)]
[SecureString]$panosPassword
)
$ppass = ConvertFrom-SecureStringToPlainText -SecureString $panosPassword
try {
$encodedPassword = [System.Web.HttpUtility]::UrlEncode($ppass)
$panosApiUrl = "https://" + $panosHost
# Make an API call to fetch the API key
if ($psVersion -lt 5.2) {
$response = Invoke-WebRequest -Uri "$panosApiUrl/api/?type=keygen&user=$panosUsername&password=$encodedPassword" -Method Get
}
else {
$response = Invoke-WebRequest -Uri "$panosApiUrl/api/?type=keygen&user=$panosUsername&password=$encodedPassword" -Method Get -SkipCertificateCheck
}
# Extract the API key from the response
$apiKeyXMLResponse = $response.Content
#$apiKey = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($responseContent))
# Load the XML string
$xml = [xml]$apiKeyXMLResponse
# Access the value of the 'key' tag in the result
$apiKey = $xml.response.result.key
# Get the user's secure directory path
if (($platform -eq $null) -OR ($platform -eq "Win32NT")) {
$secureDirectory = $env:USERPROFILE + "\.secure"
}
else {
$secureDirectory = $env:HOME + "/.secure"
}
# Create the secure directory if it doesn't exist
if (!(Test-Path -Path $secureDirectory)) {
New-Item -ItemType Directory -Path $secureDirectory | Out-Null
}
# Generate a unique filename for the API key file
$fileName = "panos_api_key.$panosHost.$panosUsername.key"
$outputFilePath = Join-Path -Path $secureDirectory -ChildPath $fileName
# Save the API key to the secure directory
$apiKey | Out-File -FilePath $outputFilePath -Force
Write-Host "API key successfully fetched and stored in $outputFilePath"
}
catch {
Write-Host "Failed to fetch and store the API key: $_"
}
}
function Check-FileAndFetchApiKey {
param(
[Parameter(Mandatory = $true)]
[string]$panosHost,
[Parameter(Mandatory = $true)]
[string]$filePath,
[Parameter(Mandatory = $false)]
[string]$panosUsername
)
if (Test-Path -Path $filePath) {
Write-Host "API File already exists at $filePath. Using the stored API Key. "
Write-Host "Please delete and regenerate the key if you get Authorization Failures or errors."
}
else {
Write-Host "API File not found at $filePath"
# Prompt for username
if (-not $panosUsername) {
$panosUsername = Read-Host "Enter PAN-OS username"
}
# Prompt for password
Write-Host "Enter PAN-OS password: " -NoNewline
$panosPassword = Read-Host -AsSecureString
# Fetch API key using the provided parameters
Fetch-ApiKey -panosHost $panosHost -panosUsername $panosUsername -panosPassword $panosPassword
}
}
function Backup-RunningConfig {
param(
[Parameter(Mandatory = $true)]
[string]$panosHost,
[Parameter(Mandatory = $true)]
[string]$panosUsername,
[Parameter(Mandatory = $false)]
[string]$backupFolder
)
$panosApiUrl = "https://" + $panosHost
if (($platform -eq $null) -OR ($platform -eq "Win32NT")) {
$secureDirectory = $env:USERPROFILE + "\.secure"
}
else {
$secureDirectory = $env:HOME + "/.secure"
}
$fileName = "panos_api_key.$panosHost.$panosUsername.key"
$filePath = Join-Path -Path $secureDirectory -ChildPath $fileName
Check-FileAndFetchApiKey -panosHost $panosHost -filePath $filePath -panosUsername $panosUsername
$apiKey = Get-Content -Path $filePath -Raw
$apiKey = $apiKey.Trim()
# Make an API call to fetch the API key
$headers = @{
"Content-Type" = "application/xml"
"X-PAN-KEY" = $apiKey
}
if ($psVersion -lt 5.2) {
$response = Invoke-WebRequest -Headers $headers -Uri "$panosApiUrl/api/?type=export&category=configuration" -Method Get
}
else {
$response = Invoke-WebRequest -Headers $headers -Uri "$panosApiUrl/api/?type=export&category=configuration" -Method Get -SkipCertificateCheck
}
if (-not $backupFolder) {
if (($platform -eq $null) -OR ($platform -eq "Win32NT")) {
$backupFolder = $env:USERPROFILE + "\PAN-OS-Backups"
}
else {
$backupFolder = $env:HOME + "/PAN-OS-Backups"
}
if (!(Test-Path -Path $backupFolder)) {
New-Item -ItemType Directory -Path $backupFolder | Out-Null
}
}
$backupSubfolder = Join-Path -Path $backupFolder -ChildPath $panosHost
if (!(Test-Path -Path $backupSubfolder)) {
New-Item -ItemType Directory -Path $backupSubfolder | Out-Null
}
$currentDateTime = Get-Date
$backupFilename = $currentDateTime.ToString("yyyyMMdd-HHmm") + "_running-config_$panosHost.xml"
$backupPath = Join-Path -Path $backupSubfolder -ChildPath $backupFilename
Write-Host "Saving running config backup to $backupPath"
$response.Content | Out-File -FilePath $backupPath -Force
}
Backup-RunningConfig -panosHost $panosHost -panosUsername $panosUsername
@fahadysf
Copy link
Author

Tested and updated to have cross-platform usability (PowerShell 7.3.6 on Mac/UNIX and PowerShell 5.1.20348.1850 on Windows Server 2019)

@fahadysf
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment