Duplicates and merging¶
Find duplicates¶
Objects are grouped by value, not name. h-web1, web-primary, and
h-web1-slash (all 10.0.0.10/32) land in one bucket; tcp-443 and
svc-https (both TCP/443) in another. Each row tells you the value and every
object name + location that defines it.
Strict by default¶
Address matching is strict: only byte-identical values are duplicates. A
host accidentally written with a subnet mask — web-server = 10.1.1.50/24 —
is not reported as a duplicate of the network internal = 10.1.1.0/24,
even though both mask down to the same /24. (10.0.0.10 and 10.0.0.10/32
are still the same host, so they group.)
Pass --not-strict for the looser, fringe behaviour that masks host bits and
collapses a host-with-mask onto its network:
--not-strict only widens what's listed — it grants no merge power. A pair it
surfaces (e.g. a host and its network) has different exact values, so
dedup merge still refuses it unless you pass
--allow-value-change. Treat --not-strict as a discovery aid, then decide
case by case whether the masked-equal objects really should be merged.
Merge two objects¶
dedup merge collapses one object (--remove) into another (--keep),
repointing every reference before deleting the loser:
By default this is a dry-run. You'll see the plan:
merge address 'web-primary'@shared -> 'h-web1'@shared
• address-group 'grp-web' @shared static: ['h-web1', 'web-primary'] -> ['h-web1']
• nat-rule 'nat-web' @shared pre source: ['web-primary'] -> ['h-web1']
• delete address 'web-primary' @shared
dry-run — re-run with --apply to execute
What gets rewritten¶
Every reference the reference graph knows about:
- static address-group membership,
- security rule
source/destination, - NAT rule
source/destination(translation fields are flagged for review), - every other rulebase's
source/destination/service/tag(PBF, decryption, authentication, QoS, application-override, DoS, SD-WAN, tunnel-inspect, network-packet-broker). A PBF next-hop object has no flat member list, so a merge that would strand it is blocked for manual review.
References are rewritten before the object is deleted, and duplicate members are collapsed (a group that listed both names ends up with just the survivor).
The safety gate¶
psc refuses (exit 6) a merge that would change meaning or that it can't
perform safely:
- Different values. Merging objects with different values changes what rules
match. Blocked unless you pass
--allow-value-change. - Invisible survivor. If the kept object isn't visible where a reference lives (e.g. it's in another device-group), the merge is blocked rather than creating a dangling reference.
$ psc -c panorama.xml -o json dedup merge --keep net-10 --remove local-only --remove-location DG-EDGE
{"error": "plan blocked (unsafe): value mismatch: ...", "type": "conflict", ...}
$ echo $?
6
Applying¶
fixed.xml is a complete, loadable config. The source export is untouched.
Locations¶
By default both objects are taken from --device-group (or shared). Override
per object with --keep-location / --remove-location.
Duplicate address-groups¶
dedup addresses/services finds duplicate objects; dedup groups finds
duplicate address-groups — two groups that resolve to the same effective
set of leaf addresses:
Groups are bucketed by the canonical set of hosts they expand to (nested groups are flattened first), so two groups land in the same bucket even if their names and direct members differ, as long as they ultimately reach the same addresses.
{
"kind": "address-group",
"value": "{ip-netmask:10.0.0.1/32, ip-netmask:10.0.0.2/32}",
"members": [
{"name": "grp-a", "location": "shared"},
{"name": "grp-b", "location": "shared"}
]
}
The audit is not exhaustive: dynamic (filter-based) groups are runtime-only,
and groups with dangling/malformed members can't be resolved — both are excluded
and counted on stderr (note audit is not exhaustive: skipped N dynamic and M
unresolvable group(s)). Scope the comparison with --location (default: the
global -d/--device-group if set, else compare across all locations).
Merge two address-groups¶
dedup merge-group collapses one group into another, reusing the same
repoint-before-delete engine as object merge:
psc -c panorama.xml dedup merge-group --keep grp-a --remove grp-b
psc -c panorama.xml dedup merge-group --keep grp-a --remove grp-b --apply --out fixed.xml
--keep(required): the survivor group.--remove(required): the group collapsed into--keepand deleted.--locationsets both;--keep-location/--remove-locationoverride per group (default: the global-d/--device-group, elseshared).- plus
--apply,--out,-of/--output-format.
Every referrer of --remove is repointed onto --keep before the dropped
group is deleted. Unlike object merge, there is no value-change override —
the merge is refused (exit 6) unless the two groups expand to the same
effective member set, because collapsing groups that mean different things would
silently change rule matching. It also blocks on a nested or cyclic pair
(one group already contains the other) and when the survivor isn't visible
where a reference lives.