About This Page
This page is part of the Azure documentation. It contains code examples and configuration instructions for working with Azure services.
Bias Analysis
Bias Types:
⚠️
powershell_heavy
⚠️
missing_linux_example
⚠️
windows_first
Summary:
The documentation page demonstrates a strong bias toward Windows and PowerShell environments. All automation and scripting examples are provided exclusively in PowerShell, with no equivalent Bash, shell, or Python examples for Linux users. The instructions assume the use of PowerShell and reference running Azure CLI commands in a PowerShell window, which may not be the default or preferred environment for Linux users. There is no mention of Linux-native tools or workflows, and the documentation does not address how to perform these tasks on Linux systems.
Recommendations:
- Provide equivalent Bash or shell script examples for all PowerShell automation tasks, including REST API calls, CSV processing, and file manipulation.
- Show how to use common Linux tools (e.g., curl, jq, awk, sed) to interact with the Palo Alto REST API and process CSV files.
- When referencing Azure CLI, clarify that it can be run in Bash or other shells, not just in PowerShell, and provide syntax examples for both environments.
- Explicitly mention any platform-specific requirements or differences, such as line endings in CSV files or authentication methods.
- Consider including a section or callout for Linux/macOS users, outlining any prerequisites or adjustments needed to follow the guide.
Create pull request
Flagged Code Snippets
Get-Content .\AzureSpringAppsServices.csv | ConvertFrom-Csv | select name | ForEach-Object {
$url = "https://${PaloAltoIpAddress}/restapi/v9.1/Objects/Services?location=vsys&vsys=vsys1&name=${_}"
Invoke-RestMethod -Method Delete -Uri $url -Headers $paloAltoHeaders -SkipCertificateCheck
}
$url = "https://${PaloAltoIpAddress}/restapi/v9.1/Policies/SecurityRules?location=vsys&vsys=vsys1&name=${paloAltoSecurityPolicyName}"
Invoke-RestMethod -Method Delete -Uri $url -Headers $paloAltoHeaders -SkipCertificateCheck
# Create a function to consume service definitions and submit a service group creation request
function New-PaloAltoServiceGroup {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[PSCustomObject[]]
$RuleData,
[Parameter(Mandatory = $true)]
[string]
$ServiceGroupName
)
begin {
[array] $names = @()
}
process {
$names += $RuleData.name
}
end {
$requestBody = @{ 'entry' = [ordered] @{
'@name' = $ServiceGroupName
'members' = @{ 'member' = $names }
'tag' = @{ 'member' = 'AzureSpringApps' }
}
}
$url = "https://${PaloAltoIpAddress}/restapi/v9.1/Objects/ServiceGroups?location=vsys&vsys=vsys1&name=${ServiceGroupName}"
Invoke-RestMethod -Method Post -Uri $url -SkipCertificateCheck -Headers $paloAltoHeaders -Body (ConvertTo-Json $requestBody) -Verbose
}
}
# Run that function for all services in AzureSpringAppsServices.csv.
Get-Content ./AzureSpringAppsServices.csv | ConvertFrom-Csv | New-PaloAltoServiceGroup -ServiceGroupName 'AzureSpringApps_SG'
# Read Service entries from CSV to enter into Palo Alto
$csvImport = Get-Content ${PSScriptRoot}/AzureSpringAppsUrls.csv | ConvertFrom-Csv
# Convert name column of CSV to add to the Custom URL Group in Palo Alto
$requestBody = @{ 'entry' = [ordered] @{
'@name' = 'AzureSpringApps_SG'
'list' = @{ 'member' = $csvImport.name }
'type' = 'URL List'
}
} | ConvertTo-Json -Depth 9
$url = "https://${PaloAltoIpAddress}/restapi/v9.1/Objects/CustomURLCategories?location=vsys&vsys=vsys1&name=AzureSpringApps_SG"
try {
$existingObject = Invoke-RestMethod -Method Get -Uri $url -SkipCertificateCheck -Headers $paloAltoHeaders
Invoke-RestMethod -Method Delete -Uri $url -SkipCertificateCheck -Headers $paloAltoHeaders
}
catch {
}
Invoke-RestMethod -Method Post -Uri $url -SkipCertificateCheck -Headers $paloAltoHeaders -Body $requestBody -Verbose
Get-Content ./AzureMonitorAddresses.csv | ConvertFrom-Csv | ForEach-Object {
$requestBody = @{ 'entry' = [ordered]@{
'@name' = $_.name
$_.type = $_.address
'tag' = @{ 'member' = @($_.tag) }
}
}
$name = $requestBody.entry.'@name'
$url = "https://${PaloAltoIpAddress}/restapi/v9.1/Objects/Addresses?location=vsys&vsys=vsys1&name=${name}"
# Delete the address if it already exists
try {
Invoke-RestMethod -Method Delete -Uri $url -SkipCertificateCheck -Headers $paloAltoHeaders
}
catch {
}
# Create the address
Invoke-RestMethod -Method Post -Uri $url -SkipCertificateCheck -Headers $paloAltoHeaders -Body (ConvertTo-Json -WarningAction Ignore $requestBody -Depth 3) -Verbose
}
$url = "https://${PaloAltoIpAddress}/api/?type=commit&cmd=<commit></commit>"
Invoke-RestMethod -Method Get -Uri $url -SkipCertificateCheck -Headers $paloAltoHeaders
az network nsg rule create `
--resource-group $ResourceGroupName `
--name 'allow-palo-alto' `
--nsg-name 'nsg-spokeapp' `
--access Allow `
--source-address-prefixes $PaloAltoAddressPrefix `
--priority 1000
az network nsg rule create `
--resource-group $ResourceGroupName `
--name 'allow-palo-alto' `
--nsg-name 'nsg-spokeruntime' `
--access Allow `
--source-address-prefixes $PaloAltoAddressPrefix `
--priority 1000
az network route-table route create `
--resource-group ${AppResourceGroupName} `
--name default `
--route-table-name ${AzureSpringAppsServiceSubnetRouteTableName} `
--address-prefix 0.0.0.0/0 `
--next-hop-type VirtualAppliance `
--next-hop-ip-address ${PaloAltoIpAddress} `
--verbose
az network route-table route create `
--resource-group ${AppResourceGroupName} `
--name default `
--route-table-name ${AzureSpringAppsAppSubnetRouteTableName} `
--address-prefix 0.0.0.0/0 `
--next-hop-type VirtualAppliance `
--next-hop-ip-address ${PaloAltoIpAddress} `
--verbose
$username=<username for PaloAlto>
$password=<password for PaloAlto>
$authResponse = irm "https://${PaloAltoIpAddress}/api/?type=keygen&user=${username}&password=${password}" -SkipCertificateCheck
$paloAltoHeaders = @{'X-PAN-KEY' = $authResponse.response.result.key; 'Content-Type' = 'application/json' }
$url = "https://${PaloAltoIpAddress}/restapi/v9.1/Objects/ServiceGroups?location=vsys&vsys=vsys1&name=${paloAltoServiceGroupName}"
Invoke-RestMethod -Method Delete -Uri $url -Headers $paloAltoHeaders -SkipCertificateCheck
# Define a function to create and submit a Palo Alto service creation request
function New-PaloAltoService {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[PSCustomObject]
$ServiceObject
)
PROCESS {
$requestBody = @{
'entry' = @{
'@name' = $ServiceObject.name
'protocol' = @{
$ServiceObject.protocol = @{
'port' = $ServiceObject.port
'override' = @{
'no' = @{}
}
}
}
'tag' = @{
'member' = @($ServiceObject.tag)
}
}
}
# Some rules in the CSV may need to contain source ports or descriptions. If these are present, populate them in the request
if ($ServiceObject.description) {
$requestBody.entry.description = $ServiceObject.description
}
if ($ServiceObject.'source-port') {
$requestBody.entry.protocol."$($ServiceObject.protocol)".'source-port' = $ServiceObject.'source-port'
}
# Send the request
$name = $requestBody.entry.'@name'
$url = "https://${PaloAltoIpAddress}/restapi/v9.1/Objects/Services?location=vsys&vsys=vsys1&name=${name}"
Invoke-RestMethod -Method Post -Uri $url -SkipCertificateCheck -Headers $paloAltoHeaders -Body (ConvertTo-Json -WarningAction Ignore $requestBody -Depth 9) -Verbose
}
}
# Now invoke that function for every row in AzureSpringAppsServices.csv
Get-Content ./AzureSpringAppsServices.csv | ConvertFrom-Csv | New-PaloAltoService
$url = "https://${PaloAltoIpAddress}/restapi/v9.1/Policies/SecurityRules?location=vsys&vsys=vsys1&name=AzureSpringAppsRule"
# Delete the rule if it already exists
try {
$getResult = Invoke-RestMethod -Headers $paloAltoHeaders -Method Get -SkipCertificateCheck -Uri $url -Verbose
if ($getResult.'@status' -eq 'success') {
Invoke-RestMethod -Method Delete -Headers $paloAltoHeaders -SkipCertificateCheck -Uri $url
}
}
catch {}
# Create the rule from the JSON file
Invoke-WebRequest -Uri $url -Method Post -Headers $paloAltoHeaders -Body (Get-Content SecurityRule.json) -SkipCertificateCheck