- Products
- Learn
- Local User Groups
- Partners
- More
AI Security Masters E7:
How CPR Broke ChatGPT's Isolation and What It Means for You
Blueprint Architecture for Securing
The AI Factory & AI Data Center
Call For Papers
Your Expertise. Our Stage
Good, Better, Best:
Prioritizing Defenses Against Credential Abuse
Ink Dragon: A Major Nation-State Campaign
Watch HereCheckMates Go:
CheckMates Fest
Good day.
Is there a universal way to delete unused domain objects? I need to delete several hundred.
I just wrote a quick script to find unused domain objects. For now, it only tells you they are unused so you can delete them yourself, but it would be simple to make it delete them. The only thing you should need to do is set the value of cmaAddress on the first line if you are using an MDS. It should be the address of a CMA as shown in the output of 'mdsstat'.
cmaAddress=""
portNumber=$(api status | grep "APACHE Gaia Port" | awk '{print $NF}')
showAll() {
IFS=$(printf "\377")
sharedArguments=( --port "${portNumber}" -f json ${cmaAddress:+-d "${cmaAddress}"} -r true show "${1}" details-level full limit 500 )
if ! firstResult=$(mgmt_cli "${sharedArguments[@]}");then return 1;fi
toReturn="$(<<<"${firstResult}" jq -c '.objects[]|.')
";objectCount=$(<<<"${firstResult}" jq -c '.total')
if [ "${objectCount}" -lt 501 ];then echo -n "${toReturn}";return 0;fi
for offsetVal in $(seq 500 500 "${objectCount}" 2>/dev/null | tr "\n" "${IFS}");do
toReturn+="$(mgmt_cli "${sharedArguments[@]}" offset "${offsetVal}" \
| jq -c '.objects[]|.')
";done;echo -n "${toReturn}";}
allDomains="$(showAll dns-domains \
| jq -c '{uuid:.uid,name:.name}')"
echo "" && echo "Working in ${cmaAddress:+CMA }${cmaAddress:-SmartCenter}" && \
echo "${allDomains[@]}" | while read dnsDomain;do
printf "Domain: %s" "$(<<<"${dnsDomain}" jq '.name')"
if [ "0" == "$(mgmt_cli --port "${portNumber}" -f json ${cmaAddress:+-d "${cmaAddress}"} -r true \
where-used uid "$(<<<"${dnsDomain}" jq '.uuid')" \
| jq '."used-directly".total')" ];then
echo " is unused"
else
printf "\33[2K\r"
fi
done
It works by dumping a list of all of the domain objects in the management, then running 'where-used' for each of them. It shows the domain it's currently checking. If the domain is unused, it tells you. If it's used by something, it wipes the line and moves on to the next domain. Here's how the output looks on my lab SmartCenter:
[Expert@DallasSC]# echo "${allDomains[@]}"
{"uuid":"f7bb7e18-4bad-4330-8f2e-4236e6b47382","name":".github.com"}
{"uuid":"df0e50bc-9055-42fd-9d70-216dd7eb73b8","name":".test.com"}
{"uuid":"7eb334af-4088-4665-b26e-b4039f4b862e","name":".time.apple.com"}
{"uuid":"c5ee68ba-c77f-44ce-9907-8001689cbea9","name":".time.windows.com"}
{"uuid":"3ca51f4e-edec-4de3-ae4a-c83c84d0d928","name":".updates.windows.com"}
{"uuid":"c439cf97-4762-4ae7-a759-07c1651d4f2a","name":".www.github.com"}
[Expert@DallasSC]# echo "" && echo "Working in ${cmaAddress:+CMA $cmaAddress}${cmaAddress:-SmartCenter}" && \
> echo "${allDomains[@]}" | while read dnsDomain;do
> printf "Domain: %s" "$(<<<"${dnsDomain}" jq '.name')"
> if [ "0" == "$(mgmt_cli --port "${portNumber}" -f json ${cmaAddress:+-d "${cmaAddress}"} -r true \
> where-used uid "$(<<<"${dnsDomain}" jq '.uuid')" \
> | jq '."used-directly".total')" ];then
> echo " is unused"
> else
> printf "\33[2K\r"
> fi
> done
Working in SmartCenter
Domain: ".test.com" is unused
Edited to fix a dumb issue causing the CMA address to be printed twice.
You could use the Objects Explorer to show unused objects, filter on domain objects and delete them all.
Or use the "show-unused-objects" Management API endpoint, filter the output on object type, list and delete the relevant objects accordingly if you're in an automated environment.
The problem is that domains are not tracked by this functionality.
I am told it supposed to work for un-used objects; however, it is bugged. I think it is on the low priority list for fixes sadly. The response I have for it was back in January 2025.
It can be little finnicky...
Good question...let me do some tests in the lab in the morning and will update you.
Thanks.
Will wait.
Will let you know soon.
Just checked and it is there, in object explorer.
If you switch from "All" to "Unused Objects" in the top left, you will notice that Domains are not listed.
So, another approach might be to list their name/uid with an API call, and iterate that list against the "where-used" endpoint.
Those which aren't used can be saved in a list and another automation could delete them after some verifications.
Correct, but they are definitely listed there.
I see all my 3109 domains in Object Explorer but none of them in Unused Objects. And I defenetly know and also see that most of them are not in use.
Can you not delete them from there then? I know it would be way better if they show in unused objects. I will try do some more testing for this tomorrow in the lab.
I did some testing on LAB GW. Same result.
So you only see 1 unused, but you are saying there is way more than that?
I'm unable to show prodaction env. Screen from above was from test gw. And on them 0 unused dimain but I shown one.
Hi,
A little bit off, but Algosec can do it semaless 🙂
Akos
Never considered that.
Tufin as well, I guess.
I believe Firemon does similar as well.
I just wrote a quick script to find unused domain objects. For now, it only tells you they are unused so you can delete them yourself, but it would be simple to make it delete them. The only thing you should need to do is set the value of cmaAddress on the first line if you are using an MDS. It should be the address of a CMA as shown in the output of 'mdsstat'.
cmaAddress=""
portNumber=$(api status | grep "APACHE Gaia Port" | awk '{print $NF}')
showAll() {
IFS=$(printf "\377")
sharedArguments=( --port "${portNumber}" -f json ${cmaAddress:+-d "${cmaAddress}"} -r true show "${1}" details-level full limit 500 )
if ! firstResult=$(mgmt_cli "${sharedArguments[@]}");then return 1;fi
toReturn="$(<<<"${firstResult}" jq -c '.objects[]|.')
";objectCount=$(<<<"${firstResult}" jq -c '.total')
if [ "${objectCount}" -lt 501 ];then echo -n "${toReturn}";return 0;fi
for offsetVal in $(seq 500 500 "${objectCount}" 2>/dev/null | tr "\n" "${IFS}");do
toReturn+="$(mgmt_cli "${sharedArguments[@]}" offset "${offsetVal}" \
| jq -c '.objects[]|.')
";done;echo -n "${toReturn}";}
allDomains="$(showAll dns-domains \
| jq -c '{uuid:.uid,name:.name}')"
echo "" && echo "Working in ${cmaAddress:+CMA }${cmaAddress:-SmartCenter}" && \
echo "${allDomains[@]}" | while read dnsDomain;do
printf "Domain: %s" "$(<<<"${dnsDomain}" jq '.name')"
if [ "0" == "$(mgmt_cli --port "${portNumber}" -f json ${cmaAddress:+-d "${cmaAddress}"} -r true \
where-used uid "$(<<<"${dnsDomain}" jq '.uuid')" \
| jq '."used-directly".total')" ];then
echo " is unused"
else
printf "\33[2K\r"
fi
done
It works by dumping a list of all of the domain objects in the management, then running 'where-used' for each of them. It shows the domain it's currently checking. If the domain is unused, it tells you. If it's used by something, it wipes the line and moves on to the next domain. Here's how the output looks on my lab SmartCenter:
[Expert@DallasSC]# echo "${allDomains[@]}"
{"uuid":"f7bb7e18-4bad-4330-8f2e-4236e6b47382","name":".github.com"}
{"uuid":"df0e50bc-9055-42fd-9d70-216dd7eb73b8","name":".test.com"}
{"uuid":"7eb334af-4088-4665-b26e-b4039f4b862e","name":".time.apple.com"}
{"uuid":"c5ee68ba-c77f-44ce-9907-8001689cbea9","name":".time.windows.com"}
{"uuid":"3ca51f4e-edec-4de3-ae4a-c83c84d0d928","name":".updates.windows.com"}
{"uuid":"c439cf97-4762-4ae7-a759-07c1651d4f2a","name":".www.github.com"}
[Expert@DallasSC]# echo "" && echo "Working in ${cmaAddress:+CMA $cmaAddress}${cmaAddress:-SmartCenter}" && \
> echo "${allDomains[@]}" | while read dnsDomain;do
> printf "Domain: %s" "$(<<<"${dnsDomain}" jq '.name')"
> if [ "0" == "$(mgmt_cli --port "${portNumber}" -f json ${cmaAddress:+-d "${cmaAddress}"} -r true \
> where-used uid "$(<<<"${dnsDomain}" jq '.uuid')" \
> | jq '."used-directly".total')" ];then
> echo " is unused"
> else
> printf "\33[2K\r"
> fi
> done
Working in SmartCenter
Domain: ".test.com" is unused
Edited to fix a dumb issue causing the CMA address to be printed twice.
That worked great for me, thanks!
Tested in my lab as well, great!
Nice. Could be extended to loop over all CMA and/or to select object type and other options.
Here's a slightly updated version which prompts, then deletes the unused objects if you approve:
cmaAddress=""
portNumber=$(api status | grep "APACHE Gaia Port" | awk '{print $NF}')
showAll() {
IFS=$(printf "\377")
sharedArguments=( --port "${portNumber}" -f json ${cmaAddress:+-d "${cmaAddress}"} -r true show "${1}" details-level full limit 500 )
if ! firstResult=$(mgmt_cli "${sharedArguments[@]}");then return 1;fi
toReturn="$(<<<"${firstResult}" jq -c '.objects[]|.')
";objectCount=$(<<<"${firstResult}" jq -c '.total')
if [ "${objectCount}" -lt 501 ];then echo -n "${toReturn}";return 0;fi
for offsetVal in $(seq 500 500 "${objectCount}" 2>/dev/null | tr "\n" "${IFS}");do
toReturn+="$(mgmt_cli "${sharedArguments[@]}" offset "${offsetVal}" \
| jq -c '.objects[]|.')
";done;echo -n "${toReturn}";}
allDomains="$(showAll dns-domains \
| jq -c '{uuid:.uid,name:.name}')"
unusedUuids=()
echo "" && echo "Working in ${cmaAddress:+CMA }${cmaAddress:-SmartCenter}" && \
while read dnsDomain;do
printf "Domain: %s" "$(<<<"${dnsDomain}" jq '.name')"
if [ "0" == "$(mgmt_cli --port "${portNumber}" -f json ${cmaAddress:+-d "${cmaAddress}"} -r true \
where-used uid "$(<<<"${dnsDomain}" jq '.uuid')" \
| jq '."used-directly".total')" ];then
echo " is unused"
unusedUuids+=("$(<<<"${dnsDomain}" jq '.uuid')")
else
printf "\33[2K\r"
fi
done < <(echo "${allDomains[@]}")
echo "" && echo "Working in ${cmaAddress:+CMA }${cmaAddress:-SmartCenter}" && \
read -p "Delete these objects? " deleteObjects && \
if [ "y" == "${deleteObjects}" ] || [ "Y" == "${deleteObjects}" ];then
sessionCookie=$(mktemp)
mgmt_cli --port "${portNumber}" ${cmaAddress:+-d "${cmaAddress}"} -r true login >"${sessionCookie}"
for unusedUuid in "${unusedUuids[@]}";do
mgmt_cli -s "${sessionCookie}" delete dns-domain uid "${unusedUuid}"
done
mgmt_cli -s "${sessionCookie}" publish
mgmt_cli -s "${sessionCookie}" logout
fi
Edited to fix a dumb issue causing the CMA address to be printed twice.
And now a version which works on SmartCenters or CMAs, and which iterates through all of the non-global CMAs on an MDS. I also cleaned up the status messages a little. The prompt to delete will time out after 30 seconds and continue without deleting (this way, you can just let it run on a big MDS without babysitting it).
portNumber=$(api status | grep "APACHE Gaia Port" | awk '{print $NF}')
showAll() {
IFS=$(printf "\377")
sharedArguments=( --port ${portNumber} -f json ${cmaAddress:+-d} ${cmaAddress:+${cmaAddress}} -r true show "$1" details-level full limit 500 )
firstResult=$(mgmt_cli ${sharedArguments[@]})
if [ $? -ne 0 ];then return 1;fi
toReturn="$(echo "${firstResult}" | jq -c '.objects[]|.')
";objectCount=$(echo "${firstResult}" | jq -c '.total')
if [ "$objectCount" -lt 501 ];then echo "${toReturn}" | head -n -1;return 0;fi
for offsetVal in $(seq 500 500 "${objectCount}" 2>/dev/null | tr "\n" "$IFS");do
toReturn+="$(mgmt_cli ${sharedArguments[@]} offset "${offsetVal}" \
| jq -c '.objects[]|.')
";done;echo "${toReturn}" | head -n -1;}
cmaList=$(showAll domains \
| jq -c '{name:.name,server:.servers[]|{host:."multi-domain-server",ipAddress:."ipv4-address"}}' \
| grep $(hostname) \
| jq -c '[.name,.server.ipAddress]')
if [ ${#cmaList} -eq 0 ];then cmaList=("[\"$(hostname)\",\"\"]");fi
for cmaRow in $cmaList;do
cmaAddress=$(<<<"${cmaRow}" jq '.[1]' | sed 's#"##g')
allDomains="$(showAll dns-domains \
| jq -c '{uuid:.uid,name:.name}')"
unusedUuids=()
echo ""echo "Working in ${cmaAddress:+CMA }${cmaAddress:-SmartCenter}"
while read dnsDomain;do
printf "Domain: %s" "$(<<<"${dnsDomain}" jq '.name')"
if [ "0" == "$(mgmt_cli --port "${portNumber}" -f json ${cmaAddress:+-d "${cmaAddress}"} -r true \
where-used uid "$(<<<"${dnsDomain}" jq '.uuid')" \
| jq '."used-directly".total')" ];then
echo " is unused"
unusedUuids+=("$(<<<"${dnsDomain}" jq '.uuid')")
else
printf "\33[2K\r"
fi
done < <(echo "${allDomains[@]}")
echo ""
echo "Found ${#unusedUuids[@]} unused domain objects in ${cmaAddress:+CMA }${cmaAddress:-SmartCenter}"
deleteObjects=""
if [ "0" != "${#unusedUuids[@]}" ];then
timeout 30s read -p "Delete these objects? " deleteObjects
if [ "y" == "${deleteObjects}" ] || [ "Y" == "${deleteObjects}" ];then
sessionCookie=$(mktemp)
mgmt_cli --port "${portNumber}" ${cmaAddress:+-d "${cmaAddress}"} -r true login >"${sessionCookie}"
for unusedUuid in "${unusedUuids[@]}";do
mgmt_cli -s "${sessionCookie}" delete dns-domain uid "${unusedUuid}"
done
mgmt_cli -s "${sessionCookie}" publish
mgmt_cli -s "${sessionCookie}" logout
else echo "";echo "Not deleting.";echo ""
fi
fi
done
To be honest I like the idea. But I don't like the coding style.
I prefer to indent lines inside loops. Use explicit CR/(/LF) and not rely on the splitting of lines in the script to get them.
Stuff like that. They make it easiier to pickup a year later to fix or enhance.
I do too, but I develop little throwaway scripts like this in a local file which I paste into a terminal rather than editing a remote file and running it. My access to my lab is limited while I'm connected to work, so I can't just open a new session to edit a file via SCP. Indentation causes problems when pasting blocks of code in the terminal (particularly when pasting a chunk from inside a loop). Here's an example:
### Without indentation works:
for outerCounter in $(seq 1 3);do
for counter in $(seq 1 3);do
echo "Loop iteration ${outerCounter:-0}:${counter}"
done
done
### With indentation fails badly:
for outerCounter in $(seq 1 3);do
for counter in $(seq 1 3);do
echo "Loop iteration ${outerCounter:-0}:${counter}"
done
done
Paste the first one into a terminal, and it works just fine. Paste the second, you'll get a lot of bells, and it starts listing all the executables in your $PATH.
Leaderboard
Epsum factorial non deposit quid pro quo hic escorol.
| User | Count |
|---|---|
| 36 | |
| 11 | |
| 10 | |
| 10 | |
| 9 | |
| 8 | |
| 7 | |
| 7 | |
| 6 | |
| 6 |
Tue 28 Apr 2026 @ 06:00 PM (IDT)
Under the Hood: Securing your GenAI-enabled Web Applications with Check Point WAFThu 30 Apr 2026 @ 03:00 PM (PDT)
Hillsboro, OR: Securing The AI Transformation and Exposure ManagementTue 28 Apr 2026 @ 06:00 PM (IDT)
Under the Hood: Securing your GenAI-enabled Web Applications with Check Point WAFTue 12 May 2026 @ 10:00 AM (CEST)
The Cloud Architects Series: Check Point Cloud Firewall delivered as a serviceThu 30 Apr 2026 @ 03:00 PM (PDT)
Hillsboro, OR: Securing The AI Transformation and Exposure ManagementAbout CheckMates
Learn Check Point
Advanced Learning
YOU DESERVE THE BEST SECURITY