Public/Object/Set-PanAddress.ps1
function Set-PanAddress { <# .SYNOPSIS Create or update address objects in the device candidate configuration. .DESCRIPTION Create an address object in the device candidate configuration if the name does *not* exist. Update an address object in the device candidate configuration if the name already exists. .NOTES Two modes: -InputObject mode and -Device mode. :: InputObject Mode (-InputObject):: Take one or more objects "as is" and apply them to the candidate configuration to create or update using API action=edit (replace) The Device and Location (vsys, device-group) are gleaned from object's own Device and Location properties. Set the object properties as desired and pipe the object to the cmdlet. :: Device Mode (-Device):: Device mode is more nuanced. Used to create objects or update objects in candidate configuration. Device mode does not take an InputObject. Required parameters are -Device, -Location, and -Name. Remaining parameters are not required by the cmdlet, but may be required by the XML API depending on if the object already exists or not. This flexibility offers interactive power as not all values have to be specified all the time. :: Rename & Move :: Set- cannot be used to rename objects. Use Rename- cmdlet. Set- cannot be used to move object locations. Use Move- cmdlet. .INPUTS PanDevice[] You can pipe a PanDevice to this cmdlet PanAddress[] You can pipe a PanAddress to this cmdlet .OUTPUTS PanAddress .EXAMPLE Create new on NGFW $D = Get-PanDevice "fw.lab.local" Set-PanAddress -Device $D -Location "vsys1" -Name "H-1.1.1.1" -Value "1.1.1.1" -Type "ip-netmask" If H-1.1.1.1 already exists in MyDeviceGroup, the specified PowerShell parameters will replace their corresponding elements/attributes. .EXAMPLE Create new on Panorama $D = Get-PanDevice "panorama.lab.local" Set-PanAddress -Device $D -Location "MyDeviceGroup" -Name "H-1.1.1.1" -Value "1.1.1.1" -Type "ip-netmask" If H-1.1.1.1 already exists in MyDeviceGroup, the specified PowerShell parameters will replace their corresponding elements/attributes. .EXAMPLE Add a description to an object that already exists. $D = Get-PanDevice "fw.lab.local" Set-PanAddress -Device $D -Location "vsys1" -Name "H-1.1.1.1" -Description "Updated Description!" If the object did NOT exist already, the command would error remotely by the API (with details) as a -Type and -Value are required for new objects to be created. .EXAMPLE Update the object Description and Tag properties in the PowerShell session (tags must already exist in PAN-OS) and pipe. $D = Get-PanDevice "fw.lab.local" $A = Get-PanAddress -Device $D -Location "vsys1" -Name "H-1.1.1.1" $A.Description = "Updated Description!" $A.Tag = @('risky','review') $A | Set-PanAddress .EXAMPLE Removing a description and removing tags Assume H-1.1.1.1 has a description to be removed and tags to be removed $D = Get-PanDevice "fw.lab.local" $A = Get-PanAddress -Device $D -Location "vsys1" -Name "H-1.1.1.1" $A.Description = "" $A.Tag = @() $A | Set-PanAddress .EXAMPLE Create fqdn address object with name "FQDN-raw.githubusercontent.com" and value "raw.githubusercontent.com" If address object with specified name already exists, the value is updated to "raw.githubusercontent.com". If address object with specified name already exists and the value is incompatible with the type, an error will be generated by the API Get-PanDevice "fw.lab.local" | Set-PanAddress -Location "vsys1" -Type 'fqdn' -Name "FQDN-raw.githubusercontent.com" -Value "raw.githubusercontent.com" .EXAMPLE Adding a "DC-A" tag to all ip-netmask type objects starting with 10.16 on fw.lab.local Note: Newline after pipe character for ease of reading Get-PanDevice "fw.lab.local" | Get-PanAddress -Filter "10.16" | Where-Object {$_.Type -eq 'ip-netmask' -and $_.Value -match "^10\.16\."} | ForEach-Object {$_.Tag += "DC-A"; $_} | Set-PanAddress .EXAMPLE Remove the "review" tag from every address object on fw1.lab.local and fw2.lab.local Note: Newline after pipe character for ease of reading Get-PanDevice "fw1.lab.local","fw2.lab.local" | Get-PanAddress | Where-Object {"review" -in $_.Tag} | ForEach-Object {$_.Tag = $_.Tag | Where-Object {$_ -ne "review"}; $_} | Set-PanAddress -Replace Not quite a PowerShell "one-liner" as Foreach-Object ScriptBlock contains semi-colons, but close. Illustrates the capabilities of PowerPAN, but not wise to do it exactly this way. If doing something like this in production, use proper foreach() loops and a few more variables. The $_ nesting present in the ForEach-Object and nested Where-Object is error-prone if not careful. On large devices with many objects with the "review" tag, might take a while. #> [CmdletBinding()] param( [parameter(Mandatory=$true,ParameterSetName='Device',ValueFromPipeline=$true,HelpMessage='PanDevice against which address object(s) will be applied')] [PanDevice[]] $Device, [parameter(Mandatory=$true,ParameterSetName='Device',HelpMessage='Case-sensitive location: vsys1, shared, DeviceGroupA, etc.')] [String] $Location, [parameter(Mandatory=$true,ParameterSetName='Device',HelpMessage='Case-sensitive name of address object')] [String] $Name, [parameter(ParameterSetName='Device',HelpMessage='Type of the address object: ip-netmask, fqdn, ip-range, ip-wildcard')] [ValidateSet('ip-netmask','fqdn','ip-range','ip-wildcard')] [String] $Type, [parameter(ParameterSetName='Device',HelpMessage='Value of the address object')] [String] $Value, [parameter(ParameterSetName='Device',HelpMessage='Description')] [String] $Description, [parameter(ParameterSetName='Device',HelpMessage='One or more tags. Tags must exist already. Will not create tags')] [String[]] $Tag, [parameter(ParameterSetName='Device',HelpMessage='Disable ability to override (Panorama device-group objects only)')] [Bool] $DisableOverride, [parameter(Mandatory=$true,Position=0,ParameterSetName='InputObject',ValueFromPipeline=$true,HelpMessage='Input object(s) to be created/updated as is')] [PanAddress[]] $InputObject ) Begin { # Propagate -Verbose to this module function, https://tinyurl.com/y5dcbb34 if($PSBoundParameters.Verbose) { $VerbosePreference = 'Continue' } # Announce Write-Verbose ('{0}:' -f $MyInvocation.MyCommand.Name) } # Begin Block Process { # ParameterSetName InputObject if($PSCmdlet.ParameterSetName -eq 'InputObject') { foreach($InputObjectCur in $PSBoundParameters.InputObject) { Write-Verbose ('{0}: InputObject Device: {1} XPath: {2}' -f $MyInvocation.MyCommand.Name,$InputObjectCur.Device.Name,$InputObjectCur.XPath) # InputObject is always action=edit, requires overlap between XPath and Element (entry.OuterXml) Write-Verbose ('{0}: InputObject (-Edit)XML: {1}' -f $MyInvocation.MyCommand.Name,$InputObjectCur.XDoc.entry.OuterXml) $R = Invoke-PanXApi -Device $InputObjectCur.Device -Config -Edit -XPath $InputObjectCur.XPath -Element $InputObjectCur.XDoc.entry.OuterXml # Check PanResponse if($R.Status -eq 'success') { # Send the updated object back to the pipeline for further use or to display Get-PanAddress -InputObject $InputObjectCur } else { Write-Error ('Error applying InputObject {0} on {1}/{2} . Status: {3} Code: {4} Message: {5}' -f $InputObjectCur.Name,$InputObjectCur.Device.Name,$InputObjectCur.Location,$R.Status,$R.Code,$R.Message) } } # End foreach InputObjectCur } # End ParameterSetName InputObject # ParameterSetName Device elseif($PSCmdlet.ParameterSetName -eq 'Device') { foreach($DeviceCur in $PSBoundParameters.Device) { Write-Verbose ('{0}: Device: {1} Location: {2} Name: {3} ' -f $MyInvocation.MyCommand.Name,$DeviceCur.Name,$PSBoundParameters.Location,$PSBoundParameters.Name) # Update Location if past due if($PSBoundParameters.Device.LocationUpdated.AddSeconds($Global:PanDeviceLocRefSec) -lt (Get-Date)) { Update-PanDeviceLocation -Device $PSBoundParameters.Device } # If object already exists, use it. If object does not exist, create a minimimum viable object with a call to ::new($Device,$Location,$Name) $Obj = $null $Obj = Get-PanAddress -Device $DeviceCur -Location $PSBoundParameters.Location -Name $PSBoundParameters.Name if($Obj) { Write-Verbose ('{0}: Found {1} on Device: {2}/{3} at XPath: {4}' -f $MyInvocation.MyCommand.Name,$PSBoundParameters.Name,$DeviceCur.Name,$PSBoundParameters.Location,$Obj.XPath) } # Object does not exist, build it else { Write-Verbose ('{0}: Cannot find {1} on Device: {2}/{3}. Building' -f $MyInvocation.MyCommand.Name,$PSBoundParameters.Name,$DeviceCur.Name,$PSBoundParameters.Location) $Obj = [PanAddress]::new($DeviceCur,$PSBoundParameters.Location,$PSBoundParameters.Name) } # Modify properties directly letting Getter/Setter do heavy XML lifting # Device, Location, and Name do not apply if($PSBoundParameters.ContainsKey('Type')) { $Obj.Type = $PSBoundParameters.Type } if($PSBoundParameters.ContainsKey('Value')) { $Obj.Value = $PSBoundParameters.Value } if($PSBoundParameters.ContainsKey('Description')) { $Obj.Description = $PSBoundParameters.Description } if($PSBoundParameters.ContainsKey('Tag')) { $Obj.Tag = $PSBoundParameters.Tag } if($PSBoundParameters.ContainsKey('DisableOverride')) { $Obj.DisableOverride = $PSBoundParameters.DisableOverride } # Call API # -Replace action=edit, requires overlap between XPath and Element (entry.OuterXml) Write-Verbose ('{0}: Device (-Edit)XML: {1}' -f $MyInvocation.MyCommand.Name,$Obj.XDoc.entry.OuterXml) $R = Invoke-PanXApi -Device $DeviceCur -Config -Edit -XPath $Obj.XPath -Element $Obj.XDoc.entry.OuterXml # Check PanResponse if($R.Status -eq 'success') { # Send the updated object back to the pipeline for further use or to display Get-PanAddress -Device $DeviceCur -Location $PSBoundParameters.Location -Name $PSBoundParameters.Name } else { Write-Error ('Error applying {0} on {1}/{2} . Status: {3} Code: {4} Message: {5}' -f $PSBoundParameters.Name,$DeviceCur.Name,$PSBoundParameters.Location,$R.Status,$R.Code,$R.Message) } } # End foreach $DeviceCur } # End ParameterSetName Device } # Process block End { } # End block } # Function |