- Access exclusive content
- Connect with peers
- Share your expertise
- Find support resources
08-07-2026 03:31 AM
Client & Partner Implementation Guide — Windows PowerShell Workflow
This guide provides a practical end-to-end procedure for generating an on-demand Best Practice Assessment (BPA) from a Palo Alto Networks firewall configuration using the Strata Cloud Manager Posture API.
Current workflow
The legacy manual On-Demand BPA dashboard was scheduled for deprecation on April 30, 2026. The Posture API is the current programmatic path for uploading NGFW/Panorama configuration files and retrieving machine-readable BPA results.
Version: 1.0
Published: August 2026
Audience: Customers, partners, presales, and security engineering teams
This document is implementation guidance. Palo Alto Networks UI labels and APIs can evolve; verify against current official documentation before production automation.
| Item | Details |
|---|---|
| Document | Palo Alto Networks NGFW BPA via Posture API |
| Scope | On-demand BPA from firewall XML configuration |
| Platform | Strata Cloud Manager Posture API |
| Shell | Windows PowerShell + curl.exe |
| Sensitive inputs | Client Secret, OAuth token, signed upload URL, firewall XML configuration |
Palo Alto Networks has moved the on-demand BPA workflow toward the Strata Cloud Manager Posture API. The API accepts a configuration file from an NGFW or Panorama, processes it against Palo Alto Networks best-practice checks, and provides the assessment as structured JSON for downstream review or automation.
Deprecation context
A Palo Alto Networks LIVEcommunity discussion captured the platform notice stating that the On-Demand BPA dashboard would be deprecated on April 30, 2026 and that customers should transition to the new Posture API. The Posture API documentation identifies the on-demand Best Practice report API as an available module.
This guide focuses on a standalone NGFW export and a Windows PowerShell workflow. The same general API pattern can also be used with Panorama configuration files when the request metadata and configuration file are appropriate.
The workflow is:
COMPLETED or FAILED.Important — API concurrency limit
The config-upload endpoint can return HTTP
429when the maximum number of active jobs is reached. Current Palo Alto Networks API documentation states a limit of five active jobs.
Before starting, make sure you have:
curl.exe.auth.apps.paloaltonetworks.comapi.strata.paloaltonetworks.comSecurity — Configuration sensitivity
A firewall configuration can reveal policy structure, addresses, objects, user information, certificates/keys metadata, and internal architecture. Treat the XML file and BPA output as confidential security data.
Open the Palo Alto Networks Hub:
https://apps.paloaltonetworks.com/hub
From the Hub / Activation Console, navigate to:
Common Services > Identity & Access
Select the tenant/TSG against which the API call will run.
Create a clearly named service account dedicated to BPA/API usage.
Use a name that allows the account owner and purpose to be identified during audits.
Record the following values:
Palo Alto Networks documentation warns that the Client Secret cannot be retrieved again after creation. If it is lost, reset or rotate the service account credentials.
Security — Credential handling
Store the Client Secret in an approved password/secret manager. Never place a real Client Secret, bearer token, or signed upload/download URL in client documentation, tickets, email, chat, or LIVEcommunity posts.
For the broad-access setup described in this workflow, assign:
Superuser provides unrestricted access. Use the minimum privileges appropriate for your environment whenever possible.
On the firewall GUI, navigate to:
Device > Setup > Operations
Under Configuration Management:
Still under:
Device > Setup > Operations
Palo Alto Networks exports the configuration as XML.
Before opening PowerShell, record the values that will be used in the BPA request body:
Use values that match the device whose XML configuration is being uploaded.
Important — PowerShell syntax
The commands below are provided inside fenced code blocks so that underscores, dollar signs, URLs, backticks, and other PowerShell characters remain unchanged when copied.
Copy the entire command or block exactly as shown. When a command uses a PowerShell continuation backtick (`
``), the backtick must be the final character on that line.
Replace the placeholder values with the credentials from the Palo Alto Networks service account.
$tokenResponse = Invoke-RestMethod -Method Post `
-Uri "https://auth.apps.paloaltonetworks.com/oauth2/access_token" `
-ContentType "application/x-www-form-urlencoded" `
-Body @{
grant_type = "client_credentials"
client_id = "PASTE_YOUR_CLIENT_ID"
client_secret = "PASTE_YOUR_CLIENT_SECRET"
scope = "tsg_id:PASTE_YOUR_TSG_ID"
}
$token = $tokenResponse.access_token
$tokenResponse
The OAuth access token is stored in:
$token
Security
Do not post the real value of
$tokenResponse,$token, your Client ID, or your Client Secret publicly.
Replace the placeholder values with the actual firewall and requester information.
$headers = @{
Authorization = "Bearer $token"
Accept = "application/json"
}
$body = @{
family = "FW_MODEL_FAMILY_E.g:400"
model = "MODEL_E.g:PA-450"
"requester-email" = "YOUR_EMAIL"
"requester-name" = "YOUR_NAME"
serial = "FW_SERIAL_NB"
version = "FW_VERSION"
} | ConvertTo-Json
Example values could look like:
family = "400"model = "PA-450"version = "12.1.7"Use the actual values for the firewall being assessed.
Run:
$bpa = Invoke-RestMethod -Method Post `
-Uri "https://api.strata.paloaltonetworks.com/posture/checks/v1/reports/config-file-upload" `
-Headers $headers `
-ContentType "application/json" `
-Body $body
$taskId = $bpa.task_id
$uploadUrl = $bpa.upload_url
$bpa
The response should contain:
The values are stored in:
$taskId
$uploadUrl
Keep the same PowerShell window/session open so these variables remain available.
Set $src to the actual location of the exported firewall XML file.
$src="C:\Users\YourUser\Downloads\FirewallConfig.xml"
Validate the path:
Test-Path $src
True
Do not continue until Test-Path returns True.
Run:
curl.exe -v `
-X PUT "$uploadUrl" `
-H "Content-Type: text/plain" `
-H "Content-Encoding: gzip" `
--data-binary "@$src"
Run:
curl.exe -v `
-X GET "https://api.strata.paloaltonetworks.com/posture/checks/v1/reports/$taskId/bpa-result" `
-H "Authorization: Bearer $token" `
-H "Accept: application/json"
The documented task states include:
QUEUEDIN_PROGRESSCOMPLETEDFAILEDContinue to the download step only after the BPA status is:
COMPLETED
Run:
$response = Invoke-RestMethod -Uri "https://api.strata.paloaltonetworks.com/posture/checks/v1/reports/$taskId/bpa-result" -Headers @{ "Accept"="application/json"; "Authorization"="Bearer $token" }
To inspect the returned object:
$response | ConvertTo-Json -Depth 20
If the download property is empty
First confirm that the task status is
COMPLETED. API response schemas can evolve, so the returned payload should be treated as the source of truth.
Run:
$downloadUrl = $response.result.custom_check_url
Confirm that the variable contains a URL:
$downloadUrl
It should return an HTTPS URL rather than a blank value.
To download the report into the current PowerShell directory:
Invoke-WebRequest -Uri $downloadUrl -OutFile "BPA_Report_$($taskId).json"
To download the report directly into the current user's Downloads folder:
$rawJsonPath = Join-Path $HOME "Downloads\BPA_Report_$($taskId).json"; Invoke-WebRequest -Uri $downloadUrl -OutFile $rawJsonPath; Write-Host "BPA report downloaded to: $rawJsonPath"
The following single PowerShell command downloads the returned JSON, parses it, formats it with indentation, and saves it under the user's Downloads folder:
$downloadPath = Join-Path $HOME "Downloads\BPA_Report_$($taskId).json"; $reportContent = Invoke-RestMethod -Uri $downloadUrl; $reportContent | ConvertTo-Json -Depth 100 | Set-Content -Path $downloadPath -Encoding UTF8; Write-Host "Report downloaded and formatted at: $downloadPath"
The generated file will look similar to:
C:\Users\<username>\Downloads\BPA_Report_<task-id>.json
The following PowerShell command flattens the nested best-practice warning/check structure into rows that can be filtered more easily in Excel.
It also sanitizes the device hostname before using it in the Windows filename.
Run this after
$reportContenthas been populated in Step 7.4.
$deviceName=[string]$reportContent.information.device_hostname; if([string]::IsNullOrWhiteSpace($deviceName)){$deviceName="UnknownDevice"}; $safeDeviceName=$deviceName -replace '[<>:"/\\|?*]','_'; $csvPath=Join-Path $HOME "Downloads\BPA_$($safeDeviceName)_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"; $rows=foreach($section in $reportContent.best_practices.PSObject.Properties){if($null -eq $section.Value){continue}; foreach($configType in $section.Value.PSObject.Properties){if($null -eq $configType.Value){continue}; foreach($item in @($configType.Value)){if($null -eq $item -or $null -eq $item.warnings){continue}; foreach($check in @($item.warnings)){if($null -eq $check){continue}; $status=if($check.check_excluded -eq $true){"Excluded"}elseif($check.check_passed -eq $true){"Passed"}else{"Failed"}; $configName=if($item.configuration.name){[string]$item.configuration.name}elseif($item.configuration.location){[string]$item.configuration.location}else{[string]$configType.Name}; $failedFields=if($null -ne $check.failed_fields){$check.failed_fields | ConvertTo-Json -Depth 100 -Compress}else{""}; [pscustomobject][ordered]@{"Device Hostname"=$deviceName;"Device IP"=[string]$reportContent.information.device_ip_address;"PAN-OS Version"=[string]$reportContent.information.PanOS_version;"Section"=[string]$section.Name;"Configuration Type"=[string]$configType.Name;"Configuration Name"=$configName;"Location"=[string]$item.configuration.location;"Status"=$status;"Check ID"=$check.check_id;"Check Type"=[string]$check.check_type;"Check Name"=[string]$check.check_name;"Check Message"=[string]$check.check_message;"Failed Fields"=$failedFields;"Excluded"=if($check.check_excluded -eq $true){"Yes"}else{"No"};"Defined By"=[string]$check.defined_by;"UUID"=[string]$check.uuid}}}}}; $rows | Export-Csv -Path $csvPath -NoTypeInformation -Encoding UTF8; Write-Host "Readable CSV created at: $csvPath"; Invoke-Item $csvPath
The command:
best_practices sections.PassedFailedExcludedExample output filename:
BPA_LBCRPA-450_20260807_124500.csv
Schema dependency
The CSV conversion assumes the BPA JSON contains
informationandbest_practicesstructures consistent with the current report shape. If Palo Alto Networks changes the JSON schema, inspect the raw JSON and adjust the field paths.
JeanPaul Mansour | Systems Engineer
Crestan International
Community note
If you use this workflow in production, validate the returned API schema and endpoint behavior against the latest Palo Alto Networks documentation before incorporating it into automation.
Click Accept as Solution to acknowledge that the answer to your question has been provided.
The button appears next to the replies on topics you’ve started. The member who gave the solution and all future visitors to this topic will appreciate it!
These simple actions take just seconds of your time, but go a long way in showing appreciation for community members and the LIVEcommunity as a whole!
The LIVEcommunity thanks you for your participation!

