Skip to content

Editing objects

The find/dedup/refs commands read and the merge/rename commands reshape the config. This guide covers the three commands that create, modify, and remove objects outright:

All three are dry-run by default and share the same write surface as the rest of psc: --apply executes, --out PATH writes a reviewable artifact, and -of/--output-format xml|set chooses what that artifact holds. See Writes and safety for the full contract.

Create or update an object

psc set writes a single object with PAN-OS-accurate validation, one subcommand per kind:

psc -c panorama.xml set address --name h-web1 --type ip-netmask --value 10.0.0.10/32
psc -c panorama.xml set address-group --name grp-web --member h-web1 --member h-web2
psc -c panorama.xml set address-group --name dag-prod --filter "'prod' and 'web'"
psc -c panorama.xml set service --name tcp-8443 --protocol tcp --dest-port 8443
psc -c panorama.xml set service-group --name svc-web --member tcp-443 --member tcp-8443
psc -c panorama.xml set tag --name prod --color color5 --comments "production"

Common flags on every subcommand: --name (required), --location (default: the global -d/--device-group, else shared), --apply, --out, -of/--output-format. Tags via --tag (repeatable) where the kind supports them.

Kind-specific flags:

Subcommand Required Notable
address --name, --type, --value --type is ip-netmask | ip-range | ip-wildcard | fqdn; --value stored verbatim; --description, --tag
address-group --name exactly one of --member (repeatable, static) or --filter (dynamic tag expression); --description, --tag
service --name, --protocol, --dest-port --protocol is tcp | udp; --dest-port required (PAN-OS mandates a destination port), --source-port optional; --description, --tag
service-group --name, --member --member repeatable (≥1); --tag
tag --name --color is color1..color42; --comments (a tag has no --description)

What gets validated

Validation mirrors what PAN-OS would reject, so the failure happens on your laptop instead of on commit. Validation errors exit 4 (validation):

  • Names must be ≤63 characters (≤127 for a tag) and start with an alphanumeric.
  • Descriptions ≤255 characters.
  • Address must carry exactly one value kind (one --type/--value).
  • Service needs a destination port (or a source port).
  • Tag color must be color1..color42.

Two failures are blockers (exit 6, conflict) rather than plain validation errors, because they would silently break references:

  • Cross-kind name collision — a name already used by a different kind at that location (e.g. setting an address named like an existing service-group).
  • In-place type/mode change on update — changing an address's value type, or flipping an address-group between static (--member) and dynamic (--filter), on an object that already exists. Delete and recreate instead.

Create vs update, live vs offline

set creates a new object or updates an existing one. Live --apply only creates — updating an existing object over the XML API is refused (config). To update, use offline --apply:

psc -c panorama.xml set address --name h-web1 --type ip-netmask --value 10.0.0.11/32 \
    --apply --out updated.xml

This keeps the risky operation (rewriting a live object) on a reviewable file rather than mutating the device candidate blind.

Bulk import from NDJSON

Every set subcommand also takes -f/--file <objs.ndjson> — a bulk import of many objects of that kind, as emitted by export:

psc -c target.xml set address -f addresses.ndjson               # dry-run plan
psc -c target.xml set address -f addresses.ndjson --apply --out merged.xml

The whole file is planned as one reviewable ChangeSet (the same per-object validation, aggregated); the singular flags are ignored, and one blocker refuses the whole file. See Comparing and porting configs.

Edit one rule-field member

psc rule edit-member adds or removes one member of one rule field, idempotently:

psc -c panorama.xml rule edit-member --rule allow-web --field source --add h-web1
psc -c panorama.xml rule edit-member --rule allow-web --field source --remove h-old
psc -c panorama.xml rule edit-member --rule allow-web --field service --add tcp-8443 --rulebase post
  • --rule (required): the rule name to edit.
  • --field (required): source | destination | service | application.
  • exactly one of --add / --remove.
  • --rulebase: pre | post (default pre).
  • --location: shared or a device-group (default: the global -d/--device-group, else shared).
  • plus --apply, --out, -of/--output-format.

Why removal renders delete-then-set

PAN-OS set … <field> [ member ] appends to the existing list rather than replacing it. So a removal can't be expressed as a single set: psc renders a delete of the whole field followed by a re-set of the remaining list. The upshot is that any edit is idempotent — re-running --add h-web1 when h-web1 is already present (or --remove when it's already absent) is a no-op that changes nothing.

Validation and limits

  • NAT service is scalar — a NAT rule's service is a single value, not a list, so member-editing it is blocked.
  • application only exists on security rules; --field application against a NAT/policy rule is a validation error.
  • An unknown rule exits 5 (not_found); an ambiguous rule (matching in more than one place) exits 4 (validation) — disambiguate with --rulebase/--location.

Edit group membership

psc group edit-member is the group counterpart of rule edit-member: it adds or removes one member of an existing address-group or service-group, idempotently. Use it to grow or shrink a group without re-sending its whole member list.

psc -c panorama.xml group edit-member --group web-pool --add web-srv-09
psc -c panorama.xml group edit-member --group web-pool --remove web-srv-02
psc -c panorama.xml group edit-member --group svc-web --add tcp-8443 --kind service-group
  • --group (required): the group name to edit.
  • exactly one of --add / --remove.
  • --kind: address-group | service-group — only needed to disambiguate a name that exists as both kinds.
  • --location: shared or a device-group (default: the global -d/--device-group, else shared).
  • plus --apply, --out, -of/--output-format.

