Posted on 10-02-2024 09:57 AM
Hi Jamf Team,
I am encountering an issue with a script that I am using in a Jamf extension attribute. The script is not returning output always “No_Certificate_Found” when processed through Jamf. I need assistance to validate the issue and understand why it is not picking up the results properly.
When I trigger an inventory update through Jamf's built-in functun, no results are returned. However, when I manually run the command via Jamf using “sudo jamf recon”, I am able to retrieve the expected results. Similarly, the script works when executed via Self Service.
It seems that the script is not functioning properly when built in inventory option is enabled and not running as user in Jamf. Could you please assit this issue? I have attached the script.
Thank you for your assistance.
#!/bin/bash
# Expiry Date | Certificate Name | SHA-256 Hash | Keychain Path
#20-Jan-2024 | Manikandan R | 40C6326E5B3458F07A1D2E4DDBEF59728A425C92612FA022263C73BA51FEB8E | "/Users/test/Library/Keychains/login.keychain-db" |test
#20-Jan-2024 | Manikandan R | B6E53632BDC2A20670CEAF2DCA9FFE92BE130DF100D6B3777646D6541921745 | "/Users/test/Library/Keychains/login.keychain-db" |test
# Output file
output_file="/Users/Shared/expired_certificates_info.txt"
sorted_file="/Users/Shared/sorted_expired_certificates_info.txt"
# Ensure the directory and output files have proper permissions for all users
chmod 777 /Users/Shared
touch "$output_file" "$sorted_file"
chmod 666 "$output_file" "$sorted_file"
# Create or clear the output file and add the header
> "$output_file"
# Current date for comparison
current_date=$(date +"%Y-%m-%d")
# Use security command to find all certificates and process each one
# Function to process certificates in a given keychain
process_certificates_in_keychain() {
local keychain="$1"
local user_home="$2"
# Extract certificates using security command
sudo -u "$user_home" /usr/bin/security find-certificate -a -Z "$keychain" | while IFS= read -r line; do
# Extract the SHA-256 hash
if [[ $line == *"SHA-256 hash:"* ]]; then
sha256=$(echo "$line" | awk '{print $3}')
fi
# Extract the certificate name
if [[ $line == *"alis"* ]]; then
cert_name=$(echo "$line" | sed 's/.*"alis"<blob>="\([^"]*\)".*/\1/')
fi
# Extract the keychain path
if [[ $line == *"keychain"* ]]; then
keychain_path=$(echo "$line" | awk -F' ' '{print $NF}')
fi
# Once we have both the SHA-256 hash and certificate name, fetch the expiry date
if [[ -n $cert_name && -n $sha256 ]]; then
expiry_date=$(/usr/bin/security find-certificate -a -c "$cert_name" -p -Z | \
sed -n 'H; /^SHA-256/h; ${g;p;}' | \
/usr/bin/openssl x509 -noout -enddate 2>/dev/null | \
cut -f2 -d= | xargs -I {} sh -c 'if [ -n "{}" ]; then date -jf "%b %e %T %Y %Z" "{}" +"%Y-%m-%d"; fi')
# Only print if all information is found and if the certificate is expired
if [[ -n $expiry_date && "$expiry_date" < "$current_date" ]]; then
# Format expiry date to DD-MMM-YYYY
formatted_expiry_date=$(date -jf "%Y-%m-%d" "$expiry_date" +"%d-%b-%Y")
echo "$formatted_expiry_date | $cert_name | $sha256 | $keychain_path |$user_home" >> "$output_file"
fi
# Reset variables for the next certificate
expiry_date=""
cert_name=""
sha256=""
keychain_path=""
fi
done
}
# Get all users with a home directory on the system and UID greater than 500
user_list=$(dscl . list /Users | grep -v '_')
# Process certificates for each user
for user in $user_list; do
# Get the UID of the user
user_uid=$(dscl . -read /Users/"$user" UniqueID | awk '{print $2}')
# Check if the UID is greater than 500
if [ "$user_uid" -gt 500 ]; then
# Get the user's home directory
user_home=$(dscl . read /Users/"$user" NFSHomeDirectory | cut -d ' ' -f 2)
# Get the list of keychains for the user
keychains=($(sudo -u "$user" security list-keychains | tr -d '"' | tr ' ' '\n'))
# Process each keychain for certificates
for keychain in "${keychains[@]}"; do
process_certificates_in_keychain "$keychain" "$user"
done
fi
done
# Sort the output file by expiry date (low to high) and save to a temporary file
sort -t '|' -k 1 "$output_file" > "$sorted_file"
# Replace the original output file with the sorted file
mv "$sorted_file" "$output_file"
output=$(cat "$output_file")
# Check if the output file is empty
if [[ -s "$output_file" ]]; then
# Display output
echo "<result>$output</result>"
else
echo "<result>No_Certificate_Found</result>"
fi
Posted on 10-02-2024 10:43 AM
Your getting a result because the script ran in user profile , while running from Jamf the script ran as root. Try sudo -s command first login as root in terminal and try to execute the script you will get the same result as executing from Jamf
Posted on 10-02-2024 10:44 AM
If your running anything from self service it execute as user
Posted on 10-04-2024 04:01 PM
One a side note, I would strongly recommend you not action changes to your endpoints via Extension Attributes. You should make the change via policy, use your EA to validate your expectations, and then use Smart Groups to trigger changes based upon the results of the EA's output.
Aside from the danger of having scripts that action changes on your device on an ongoing basis, you looks the ability to view logs, and track history. If the EA fails in a way other than ways your logic has accounted for, you won't know why.
Finally, those EAs run with inventory updates, so every time you add something that "does" something, it prologues your recon times. If a script errors out in an EA that isn't clean, you run the risk of incomplete inventory updates, or worse, stuck inventory updates. That will lead to your computer failing to being managed correctly, as it waits for the EA to finish.
My 2 cents. Good luck to you.