Creates a LaunchDaemon and a self-destructing Bash script to run a
recon
at next Reboot, after confirming your Jamf Pro server is available
Background
With surprising frequency, updating a computer’s inventory with the Jamf Pro server the next time a computer reboots can be quite handy. For example:
- After upgrading the OS via erase-install
- After completing Setup Your Mac
- After running Office Reset policies
- After FileVault-related policies
The self-destructing script below will create a LaunchDaemon and a client-side Bash script to run a recon
at the next reboot, after confirming your Jamf Pro server is available.
Script Modifications
After making the following modifications, upload the script to your Jamf Pro server.
plistDomain
Variable
Modify both occurrences of the plistDomain
variable to match your organization’s Reverse Domain Name Notation, for example: org.churchofjesuschrist
.
sleep
(optional)
The script is set to make 10 attempts to check for a connection to your Jamf Pro server, pausing for 30 seconds after each attempt (for a total of 5 minutes); modify to your liking.
Script Execution (1 of 2)
The initial script execution is controlled by the Script payload in the various Jamf Pro policies to which you add the Recon at Reboot script.
The output of the initial script execution is similar to the following, which indicates the creation of both the LaunchDaemon — in the /Library/LaunchDaemons/
directory — and the self-destructing client-side script — in the /private/var/tmp/
directory.
Recon at Reboot (1.0.1) Create the LaunchDaemon ... Set LaunchDaemon file permissions ... Create the script ... Set script file permissions ... Create Log File at /private/var/tmp/org.churchofjesuschrist.reconAtReboot.log ... LaunchDaemon and Script created.
Script Execution (2 of 2)
The second (and final) script execution is controlled by the RunAtLoad
LaunchDaemon.
While waiting to confirm connectivity to your Jamf Pro server, the log located in /private/var/tmp
is similar to the following:
Created org.churchofjesuschrist.reconAtReboot.log on 2022-08-25-015120 Starting Recon at Reboot (1.0.1) at 2022-08-25-015322
After confirming your Jamf Pro server is available, inventory is updated and then both the client-side script and LaunchDaemon are removed; the log file remains in the /private/var/tmp
directory for later inspection.
Created org.churchofjesuschrist.reconAtReboot.log on 2022-08-25-015120 Starting Recon at Reboot (1.0.1) at 2022-08-25-015322 Jamf Pro server is available, proceeding; Check for Jamf Pro server connection; Resuming Recon at Reboot; Updating inventory; Delete org.churchofjesuschrist.reconAtReboot.plist; Delete script; End-of-line.
Custom Trigger
We also have a Jamf Pro policy with a custom trigger of reconAtReboot
set to Ongoing and scoped to All computers which we frequently leverage in various other scripts and policies.
Script
Latest version available on GitHub.
#!/bin/bash #################################################################################################### # # ABOUT # # Creates a self-destructing LaunchDaemon and script to run a Recon # at next Reboot (after confirming your Jamf Pro server is available) # #################################################################################################### # # HISTORY # # Version 1.0.0, 10-Nov-2016, Dan K. Snelson (@dan-snelson) # Original version # # Version 1.0.1, 12-Aug-2022, Dan K. Snelson (@dan-snelson) # Added check for Jamf Pro server connection # #################################################################################################### #################################################################################################### # # Variables # #################################################################################################### scriptVersion="1.0.1" plistDomain="org.churchofjesuschrist" # Hard-coded domain name plistLabel="reconAtReboot" # Unique label for this plist plistLabel="$plistDomain.$plistLabel" # Prepend domain to label timestamp=$( /bin/date '+%Y-%m-%d-%H%M%S' ) # Used in log file #################################################################################################### # # Program # #################################################################################################### # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Logging preamble # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # echo "Recon at Reboot (${scriptVersion})" # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Create launchd plist to call a shell script # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # echo "Create the LaunchDaemon ..." /bin/echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"> <plist version=\"1.0\"> <dict> <key>Label</key> <string>${plistLabel}</string> <key>ProgramArguments</key> <array> <string>/bin/sh</string> <string>/private/var/tmp/reconAtReboot.bash</string> </array> <key>RunAtLoad</key> <true/> </dict> </plist>" > /Library/LaunchDaemons/$plistLabel.plist # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Set the permission on the file # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # echo "Set LaunchDaemon file permissions ..." /usr/sbin/chown root:wheel /Library/LaunchDaemons/$plistLabel.plist /bin/chmod 644 /Library/LaunchDaemons/$plistLabel.plist /bin/chmod +x /Library/LaunchDaemons/$plistLabel.plist # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Create reboot script # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # echo "Create the script ..." cat << '==endOfScript==' > /private/var/tmp/reconAtReboot.bash #!/bin/bash #################################################################################################### # # ABOUT # # Recon at Reboot # #################################################################################################### # # HISTORY # # Version 1.0.0, 10-Nov-2016, Dan K. Snelson # Original version # # Version 1.0.1, 12-Aug-2022, Dan K. Snelson (@dan-snelson) # Added check for Jamf Pro server connection # #################################################################################################### #################################################################################################### # # Variables # #################################################################################################### scriptVersion="1.0.1" plistDomain="org.churchofjesuschrist" # Hard-coded domain name plistLabel="reconAtReboot" # Unique label for this plist plistLabel="$plistDomain.$plistLabel" # Prepend domain to label timestamp=$( /bin/date '+%Y-%m-%d-%H%M%S' ) # Used in log file scriptResult="" #################################################################################################### # # Functions # #################################################################################################### # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Check for a Jamf Pro server connection # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # jssConnectionStatus () { scriptResult+="Check for Jamf Pro server connection; " unset jssStatus jssStatus=$( /usr/local/bin/jamf checkJSSConnection 2>&1 | /usr/bin/tr -d '\n' ) case "${jssStatus}" in *"The JSS is available." ) jssAvailable="yes" ;; *"No such file or directory" ) jssAvailable="not installed" ;; * ) jssAvailable="unknown" ;; esac } #################################################################################################### # # Program # #################################################################################################### # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Logging preamble # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # echo "Starting Recon at Reboot (${scriptVersion}) at $timestamp" >> /private/var/tmp/$plistLabel.log # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Hard-coded sleep of 25 seconds for auto-launched applications to start # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # sleep "25" # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Check for a Jamf Pro server connection # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # jssConnectionStatus counter=1 until [[ "${jssAvailable}" == "yes" ]] || [[ "${counter}" -gt "10" ]]; do scriptResult+="Check ${counter} of 10: Jamf Pro server NOT reachable; waiting to re-check; " sleep "30" jssConnectionStatus ((counter++)) done # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # If Jamf Pro server is available, update inventory # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # if [[ "${jssAvailable}" == "yes" ]]; then echo "Jamf Pro server is available, proceeding; " >> /private/var/tmp/$plistLabel.log scriptResult+="Resuming Recon at Reboot; " scriptResult+="Updating inventory; " /usr/local/bin/jamf recon else scriptResult+="Jamf Pro server is NOT available; exiting." fi # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Delete launchd plist # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # scriptResult+="Delete $plistLabel.plist; " /bin/rm -fv /Library/LaunchDaemons/$plistLabel.plist # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Delete script # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # scriptResult+="Delete script; " /bin/rm -fv /private/var/tmp/reconAtReboot.bash # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Exit # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # scriptResult+="End-of-line." echo "${scriptResult}" >> /private/var/tmp/$plistLabel.log exit 0 ==endOfScript== # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Set the permission on the script # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # echo "Set script file permissions ..." /usr/sbin/chown root:wheel /private/var/tmp/reconAtReboot.bash /bin/chmod 644 /private/var/tmp/reconAtReboot.bash /bin/chmod +x /private/var/tmp/reconAtReboot.bash # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Create Log File # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # echo "Create Log File at /private/var/tmp/$plistLabel.log ..." touch /private/var/tmp/$plistLabel.log echo "Created $plistLabel.log on $timestamp" > /private/var/tmp/$plistLabel.log # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Exit # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # echo "LaunchDaemon and Script created." exit 0