It took me a long time to get the clue, how to do an export of our Prisma Access, Service Connection and Global Protect configuration into JSON Backup files. If someone need to do this as well, here my PowerShell Script I have created as a base. You need to adjust the relevant areas (API URLs) depending of your Prisma Access configurations.
# SCM API credentials (replace placeholders with actual values)
$clientId = "YOUR CLIENT ID" # Replace with CLIENT ID
$clientSecret = "YOUR CLIENT SECRET" # Replace with CLIENT SECRET
$tsgId = "YOUR TSG ID" # Replace with Tenant Services Group ID
$tokenEndpoint = "https://auth.apps.paloaltonetworks.com/auth/v1/oauth2/access_token"
# General Script variables
$outputDirectory = "C:\Temp\PAN-SCM-Output\$(Get-Date -Format 'ddMMyyyy')" # Define the output directory
# Create output directory if it doesn't exist
If (-not (Test-Path $outputDirectory)) {
New-Item -ItemType Directory -Path $outputDirectory | Out-Null
Write-Host "Output directory created: $outputDirectory"
}
# Construct the request body for token
$body = @{
grant_type = "client_credentials"
scope = "tsg_id:$tsgId"
}
# Construct the authentication header for token
$encodedCredentials = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("${clientId}:${clientSecret}"))
$authHeader = @{
"Authorization" = "Basic $encodedCredentials"
"Content-Type" = "application/x-www-form-urlencoded"
}
# Make the API call to get access token
try {
$response = Invoke-RestMethod -Uri $tokenEndpoint -Method Post -Headers $authHeader -Body $body -ContentType "application/x-www-form-urlencoded"
$accessToken = $response.access_token
Write-Host "Bearer Token generated successfully."
} catch {
Write-Error "Error getting access token: $($_.Exception.Message)"
Exit 1 # Exit script if token cannot be obtained
}
# API URLs from https://pan.dev/access/api/prisma-access-config/
# Define the list of API URLs
# Add or remove API URLs depend on your Prisma Access environment
$apiUrls = @(
"https://api.sase.paloaltonetworks.com/sse/config/v1/address-groups?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/addresses?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/anti-spyware-profiles?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/application-filters?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/application-groups?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/app-override-rules?position=pre&folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/authentication-profiles?folder=Mobile%20Users",
"https://api.sase.paloaltonetworks.com/sse/config/v1/certificate-profiles?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/certificates?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/certificates?folder=Mobile%20Users",
"https://api.sase.paloaltonetworks.com/sse/config/v1/config-versions",
"https://api.sase.paloaltonetworks.com/sse/config/v1/dns-security-profiles?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/decryption-exclusions?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/decryption-profiles?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/decryption-rules?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/external-dynamic-lists?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/file-blocking-profiles?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/hip-objects?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/hip-profiles?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/http-header-profiles?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/ike-crypto-profiles?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/ipsec-crypto-profiles?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/shared-infrastructure-settings",
"https://api.sase.paloaltonetworks.com/sse/config/v1/internal-dns-servers?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/mobile-agent/agent-profiles?folder=Mobile%20Users",
"https://api.sase.paloaltonetworks.com/sse/config/v1/mobile-agent/agent-versions",
"https://api.sase.paloaltonetworks.com/sse/config/v1/mobile-agent/authentication-settings?folder=Mobile%20Users",
"https://api.sase.paloaltonetworks.com/sse/config/v1/mobile-agent/global-settings",
"https://api.sase.paloaltonetworks.com/sse/config/v1/mobile-agent/infrastructure-settings?folder=Mobile%20Users",
"https://api.sase.paloaltonetworks.com/sse/config/v1/mobile-agent/locations?folder=Mobile%20Users",
"https://api.sase.paloaltonetworks.com/sse/config/v1/mobile-agent/tunnel-profiles?folder=Mobile%20Users",
"https://api.sase.paloaltonetworks.com/sse/config/v1/profile-groups?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/security-rules?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/service-connections?folder=Service%20Connections",
"https://api.sase.paloaltonetworks.com/sse/config/v1/bgp-routing?position=pre&folder=Service%20Connections",
"https://api.sase.paloaltonetworks.com/sse/config/v1/services?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/tags?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/trusted-certificate-authorities?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/url-access-profiles?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/url-categories?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/vulnerability-protection-profiles?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/vulnerability-protection-signatures?folder=Shared",
"https://api.sase.paloaltonetworks.com/sse/config/v1/wildfire-anti-virus-profiles?folder=Shared"
)
# Headers for subsequent API calls
$Headers = @{
"Authorization" = "Bearer $AccessToken"
"Accept" = "application/json"
}
# Loop through each API URL
foreach ($apiUrl in $apiUrls) {
try {
Write-Host "Fetching data from: $apiUrl"
# Make the API call to retrieve data
$apiData = Invoke-RestMethod -Uri $apiUrl -Method Get -Headers $Headers
# Extract a meaningful name for the file from the URL
$uri = New-Object System.Uri($apiUrl)
$pathSegments = $uri.Segments | Where-Object { $_ -ne "/" }
$fileNameBase = ($pathSegments[-1] -replace '\?.*$', '').Trim('/') # Get the last segment and remove query string
# Determine prefix based on folder parameter
$prefix = ""
if ($apiUrl -like "*folder=Shared*") {
$prefix = "PrismaAccess_"
} elseif ($apiUrl -like "*folder=Mobile%20Users*") {
$prefix = "GlobalProtect_"
} elseif ($apiUrl -like "*folder=Service%20Connections*") {
$prefix = "ServiceConnection_"
} elseif ($apiUrl -like "*/config-versions*") {
$prefix = "PrismaAccess_"
} elseif ($apiUrl -like "*/mobile-agent/agent-versions*") {
$prefix = "GlobalProtect_"
} elseif ($apiUrl -like "*/mobile-agent/global-settings*") {
$prefix = "GlobalProtect_"
} elseif ($apiUrl -like "*/shared-infrastructure-settings*") {
$prefix = "PrismaAccess_"
}
# Handle special cases or generic fallbacks if needed
if ([string]::IsNullOrEmpty($fileNameBase)) {
$fileNameBase = "data" # Fallback if no specific name can be extracted
}
# Construct the output file path with prefix
$outputFileName = "PAN_SCM_${prefix}${fileNameBase}_$(Get-Date -Format 'ddMMyyyy').json"
$outputFilePath = Join-Path -Path $outputDirectory -ChildPath $outputFileName
# Convert data to JSON and save to file
$apiData | ConvertTo-Json -Depth 10 | Out-File $outputFilePath -Encoding UTF8
Write-Host "Data from '$apiUrl' successfully saved to: $outputFilePath" -ForegroundColor Green
} catch {
Write-Host "Error retrieving data from '$apiUrl': $($_.Exception.Message)" -BackgroundColor Red
if ($_.Exception.Response) {
Write-Host "Status Code: $($_.Exception.Response.StatusCode)" -BackgroundColor Red
}
}
}
Write-Host "Script execution completed."