Removal renders the same delete-of-field + re-set as a rule edit (PAN-OS set … static [ member ] appends), so every op is idempotent — adding a member already present, or removing one already absent, is a no-op.

Create vs. edit membership

group edit-member changes the membership of a group that already exists. To create a group, use set address-group/set service-group. set address-group --member … also replaces the whole member list in one shot — reach for group edit-member when you want a surgical, idempotent single-member change instead.

Validation and limits

  • A dynamic (filter-based) address-group has no static member list, so editing its members is a validation error (exit 4) — change its --filter with set address-group instead.
  • A group cannot contain itself — a self-referential --add is rejected.
  • An unknown group exits 5 (not_found); a name that is both an address- and service-group, or exists in several locations, exits 4 — disambiguate with --kind / --location.
  • Members aren't required to exist yet (PAN-OS permits forward references), same as rule edit-member.

In the workbench, select objects and press G to add them to a named group in one step — or press N to build a new group out of the selection. Because the workbench knows which objects you pointed at (not just their names), N can refuse a member the group's location cannot see, or one whose name is shadowed there. set address-group takes bare names and cannot make that check.

Decommission an address

psc decommission performs a reference-safe, ordered teardown of every address object that matches one or more IPs/CIDRs/ranges. It's the safe inverse of set: instead of hand-scrubbing groups and rules before deleting an object, you name the IP and let psc plan the cascade.

psc -c panorama.xml decommission 10.1.0.5
psc -c panorama.xml decommission 10.1.0.0/24 10.2.0.0/24
psc -c panorama.xml decommission --file retired-ips.txt
psc -c panorama.xml decommission 10.1.0.5 --scope DG-EDGE

Targets come from positional arguments, repeated --target, and/or a -f/--file list (one per line, # comments). --scope DG limits the object search to one device-group (plus inherited shared); the default is the global -d/--device-group, else everywhere.

The teardown order

The plan cascades to a fixpoint in this order:

  1. Scrub the matched objects from every address-group member list.
  2. Scrub them from every rule source/destination.
  3. Delete orphaned rules — a rule whose source or destination became empty (an any field survives; it was never narrowed by this object).
  4. Delete emptied groups — a group left with no members.
  5. Delete the objects themselves.

Because deleting an emptied group can orphan its referrers, the plan repeats until nothing more changes. Example dry-run plan:

decommission address objects
  ! orphan rule 'r-sole-source' @shared pre will be deleted (source/destination empty after decommission — verify no traffic depends on it)
  • address-group 'g-mixed' @shared static: ['h-dead', 'h-keep'] -> ['h-keep']
  • security-rule 'r-sole-source' @shared pre source: ['h-dead'] -> []
  • delete security-rule rule 'r-sole-source' @shared pre
  • delete address 'h-dead' @shared
  • delete address-group 'g-dead-only' @shared
dry-run — re-run with --apply to execute

Only exact and within matches are torn down

decommission removes only objects that equal the target or are inside it (an EXACT or WITHIN match). A broader object that merely contains the target is left in place — decommissioning 10.1.0.5 never deletes the supernet 10.1.0.0/24, because that network is still meaningful for other hosts.

A shadowed name is never scrubbed

An object in a device group hides a same-named object above it: a parent device group, or shared. A delete of the lower object does not break a reference to that name. The reference falls through to the object above.

decommission scrubs a name only when the name resolves to nothing after the plan applies. Take an address web in shared. Add a second web in dg-a. A group g@dg-a holds web, and a rule uses g as its source. A decommission of the dg-a value deletes that one address and stops. g keeps web, so g does not become empty and the rule keeps its source. The plan warns about the new meaning of the name:

decommission address objects
  ! address-group 'g'@dg-a static keeps the name 'web'; after this plan the name points to address 'web'@shared (10.0.0.1/32) — make sure that the referrer is still correct
  • delete address 'web' @dg-a

Read the warning and confirm that the referrer is still correct. To remove the name completely, decommission the surviving object that the warning names. The same rule applies to delete.

--keep-groups deletes nothing, so no name falls through in that mode. The scrub of the group and rule member fields always runs there.

Keep groups / keep rules

  • --keep-groups scrubs the matched objects from group and rule member fields but deletes neither the groups nor the objects — useful when you want to vacate the references but retain the now-empty shells.
  • --keep-rules keeps rules that would otherwise be deleted as orphans (empty source/destination), leaving them for manual review.

Blockers and warnings

  • Blockers (exit 6, refuse to apply): a matched object that a DAG filter tag selects (dynamic membership psc can't enumerate), or a matched object that a NAT translation field or a PBF forwarding next-hop names (neither is a flat member list psc can safely rewrite). The NAT and PBF blocker fires only when the name resolves to nothing after the plan applies. Resolve the reference by hand, then re-run.
  • Warnings (surfaced, don't block): every orphan-rule deletion is a warning — verify no traffic depends on the rule before you --apply. A kept name that falls through to a same-named object above is a warning too.

Applying

Like every write, decommission is dry-run until --apply, and offline --apply needs --out:

psc -c panorama.xml decommission 10.1.0.5 --apply --out torn-down.xml
psc -c panorama.xml decommission 10.1.0.5 --out torn-down.set -of set   # review the script first