Public/Object/Address/Set-PanAddress.ps1
function Set-PanAddress { <# .SYNOPSIS Create or update PanAddress objects in the candidate configuration .DESCRIPTION Set-PanAddress will update an existing address object, or create new if none exists already. .NOTES Set-PanAddress cannot be used to rename objects. Use Rename- cmdlet Set-PanAddress cannot be used to move object locations. Use Move- cmdlet Cmdlet accepts two different pipeline inputs offering flexibility PanDevice[] pipeline input Pipe output of Get-PanDevice and operate on a single address object at a time PanAddress[] pipeline input Pipe output of Get-PanAddress (or other) and operate on one or more address objects at a time .INPUTS PanDevice[] You can pipe a PanDevice to this cmdlet PanAddress[] You can pipe a PanAddress to this cmdlet .OUTPUTS PanAddress .EXAMPLE PS> Get-PanDevice "192.168.250.250" | Set-PanAddress -Name "H-1.1.1.1" -Value "1.1.1.1" Creates an ip-netmask (default) address object with name "H-1.1.1.1" and value "1.1.1.1". If address object with specified name already exists, the value is updated to "1.1.1.1". If address object with specified name already exists and the value is incompatible with the type, an error will be generated. .EXAMPLE PS> Get-PanDevice "192.168.250.250" | Set-PanAddress -Name "FQDN-raw.githubusercontent.com" -Value "raw.githubusercontent.com" -Type Fqdn Creates a 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. .EXAMPLE PS> Get-PanDevice "192.168.250.250" | Set-PanAddress -Name "H-1.1.1.1" -Description "Updated description for H-1.1.1.1 address object!" Updates just the description property of an already existing address object named "H-1.1.1.1". If there is no existing address object named "H-1.1.1.1" an error will be generated. New address objects require a value. .EXAMPLE PS> Get-PanDevice "192.168.250.250" | Get-PanAddress "H-" | Set-PanAddress -Description "Updated description for all address objects with H-". Set-PanAddress accepts either PanDevice or PanAddress via pipeline for easier mid-pipeline filtering. .EXAMPLE PS> Get-PanDevice "192.168.250.250" | Get-PanAddress -Filter "H-" | Where-Object {$_.Name -match "^H-192\."} | Set-PanAddress -Description "Updated description for all address STARTING with H-192." Get-PanAddress -Filter parameter applies filter REMOTELY (via API) and reduces the number of objects processed by the PAN-OS API. Where-Object applies filtering capabilities LOCALLY and provides far more advanced filtering capabilities. Consider using both, simultaneously if needed, to optimize flexilibility and speed. .EXAMPLE PS> Get-PanDevice "192.168.250.250","192.168.250.251" | Set-PanAddress -Name "H-1.1.1.1" -Tag "Sanctioned","MyCorp" Overwrite tag configuration on address object "H-1.1.1.1" to have only "Sanctioned" and "MyCorp" tags on 192.168.250.250 and 192.168.250.251 devices. Previous tags will be overwritten. .EXAMPLE PS> Get-PanDevice "192.168.250.250","192.168.250.251" | Get-PanAddress | Set-PanAddress -Tag "" -Description "" Removes all tags and all descriptions from all address objects on 192.168.250.250 and 192.168.250.251 devices.. Passing an empty string "" to both -Tag and -Description parameters will explicitly remove Tag(s) and Descriptions from the address object(s). .EXAMPLE PS> Get-PanDevice "192.168.250.250" | Get-PanAddress | % { $_.Tag.Add("in") | Out-Null; $_ | Set-PanAddress } PS> foreach( $AddrCur in (Get-PanDevice "192.168.250.250" | Get-PanAddress)) { $AddrCur.Tag.Add("in") | Out-Null; $AddrCur | Set-PanAddress } Add a single tag to all address objects using either foreach-object (%) or standard foreach. Both are equivalent. The Out-Null is to eat the Boolean value returned by Add() method and keep the output clean. In event the tag is already on the object, the PAN-OS API will return an error, but processing continues for subsequent address objects. .EXAMPLE PS> Get-PanDevice "192.168.250.250" | Get-PanAddress | % { $_.Tag.Remove("in") | Out-Null; $_ | Set-PanAddress } PS> foreach( $AddrCur in (Get-PanDevice "192.168.250.250" | Get-PanAddress)) { $AddrCur.Tag.Remove("in") | Out-Null; $AddrCur | Set-PanAddress } Remove a single tag from all address objects using either foreach-object (%) or standard foreach. Both are equivalent. The Out-Null is to eat the Boolean value returned by Remove() method and keep the output clean. In event the tag is not already on the object, the PAN-OS API will return an error, but processing continues for subsequent address objects. #> [CmdletBinding(SupportsShouldProcess,ConfirmImpact='High')] param( [parameter( Mandatory=$true, ValueFromPipeline=$true, ParameterSetName='Device', HelpMessage='PanDevice against which object will be created or updated')] [PanDevice[]] $Device, [parameter( Mandatory=$true, ValueFromPipeline=$true, ParameterSetName='Object', HelpMessage='PanAddress object to be updated')] [PanAddress[]] $Address, # $Name parameter only available in "Device" ParameterSetName, *not* in "Object" ParameterSetName. To rename the object, use a Rename- cmdlet [parameter( Mandatory=$true, Position=0, ParameterSetName='Device', HelpMessage='Address object name')] [String] $Name, # $Value parameter available in "Device" and "Object" ParameterSetName. Not mandatory, unless creating an object -- such a check will occur later in code. # Only a positional parameter in "Device" [parameter( Position=1, ParameterSetName='Device', HelpMessage='Address object value e.g. "10.1.1.1/32" , "server.acme.com"')] [parameter( ParameterSetName='Object', HelpMessage='Address object value e.g. "10.1.1.1/32" , "server.acme.com"')] [String] $Value, [parameter( ParameterSetName='Device', HelpMessage='IpNetmask, IpRange, IpWildcardMask, Fqdn')] [parameter( ParameterSetName='Object', HelpMessage='IpNetmask, IpRange, IpWildcardMask, Fqdn')] [PanAddressType] $Type = [PanAddressType]::IpNetmask, [parameter( ParameterSetName='Device', HelpMessage='Address object description')] [parameter( ParameterSetName='Object', HelpMessage='Address object description')] [String] $Description = $null, [parameter( ParameterSetName='Device', HelpMessage='PAN-OS tag(s) to be added to address object, tags must already exist')] [parameter( ParameterSetName='Object', HelpMessage='PAN-OS tag(s) to be added to address object, tags must already exist')] [System.Collections.Generic.List[String]] $Tag = [System.Collections.Generic.List[String]]@(), [parameter( ParameterSetName='Device', HelpMessage='Device location')] [String] $Location = $null ) Begin { # Propagate -Debug and -Verbose to this module function, https://tinyurl.com/y5dcbb34 if($PSBoundParameters.Debug) { $DebugPreference = 'Continue' } if($PSBoundParameters.Verbose) { $VerbosePreference = 'Continue' } # Announce Write-Debug ($MyInvocation.MyCommand.Name + ':') } # Two rather different ParameterSets require different iteration logic Process { # Device ParameterSet, when PanDevice is present from call or from pipeline if($PSCmdlet.ParameterSetName -eq 'Device') { Write-Debug $($MyInvocation.MyCommand.Name + ': Device ParameterSetName') foreach($DeviceCur in $PSBoundParameters.Device) { Write-Debug $($MyInvocation.MyCommand.Name + ': Device: ' + $DeviceCur.Name) # Determine if there is a current object with this exact Name. If so, update only properties specified by caller $PanObject = Get-PanAddress -Device $DeviceCur -Filter $PSBoundParameters.Name | Where-Object {$_.Name -ceq $PSBoundParameters.Name} if($PanObject) { Write-Debug $($MyInvocation.MyCommand.Name + ': Object "' + $PSBoundParameters.Name + '" found, updating') # Update object properties only for those arguments specified. Parameters with default values (like Type in this function) do NOT populate PSBoundParameters if($PSBoundParameters.Value) { $PanObject.Value = $PSBoundParameters.Value } if($PSBoundParameters.Type) { $PanObject.Type = $PSBoundParameters.Type } if($PSBoundParameters.Description.Count) { $PanObject.Description = $PSBoundParameters.Description } if($PSBoundParameters.Tag.Capacity) { $PanObject.Tag = $PSBoundParameters.Tag } if($PSBoundParameters.Location) { Write-Warning $($MyInvocation.MyCommand.Name + ': Ignoring location parameter "' + $PSBoundParameters.Location + '" for existing object "' + $PanObject.Name + '" on device "' + $DeviceCur.Name + '" To move, use Move- cmdlet.') } } # No object with the exact Name. Create one else { Write-Debug $($MyInvocation.MyCommand.Name + ': Object "' + $PSBoundParameters.Name + '" not found, creating') # Verify a Value has been specified to continue creating object. if([String]::IsNullOrEmpty($PSBoundParameters.Value)) { Write-Error $($MyInvocation.MyCommand.Name + ': Unable to create an object without a Value') # Break current loop iteration, continue to next Device continue } # Create a minimum viable object. Then update only the properties specified by caller $PanObject = New-PanAddress -Name $PSBoundParameters.Name -Value $PSBoundParameters.Value -Device $DeviceCur if($PSBoundParameters.Type) { $PanObject.Type = $PSBoundParameters.Type } if($PSBoundParameters.Description.Count) { $PanObject.Description = $PSBoundParameters.Description } if($PSBoundParameters.Tag.Capacity) { $PanObject.Tag = $PSBoundParameters.Tag } if($PSBoundParameters.Location) { $PanObject.Location = $PSBoundParameters.Location } else { $PanObject.Location = 'local/' + $PSBoundParameters.Device.VsysDefault } } if($PSCmdlet.ShouldProcess($PanObject.Device.Name,'Create/Update ' + $PanObject.Name)) { # Call to helper which returns a PanResponse $PanResponse = Set-PanAddressHelper -Address $PanObject # When successful send object to pipeline as confirmation. Failures will have errors written if($PanResponse.Status -eq 'success') { $PanObject } else { Write-Error $($MyInvocation.MyCommand.Name + ': Device: ' + $DeviceCur.Name + ' Object: ' + $PanObject.Name + ' Message: ' + $PanResponse.Message) } } } # end foreach } # end ParameterSetName Device # Object ParameterSet, when PanAddress is specified from call or pipeline elseif($PSCmdlet.ParameterSetName -eq 'Object') { Write-Debug $($MyInvocation.MyCommand.Name + ': Object ParameterSetName') foreach($AddressCur in $PSBoundParameters.Address) { # AddressCur tracks the current passed-by-reference address # AddressCurClone is a clone used to merge in additional requested changes from other parameters. Don't want to change original Address object passed-by-reference Write-Debug $($MyInvocation.MyCommand.Name + ': Object: ' + $AddressCur.Name) # Update object properties only for those arguments specified. Parameters with default values (like Type in this function) do NOT populate PSBoundParameters $AddressCurClone = $AddressCur.Clone() if($PSBoundParameters.Value) { $AddressCurClone.Value = $PSBoundParameters.Value } if($PSBoundParameters.Type) { $AddressCurClone.Type = $PSBoundParameters.Type } if($PSBoundParameters.Description.Count) { $AddressCurClone.Description = $PSBoundParameters.Description } if($PSBoundParameters.Tag.Capacity) { $AddressCurClone.Tag = $PSBoundParameters.Tag } # Location paramater not possible within Object ParameterSet based on Parameter() block definitions. To move objects, use Move- cmdlet if($PSCmdlet.ShouldProcess($AddressCurClone.Device.Name,'Create/Update ' + $AddressCurClone.Name)) { # Call to helper which returns a PanResponse $PanResponse = Set-PanAddressHelper -Address $AddressCurClone # When successful send object to pipeline as confirmation. Failures will have errors written if($PanResponse.Status -eq 'success') { $AddressCurClone } else { Write-Error $($MyInvocation.MyCommand.Name + ': Device: ' + $DeviceCur.Name + ' Object: ' + $AddressCurClone.Name + ' Message: ' + $PanResponse.Message) } } } # end foreach } # end ParameterSetName Object } End { } } # Function |