01-30-2023 08:10 AM - edited 02-03-2023 07:15 AM
Hi folks, struggling to find an answer for this.
We have a number of machines unable to run Big Sur, so I wish to deploy a script on all of these devices that remove these devices from support. I've achieved similar in the past where I can actually remove all the local jamf components, licensed apps etc.. and also delete the JSS record for the specific device using an API call. However, looking forward, I'd like to keep the JSS record available as they may contain encryption keys that we want to keep a hold of.
Basically, I'm looking for a way to "Unmanage" these devices by unticking the "Allow Jamf Pro to perform management tasks" checkbox for each machine through the API, as I believe this will free up licenses:
I've had a look online, and found some instances that I believe provide a resolution but I can't get anything to de-select this checkbox. For example :
https://community.jamf.com/t5/jamf-pro/script-to-remove-management-through-api/m-p/233611
https://community.jamf.com/t5/jamf-pro/help-sending-post-command-to-jss-api/td-p/192968
But the above are older posts and don't seem to be using tokens for authentication, and I just don't seem to be able to get the proper syntax when attempting a POST or PUT.
I can obtain the bearer tokens fine (using encrypted JSS variables with a dedicated API account) and send other GET API calls with no problems, so don't believe this to be an authorisation issue. The account I'm using for testing purposes has full access to perform all API calls.
The script I'm attempting to create, grabs the serial from the local device, uses the serial to grab the specific computer ID in the JSS using an API call (this also works fine), and then uses the ID to attempt to unmanage the device (this below is just a stand alone script for testing purposes):
#!/bin/bash
echo "Enter JSS username:"
read USERNAME
echo "Enter JSS password:"
read -s PASSWORD
TOKEN_EXPIRATION_EPOCH="0"
function getBearerToken() {
RESPONSE=$(curl -s -u "$USERNAME":"$PASSWORD" "https://<our_server>.jamfcloud.com/api/v1/auth/token" -X POST)
BEARER_TOKEN=$(echo "$RESPONSE" | plutil -extract token raw -)
TOKEN_EXPIRATION=$(echo "$RESPONSE" | plutil -extract expires raw - | awk -F . '{print $1}')
TOKEN_EXPIRATION_EPOCH=$(date -j -f "%Y-%m-%dT%T" "$TOKEN_EXPIRATION" +"%s")
}
function checkTokenExpiration() {
NOW_EPOCH_UTC=$(date -j -f "%Y-%m-%dT%T" "$(date -u +"%Y-%m-%dT%T")" +"%s")
if [[ TOKEN_EXPIRATION_EPOCH -gt NOW_EPOCH_UTC ]]
then
echo "Token valid until the following epoch time: " "$TOKEN_EXPIRATION_EPOCH"
else
echo "No valid token available, getting new token"
getBearerToken
fi
}
function invalidateToken() {
RESPONSE_CODE=$(curl -w "%{http_code}" -H "Authorization: Bearer ${BEARER_TOKEN}" "https://<our_server>.jamfcloud.com/api/v1/auth/invalidate-token" -X POST -s -o /dev/null)
if [[ ${RESPONSE_CODE} == 204 ]]
then
echo "Token successfully invalidated"
BEARER_TOKEN=""
TOKEN_EXPIRATION_EPOCH="0"
elif [[ ${RESPONSE_CODE} == 401 ]]
then
echo "Token already invalid"
else
echo "An unknown error occurred invalidating the token"
fi
}
echo "Getting API token..."
checkTokenExpiration
# Get serial number
SERIAL=$(system_profiler SPHardwareDataType | awk '/Serial/ {print $4}')
/bin/echo "Serial number is $SERIAL"
# Get JAMF ID of device
JAMF_ID=$(curl -X GET "https://<our_server>.jamfcloud.com/JSSResource/computers/serialnumber/$SERIAL" -H "accept: application/xml" -H "Authorization: Bearer $BEARER_TOKEN" | xmllint --xpath '/computer/general/id/text()' -)
/bin/echo "JAMF ID for $SERIAL is $JAMF_ID"
# Unmanage the device
/bin/echo "Attempting to remove device from Jamf management..."
curl -X POST "https://<our_server>.jamfcloud.com/JSSResource/computercommands/command/UnmanageDevice/id/$JAMF_ID" -H "accept: application/xml" -H "Authorization: Bearer $BEARER_TOKEN"
# Bin the token
/bin/echo "Invalidating API token..."
invalidateToken
/bin/echo "Done."
exit 0;
Strangely, when I run the above, there does appear to be an "Unenroll" command sent to the JSS:
However, nothing seems to be changing.
Apologies if I'm missing something which is fairly straight forward, but I'm just going round in circles.
Anyone any ideas?
Many thanks
Posted on 01-30-2023 08:20 AM
Ok, think I may be looking at this wrong. I've just noticed that on my test device, all profiles have now gone, and that there is no option in the JSS Record for the device for issuing Management commands, so it looks like it may actually be "unmanaging" the device anyway.
Does anyone know of anyway to use the API to de-select the ""Allow Jamf Pro to perform management tasks" checkbox anyway?
Posted on 01-30-2023 09:13 AM
I feel like I'm narrowing it down. Looking here: https://developer.jamf.com/jamf-pro/reference/updatecomputerbyid
I've tried the following:
curl --request PUT --url "https://<our_server>.jamfcloud.com/JSSResource/computers/id/$JAMF_ID" -H "Content-Type: application/xml" -H "Accept: application/xml" -H "Authorization: Bearer $BEARER_TOKEN" '<computer><general><remote_management><managed>false</managed></remote_management></general></computer>'
But now getting an error:
curl: (6) Could not resolve host: <computer><general><remote_management><managed>false<
Any ideas what I'm missing?
Posted on 01-31-2023 02:29 AM
Ok figured it out. The exact command required is:
curl --request PUT --url "https://<our_server>.jamfcloud.com/JSSResource/computers/id/$JAMF_ID" -H "Content-Type: application/xml" -H "Accept: application/xml" -H "Authorization: Bearer $BEARER_TOKEN" -d '<computer><general><remote_management><managed>false</managed></remote_management></general></computer>'
Posted on 02-01-2023 07:55 AM
@rcoleman I trying to get the Unmanaged Command to work, do you know what minimum permissions that is needed? I have Jamf Pro Server Actions -> Send Computer Unmanage Command and Computer Read
Thanks!
02-01-2023 08:10 AM - edited 02-01-2023 08:19 AM
@Mikael_lofgren I actually just ran into this issue. We use a dedicated API account with encrypted details for performing API operations and on my last test with this it complained about permissions. During my testing, I used my own account which has full permissions and it worked fine. Unfortunately I don't have time just now to investigate this further however on first look I believe for the account being used to perform API operations you'll need to make sure "Send Computer Unmanage Command" is selected. If you manage to try this let me know if it works:
EDIT - Sorry, I've just realised that you've mentioned this is already selected! In that case I'm not sure what will be required. We also use the account for enabling remote management using MDM command and that works fine. When I get time to investigate further and if I come up with a solution then I'll make sure to post.
Posted on 02-02-2023 08:07 AM
@Mikael_lofgren Just to say this worked for myself and I only have the same permissions you listed above, so apologies but I'm not sure what's going wrong at your side :(
Posted on 02-03-2023 12:50 AM
@rcoleman My command seems to work when using full permissions, I have opened a support case to get this sorted, can post any findings here when done. Thanks!
Posted on 02-03-2023 03:30 AM
@Mikael_lofgren That would be great, many thanks. It's possible I made a change to the permissions a long time ago for our API account but just can't remember, so it certainly would be useful to know exactly what permissions are required.
Posted on 02-03-2023 04:40 AM
Ahh think I missed, create in Computer objects, but this is the minimum to work, response code from API when working is 201.
# Jamf Pro Server Objects > Computers Create, Read and Update
# Jamf Pro Server Actions > Send Computer Unmanage Command
Posted on 02-11-2023 11:43 AM
Sending the MDM Command to "Unmanage" a device requires the device to be active to receive it -- in other words, the device is not marked as "unmanaged" until it receives the command and responds back to the Jamf Pro Server.
The other method you used, sending the remote_management > managed > false payload does not rely on the device being active, however, it does not remove anything from the device (e.g. the Jamf Management Framework, aka the jamf binary, MDM Profile, etc.); in this scenario the device does not know it has been unmanaged and will continue to attempt to check-in, as well as apply any and all configurations that it has "cached" on the device.
As noted, to perform this operation, the account will need Update privileges to Computers (at minimum), but it's not uncommon that additional privileges, that seem excessive given the task, are required (such as Create and Read) in Jamf's implementation of numerous API endpoints. There's even been occurrences where permissions for completely separate objects are required to perform operations on another object.
Posted on 02-20-2023 04:34 AM
@rcoleman
Just looking at this myself but still not getting the Mac to move into the umanaged devices in Jamf, the tick box is still ticked.
Any chance you can post your full updated script as the first script posted does a full unenrol unmanage which removes all jamf framework which is not what I think we are both trying to achieve and I can't seem to get the syntax right when adding in your updated curl setting this
<remote_management><managed>false</managed></remote_management>
Posted on 02-20-2023 06:27 AM
I worked it out 😀
02-20-2023 06:32 AM - edited 02-20-2023 06:33 AM
@MatG - Sure no problem. I've removed the "Unmanage" command and you'll need to replace the server name but this works for myself for unticking:
#!/bin/bash
echo "Enter JSS username:"
read USERNAME
echo "Enter JSS password:"
read -s PASSWORD
TOKEN_EXPIRATION_EPOCH="0"
function getBearerToken() {
RESPONSE=$(curl -s -u "$USERNAME":"$PASSWORD" "https://<your_server>.jamfcloud.com/api/v1/auth/token" -X POST)
OS_MAJOR_VERSION=$(sw_vers -buildVersion | cut -c 1-2)
echo "OS Major Version: $OS_MAJOR_VERSION"
if [ "$OS_MAJOR_VERSION" -lt 21 ]; then
# Get the token info
BEARER_TOKEN=$(echo $RESPONSE | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["token"]')
# Get the expiration date
TOKEN_EXPIRATION=$(echo $RESPONSE | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["expires"]')
# If we are running Monterey or later then we can use plutil to parse json
else
# Get the token info
BEARER_TOKEN=$(echo "$RESPONSE" | plutil -extract token raw -)
# Get the token expiration date
TOKEN_EXPIRATION=$(echo "$RESPONSE" | plutil -extract expires raw - | awk -F . '{print $1}')
fi
TOKEN_EXPIRATION_EPOCH=$(date -j -f "%Y-%m-%dT%T" "$TOKEN_EXPIRATION" +"%s")
}
function checkTokenExpiration() {
NOW_EPOCH_UTC=$(date -j -f "%Y-%m-%dT%T" "$(date -u +"%Y-%m-%dT%T")" +"%s")
if [[ TOKEN_EXPIRATION_EPOCH -gt NOW_EPOCH_UTC ]]
then
echo "Token valid until the following epoch time: " "$TOKEN_EXPIRATION_EPOCH"
else
echo "No valid token available, getting new token"
getBearerToken
fi
}
function invalidateToken() {
RESPONSE_CODE=$(curl -w "%{http_code}" -H "Authorization: Bearer ${BEARER_TOKEN}" "https://uoe.jamfcloud.com/api/v1/auth/invalidate-token" -X POST -s -o /dev/null)
if [[ ${RESPONSE_CODE} == 204 ]]
then
echo "Token successfully invalidated"
BEARER_TOKEN=""
TOKEN_EXPIRATION_EPOCH="0"
elif [[ ${RESPONSE_CODE} == 401 ]]
then
echo "Token already invalid"
else
echo "An unknown error occurred invalidating the token"
fi
}
echo "Getting API token..."
checkTokenExpiration
# Get serial number
SERIAL=$(system_profiler SPHardwareDataType | awk '/Serial/ {print $4}')
/bin/echo "Serial number is $SERIAL"
# Get JAMF ID of device
JAMF_ID=$(curl -X GET "https://<your_server>.jamfcloud.com/JSSResource/computers/serialnumber/$SERIAL" -H "accept: application/xml" -H "Authorization: Bearer $BEARER_TOKEN" | xmllint --xpath '/computer/general/id/text()' -)
/bin/echo "JAMF ID for $SERIAL is $JAMF_ID"
# De-select "Allow Jamf Pro to perform management tasks" in the JSS for this device
curl --request PUT --url "https://<your_server>.jamfcloud.com/JSSResource/computers/id/$JAMF_ID" -H "Content-Type: application/xml" -H "Accept: application/xml" -H "Authorization: Bearer $BEARER_TOKEN" -d '<computer><general><remote_management><managed>false</managed></remote_management></general></computer>'
# Bin the token
/bin/echo "Invalidating API token..."
invalidateToken
/bin/echo "Done."
exit 0;
EDIT - Ah, I just see you got it working - good stuff 😀
Posted on 04-05-2023 04:31 AM
Guys,
Help me out here.. I'm in testing mode of Jamf API. So did sample test to get activation code. I do have all permission to run the API as I created a local user account in Jamf with the privilege as 'Administrator'. However, I'm getting the same below error message when I 'Try it out' as well as through 'shell script'.
Error message:
<html>
<head>
<title>Status page</title>
</head>
<body style="font-family: sans-serif;">
<p style="font-size: 1.2em;font-weight: bold;margin: 1em 0px;">Unauthorized</p>
<p>The request requires user authentication</p>
<p>You can get technical details <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">here</a>.<br>
Please continue your visit at our <a href="/">home page</a>.
</p>
</body>
</html>%
Kindly advice. Thanks.
Posted on 04-05-2023 10:18 AM
@sk25 Without knowing how you constructed the command in the script....But using the API documentation page's "Try it out" feature and still having issues...
Do you use Sites? The Site you have selected in the GUI affects API usage. If you're not at the "Full Jamf Pro" level, you will be limited when using the API.
Posted on 04-06-2023 05:17 AM
As said the local user created in Jamf Pro is as an 'Administrator' privilege which means having create, read,update and delete of Jamf pro server objects, jamf pro server settings,Jamf Pro server actions
Posted on 04-06-2023 10:41 AM
That doesn't matter if you use and have a Site selected. If you use Sites and are viewing a Site in the GUI, it affects what you can do/see in the API.
Trust me, we use Sites here and I have to account for it in all of the scripts I write for usage by our Site Admins.
Posted on 04-05-2023 04:39 AM
@sk25 Do you have the bearer token then? As the API page says:
If Basic authentication is disabled then a token must be generated to be used with the 'Try it out!' feature. Enter username and password to generate a token.
Posted on 04-06-2023 05:06 AM
I've unchecked the 'Allow Basic Authentication in addition to Bearer Token Authentication" and ran the Bearer Token authorization from open recipe and getting the below error message. Kindly advice. Thanks.
"No valid token available, getting new token
Failed conversion of ``<stdin>: Could not extract value, error: No value at that key path or invalid key path: expires'' using format ``%Y-%m-%dT%T''
date: illegal time format
usage: date [-jnRu] [-r seconds|file] [-v[+|-]val[ymwdHMS]]
[-I[date | hours | minutes | seconds]]
[-f fmt date | [[[mm]dd]HH]MM[[cc]yy][.ss]] [+format]
{
"httpStatus" : 401,
"errors" : [ ]
}No valid token available, getting new token
Failed conversion of ``<stdin>: Could not extract value, error: No value at that key path or invalid key path: expires'' using format ``%Y-%m-%dT%T''
date: illegal time format
usage: date [-jnRu] [-r seconds|file] [-v[+|-]val[ymwdHMS]]
[-I[date | hours | minutes | seconds]]
[-f fmt date | [[[mm]dd]HH]MM[[cc]yy][.ss]] [+format]
Token already invalid
{
"httpStatus" : 401,
"errors" : [ ]"
Posted on 04-06-2023 11:00 AM
Without seeing the constructed command, it's hard to troubleshoot errors. But....it looks like you may have ran the code from the Bearer Token Authorization Recipe example. Did you simply copy and paste the code? If so, you could have invalid character (e.g. ASCII vs Unicode) encoding in your script. (This is a common issue when copying code from a website into a shell script and it's commonly due to the quotation marks used; e.g. " and ' ).
For more information on review these pages:
Also, I'd recommend reviewing (if you haven't already) for working with Bearer Tokens:
Posted on 04-19-2023 01:02 AM
All,
I'm not getting anymore error on date format on the above mentioned API. However, if I give SSO enabled Jamf username and password, getting "Http code as 401". If I give Jamf local account username and password, I'm able to see the token, token expiration information, epoch etc.,
Question here:
SSO enabled Jamf username and password won't work on API's?
Any simple code for renewal of Token as Jamf token is valid for 30 mins or so.
Kindly advice guys. Thanks.
Posted on 04-19-2023 03:35 AM
We haven't got any SSO accounts to work with the API, we use local accounts for different API/scripts. Strange thing when re-tested is that API call to return the servern version seems to work (jamf-pro-version)
Posted on 04-27-2023 02:52 AM
@Mikael_lofgren @MLBZ521 For Jamf API SSO is not supporting. We have to use local Jamf account with necessary API permission.
Posted on 04-19-2023 11:45 AM
I can't speak for the API usage with SSO enabled, but wouldn't be surprised...
For expiration tracking/checking, you can utilize the function sample in the Bearer Token Authorization Recipe page I referenced before. Or, more correctly, you could use the Keep Alive endpoint to invalidate the current and create a new Bearer Token in one step.
Posted on 04-06-2023 05:32 AM
Maybe start look here on how to get bearer token: https://derflounder.wordpress.com/2021/12/10/obtaining-checking-and-renewing-bearer-tokens-for-the-j...
Posted on 04-27-2023 02:58 AM
Guys,
Help me out with the below script. Trying to send unmanage command to machine. However, I'm getting: Syntax Error Unexpected end of file
#! /bin/sh
# server connection information
jamfProURL="XXXX"
username="XXXX"
password="XXXX"
renewToken() {
# renew auth token
authToken=$( /usr/bin/curl \
--header "Accept: application/json" \
--header "Authorization: Bearer $token" \
--request POST \
--silent \
--url "$jamfProURL/api/v1/auth/keep-alive" )
# parse auth token
token=$( /usr/bin/plutil \
-extract token raw - <<< "$authToken" )
tokenExpiration=$( /usr/bin/plutil \
-extract expires raw - <<< "$authToken" )
localTokenExpirationEpoch=$( TZ=UTC /bin/date -j -f "%Y-%m-%dT%T" "$tokenExpiration" "+%s" 2> /dev/null )
# update the renewal time for another 25 minutes
renewalTime=$(( $localTokenExpirationEpoch - 300 ))
}
# request auth token
authToken=$( /usr/bin/curl \
--request POST \
--silent \
--url "$jamfProURL/api/v1/auth/token" \
--user "$username:$password" )
echo "$authToken"
# parse auth token
token=$( /usr/bin/plutil \
-extract token raw - <<< "$authToken" )
tokenExpiration=$( /usr/bin/plutil \
-extract expires raw - <<< "$authToken" )
localTokenExpirationEpoch=$( TZ=GMT /bin/date -j \
-f "%Y-%m-%dT%T" "$tokenExpiration" \
+"%s" 2> /dev/null )
echo Token: "$token"
echo Expiration: "$tokenExpiration"
echo Expiration epoch: "$localTokenExpirationEpoch"
# verify auth token is valid
checkToken=$( /usr/bin/curl \
--header "Authorization: Bearer $token" \
--silent \
--url "$jamfProURL/api/v1/auth" \
--write-out "%{http_code}" )
tokenStatus=${checkToken: -3}
echo Token status: "$tokenStatus"
# subtract five minutes (300 seconds) from localTokenExpirationEpoch
renewalTime=$(( $localTokenExpirationEpoch - 300 ))
while IFS= read aDevice
do
now=$( /bin/date +"%s" )
if [[ "$renewalTime" -lt "$now" ]]; then
renewToken
fi
## get unique identifier for machine
udid=$(system_profiler SPHardwareDataType | awk '/UUID/ { print $3; }')
## get computer ID from Jamf server
compId=$( /usr/bin/curl \
--request GET \
--url "$jamfProURL/JSSResource/computers/udid/${udid}/subset/general" \
--header "Accept: application/xml" \
--header "Authorization: Bearer $token" \
--xpath '/computer/general/id/text()' )
echo "${compID}"
## send unmanage command to machine
/usr/bin/curl \
--header "Authorization: Bearer $token" \
--request POST \
--url "$jamfProURL/JSSResource/computercommands/command/UnmanageDevice/id/${compId}"
# expire auth token
/usr/bin/curl \
--header "Authorization: Bearer $token" \
--request POST \
--silent \
--url "$jamfProURL/api/v1/auth/invalidate-token"
04-27-2023 11:06 AM - edited 04-27-2023 11:07 AM
I'm really confused on what you're doing here....as it looks like two different possibilities:
It's also important to note that sending the Unmanage MDM Command to a device means the device must be active to receive it and become unmanaged. In addition, on a Mac, this command only removes the MDM Profile (and related bits), it does not remove the Jamf Management Framework which consists of the `jamf` binary and other bits, which means the device will continue to check-in to the JPS.
Posted on 05-01-2023 11:41 PM
@MLBZ521 Using this same While loop i'm able to get the list of smart groups, but not sure why unable to send the unmanage command.
I'm passing the credential to bearer token so that no need to key in credentials each and every time.
Also, I'm running this script which already managed by the Jamf. And I would like to take your last point that it would check in back to Jamf server. Will work on it. Thanks, BTW.
Posted on 05-04-2023 12:19 AM
@MLBZ521 My apologies MLBZ521. After I removed the 'while' loop the script executed well. I mean without any issues profiles got removed. Thanks a lot.
Posted on 05-04-2023 02:22 PM
As a mentioned previously, removing the MDM Profile does not remove the Jamf Management Framework which consists of the `jamf` binary and other bits, which means the device will continue to check-in to the JPS.
Posted on 05-04-2023 02:18 PM
Why are you using the `while` loop to get a list of Smart Groups?
But, as mentioned, the `while` loop is not terminated, so that is going to cause the script to fail.
Posted on 06-05-2023 02:19 AM
Guys, anyone explain me below when I execute the unmanage script via API and Bearer token renewal in terminal I'm getting this,
What's this?
Also, I used below to delete the entry of the computer in Jamf via API, but getting the below error message and the Id having administrator privilege.
Posted on 06-05-2023 02:35 AM
add:
set -x
to code after shebang, then you can see output to debug.
Posted on 06-05-2023 05:15 PM
The first question: The image indicates that `curl` is "downloading" something, for instance an ".html" file. This is what `curl` natively does. What it's downloading, you'd have to check. You can add `--output ~/Downloads/file.html` to the end of your `curl` command and see what's being transmitted.
For the second question: It's hard to know exactly without seeing the full `curl` command, but to me, it almost looks like the `curl` command is attempting to interact with a web server (aka host) named `DELETE`, which would obviously be incorrect. That should be your HTTP method, not your host. Be sure you're passing your values to the correct parameters. e.g.
curl --url <https://jamf.pro.url:8443> --request [GET | PUT | POST | DELETE ] [...<remaining parameters>...]
That said, I don't think the code is doing what you think it's doing... At least, the XML payload in that second image has nothing to do with deleting a computer record...
Posted on 06-05-2023 10:28 PM
@MLBZ521 Below is the curl command for the deletion of the computer entry in Jamf.
/usr/bin/curl \
--header "Authorization: Bearer $token"\
--request DELETE \
--url "$jamfProURL/JSSResource/computers/udid/${compId}"
Sure, will try add output parameter and check. Thanks.
Posted on 06-07-2023 11:29 AM
That looks correct for what I can see. What's the value of your `$comdId` variable?
That said, that command and the screenshot for the results of that command do not match at all.
Posted on 06-16-2023 03:59 AM
Guys, help me with the script,
Requirements:
1. Once the jamf unenroll script executed, I would like to let the customer must get notification "system is going to reboot in 2 mins" and after 2 mins should restart automatically.
2. Another script to remove the CA certificate profile from Profile tab in system preference.
Thanks in advance.
Posted on 06-16-2023 06:51 PM
I believe you have a misunderstanding of how things work...
1. Unless you're running this on the device that is being unenrolled...this isn't possible....and if you are doing that....that's a very bad idea... Either way, why are you bothering with rebooting them?
2. Not sure what you're referring to here... This sounds like a custom Profile and you can't locally remove Profiles installed via MDM when the device is ADE Enrolled...
Posted on 06-17-2023 09:55 AM
The reason to reboot the machine is our customer is moving out of jamf and getting the enrolled in Intune. After the Jamf profile removed, we were unable to enroll it intune unless we reboot the machine.
2. As soon as we enroll the device in Jamf, unlike the other profiles, customer created a profile to CA certificate install. Normal script isn't remove the CA Profile.