Menu Close

CrowdStrike Falcon RTR macOS Scripts

A collection of macOS scripts for CrowdStrike Falcon Real Time Response

Vendor Overview

Real Time Response is a feature of CrowdStrike Falcon® Insight [that] empowers incident responders with deep access to systems across the distributed enterprise, [providing] enhanced visibility … to fully understand emerging threats and the power to directly remediate. External Link

macOS Scripts

The following macOS scripts — presented in their typical execution order — are tuned for computers enrolled in Jamf Pro.

Template

Description

The template below includes the following features:

  • Interpreter Directive: Unless you’re leveraging specific “bash-isms,” you should probably use zsh as the default interpreter directive
  • Script Name: Including the script’s name and purpose as part of the script’s output has proved invaluable when assembling copy-pasta audit logs
  • Estimated Duration: As with nearly all remotely executed commands, you’re “flying blind” and having a ballpark estimate of how long the command typically takes to execute can be stress-reducing — in what tends to be stressful situations
#!/bin/zsh

# macOS Script_Name_Goes_Here (0.0.1)
# (Estimated Duration: 0h:0m:01s)

echo -e "\n\n\n###\n# macOS Script_Name_Goes_Here (0.0.1)\n# (Estimated Duration: 0h:0m:01s)\n###"

# INITIALIZE SECONDS
SECONDS="0"

# COMMAND
# Replace
# these
# lines
# with
# the
# command
# to
# execute

# OUTPUT EXECUTION DURATION
echo -e "\nExecution Duration: $(printf '%dh:%dm:%ds\n' $((SECONDS/3600)) $((SECONDS%3600/60)) $((SECONDS%60)))"
macOS Clock Skew Correction (0.0.1)

Description

Set Simple Network Time Protocol to time.apple.com

#!/bin/zsh

# macOS Clock Skew Correction (0.0.1)
# (Estimated Duration: 0h:0m:01s)

echo -e "\n\n\n###\n# macOS Clock Skew Correction (0.0.1)\n# (Estimated Duration: 0h:0m:01s)\n###"

# Initialize SECONDS
SECONDS="0"

echo "• Set Simple Network Time Protocol to 'time.apple.com'"
/usr/bin/sntp -sS time.apple.com

echo -e "\nExecution Duration: $(printf '%dh:%dm:%ds\n' $((SECONDS/3600)) $((SECONDS%3600/60)) $((SECONDS%60)))"

Sample Output

###
# macOS Clock Skew Correction (0.0.1)
# (Estimated Duration: 0h:0m:01s)
###

• Set Simple Network Time Protocol to 'time.apple.com'
+0.129035 +/- 0.112248 time.apple.com 17.254.0.26

Execution Duration: 0h:0m:0s
macOS Network Quality Test (0.0.2)

Description

Leverage macOS Monterey’s (and later) networkQuality binary to better understand your users’ Internet connection

#!/bin/zsh

# macOS Network Quality Test (0.0.2)
# (Estimated Duration: 0h:0m:41s)

echo -e "\n\n\n###\n# macOS Network Quality Test (0.0.2)\n# (Estimated Duration: 0h:0m:41s)\n###"

# Initialize SECONDS
SECONDS="0"

osProductVersion=$( /usr/bin/sw_vers -productVersion )
case "${osProductVersion}" in

    10* | 11* ) 
        dlCapacity="N/A; macOS ${osProductVersion}"
        dlResponsiveness="N/A; macOS ${osProductVersion}"
        ;;

    12* )
        networkqualityTest=$( /usr/bin/networkquality -s -v )
        dlCapacity=$( echo "${networkqualityTest}" | /usr/bin/awk '/Download capacity:/{print $3, $4}' )
        dlResponsiveness=$( echo "${networkqualityTest}" | /usr/bin/awk '/Download Responsiveness:/{print $3, $4, $5}' )
        ;;

    13* | 14* )
        networkqualityTest=$( /usr/bin/networkquality -s -v )
        dlCapacity=$( echo "${networkqualityTest}" | /usr/bin/awk '/Downlink capacity:/{print $3, $4}' )
        dlResponsiveness=$( echo "${networkqualityTest}" | /usr/bin/awk '/Downlink Responsiveness:/{print $3, $4, $5}' )
        ;;

    15* )
        networkqualityTest=$( /usr/bin/networkquality -s -v )
        dlCapacity=$( echo "${networkqualityTest}" | /usr/bin/awk '/Downlink capacity:/{print $3, $4}' | head -n 1 )
        dlResponsiveness=$( echo "${networkqualityTest}" | /usr/bin/awk '/Downlink Responsiveness:/{print $3, $4, $5}' | head -n 1 )
        ;;

esac

echo -e "\n• Download Capacity: ${dlCapacity}"
echo "• Download Responsiveness: ${dlResponsiveness}"
echo -e "\nExecution Duration: $(printf '%dh:%dm:%ds\n' $((SECONDS/3600)) $((SECONDS%3600/60)) $((SECONDS%60)))"

Sample Output

###
# macOS Network Quality Test (0.0.2)
# (Estimated Duration: 0h:0m:41s)
###

• Download Capacity: 458.487 Mbps
• Download Responsiveness: Medium 

Execution Duration: 0h:0m:39s
macOS Computer Information (0.0.2)

Description

Outputs macOS version, Serial Number, Uptime, Pending Updates and jamf binary status

#!/bin/zsh

# macOS Computer Information (0.0.2)
# (Estimated Duration: 0h:0m:5s)

echo -e "\n\n\n###\n# macOS Computer Information (0.0.2)\n# (Estimated Duration: 0h:0m:5s)\n###"

# Initialize SECONDS
SECONDS="0"

# General Computer Information Variables
macOSproductVersion="$( sw_vers -productVersion )"
macOSbuildVersion="$( sw_vers -buildVersion )"
serialNumber=$( ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformSerialNumber/{print $4}' )

# Uptime
lastBootTime=$( sysctl kern.boottime | awk -F'[ |,]' '{print $5}' )
currentTime=$( date +"%s" )
upTimeRaw=$((currentTime-lastBootTime))
upTimeMin=$((upTimeRaw/60))
upTimeHours=$((upTimeMin/60))
uptimeDays=$( uptime | awk '{ print $4 }' | sed 's/,//g' )
uptimeNumber=$( uptime | awk '{ print $3 }' | sed 's/,//g' )

if [[ "${uptimeDays}" = "day"* ]]; then
    if [[ "${uptimeNumber}" -gt 1 ]]; then
        uptimeHumanReadable="${uptimeNumber} (days)"
    else
        uptimeHumanReadable="${uptimeNumber} (day)"
    fi
elif [[ "${uptimeDays}" == "mins"* ]]; then
    uptimeHumanReadable="${uptimeNumber} (mins)"
else
    uptimeHumanReadable="${uptimeNumber} (HH:MM)"
fi

# General Computer Information Output
echo "• macOS ${macOSproductVersion} (${macOSbuildVersion})"
echo "• Serial Number: ${serialNumber}"
echo "• Uptime: ${uptimeHumanReadable}"

# Pending Software Updates
availableUpdates=$( defaults read /Library/Preferences/com.apple.SoftwareUpdate.plist LastRecommendedUpdatesAvailable )
if [ "$availableUpdates" != "0" ]; then
    echo "• Pending Software Updates: $( /usr/libexec/mdmclient AvailableOSUpdates )"
else
    echo "• Pending Software Updates: ${availableUpdates}"
fi

# Jamf binary-related Variables
jamfVersion=$( /usr/local/bin/jamf -version | cut -d "=" -f2 )
jamfPid=$( pgrep -a "jamf" | head -n 1 )
if [[ -n "${jamfPid}" ]]; then
    jamfPidDuration=$( ps -ao etime= "${jamfPid}" )
    if [[ "${jamfPidDuration}" == *"-"* ]]; then
        jamfPidDays=$( ps -ao etime= "${jamfPid}" | cut -d "-" -f1 )
        echo "• Jamf ${jamfVersion} binary PID [${jamfPid}] running for ${jamfPidDays} days"
        ps -p "$jamfPid"
        echo "  Please run the 'macOS jamf Binary Kick-start' script"
    else
        echo "• Jamf ${jamfVersion} binary PID [${jamfPid}] hasn't been running more than a day"
        ps -p "$jamfPid"
    fi
else
    echo "• Jamf ${jamfVersion} binary not running"
fi

echo -e "\nExecution Duration: $(printf '%dh:%dm:%ds\n' $((SECONDS/3600)) $((SECONDS%3600/60)) $((SECONDS%60)))"

Sample Output

###
# macOS Computer Information (0.0.2)
# (Estimated Duration: 0h:0m:5s)
###

• macOS 14.5 (23F79)
• Serial Number: Q********1
• Uptime: 4 (days)
• Pending Software Updates: === OS Update Item ===
Product Key:               MSU_UPDATE_23G93_patch_14.6.1_minor
Title:                     macOS Sonoma 14.6.1
Version:                   14.6.1 <Build: 23G93> <PMV: 14.6.1>
Deferred:                  no  (Date: )
Tags:                      (null)
MacOSUpdate:               YES
MSU:                       YES  (Major: no  Full: no  DL: no  label: macOS Sonoma 14.6.1-23G93)
Splat:                     no  <(null)> (Revoked: no)
IsMacOSUpdate():           YES
Available updates (install debug profile for more details): (
        {
        AllowsInstallLater = 1;
        AppIdentifiersToClose =         (
        );
        Build = 23G93;
        DownloadSize = 2191465447;
        HumanReadableName = "macOS Sonoma 14.6.1";
        HumanReadableNameLocale = "en-US";
        IsConfigDataUpdate = 0;
        IsCritical = 0;
        IsFirmwareUpdate = 0;
        IsSecurityResponse = 0;
        ProductKey = "MSU_UPDATE_23G93_patch_14.6.1_minor";
        RequiresBootstrapToken = 1;
        RestartRequired = 1;
        SupplementalBuildVersion = 23G93;
        Version = "14.6.1";
    }
)
• Jamf 11.7.1-t1721056075 binary PID [668] running for 04 days
  PID TTY           TIME CMD
  668 ??         0:39.14 /usr/local/jamf/bin/jamf policy -event CLIENT_CHECKIN -stopConsoleLogs
  Please run the 'macOS jamf Binary Kick-start' script

Execution Duration: 0h:0m:3s
macOS LaunchDaemons & LaunchAgents (0.0.4)

Description

Lists LaunchDaemons and LaunchAgents both system-wide and for the last logged-in user

#!/bin/zsh

# macOS LaunchDaemons & LaunchAgents (0.0.4)
# (Estimated Duration: 0h:0m:0s)

echo -e "\n\n\n###\n# macOS LaunchDaemons & LaunchAgents (0.0.4)\n# (Estimated Duration: 0h:0m:0s)\n###"

# Initialize SECONDS
SECONDS="0"

echo -e "\nSystem LaunchDaemons:"
ls -ld /Library/LaunchDaemons/*

echo -e "\n\n\nSystem LaunchAgents:"
ls -ld /Library/LaunchAgents/*

lastUser=$( defaults read /Library/Preferences/com.apple.loginwindow.plist lastUserName )
echo -e "\n\n\nUser's LaunchAgents:"
ls -ld /Users/$lastUser/Library/LaunchAgents/*
if [[ -f "/Users/$lastUser/Library/LaunchAgents/com.mmsprot.agent.plist" ]]; then
    /usr/bin/plutil -p "/Users/$lastUser/Library/LaunchAgents/com.mmsprot.agent.plist"
fi

echo -e "\nExecution Duration: $(printf '%dh:%dm:%ds\n' $((SECONDS/3600)) $((SECONDS%3600/60)) $((SECONDS%60)))"

Sample Output

###
# macOS LaunchDaemons & LaunchAgents (0.0.4)
# (Estimated Duration: 0h:0m:0s)
###

System LaunchDaemons:
-rw-r--r--  1 root  wheel  474 Feb 26  2024 /Library/LaunchDaemons/com.a***.plist
-rw-r--r--  1 root  wheel  486 Feb 26  2024 /Library/LaunchDaemons/com.b***.plist
-rw-r--r--  1 root  wheel  564 Aug 30 14:08 /Library/LaunchDaemons/com.c***.plist



System LaunchAgents:
-rw-r--r--  1 root  wheel  577 Aug 30 13:42 /Library/LaunchAgents/com.a***.plist
-rw-r--r--  1 root  wheel  562 Jun  5 15:49 /Library/LaunchAgents/com.crowdstrike.falcon.UserAgent.plist
-rw-r--r--  1 root  wheel  523 Aug 30 13:37 /Library/LaunchAgents/com.m***.plist



User's LaunchAgents:
-rw-r--r--  1 dan  staff  640 Aug 31 22:04 /Users/dan/Library/LaunchAgents/com.a***.plist

Execution Duration: 0h:0m:0s
macOS Update Inventory via Daily Update Inventory policy (0.0.1)

Description

Updates the Jamf Pro server with this Mac’s current inventory data via the “Daily Update Inventory” policy. (Observation of No policies were found for the ID 1. indicates the policy has executed as expected in the last 24 hours.)

#!/bin/zsh

# macOS Update Inventory via "Daily Update Inventory" policy (0.0.1)
# (Estimated Duration: 0h:0m:37s)

echo -e "\n\n\n###\n# macOS Update Inventory via "Daily Update Inventory" policy (0.0.1)\n# (Estimated Duration: 0h:0m:37s)\n###\n"

# Initialize SECONDS
SECONDS="0"

# Jamf binary-related Variables
jamfVersion=$( /usr/local/bin/jamf -version | cut -d "=" -f2 )
jamfPid=$( pgrep -a "jamf" | head -n 1 )
if [[ -n "${jamfPid}" ]]; then
    echo "• jamf ${jamfVersion} binary already running …"
    ps -p "${jamfPid}"
    echo "• Killing  ${jamfPid} …"
    kill "${jamfPid}"
fi

echo "• Update Inventory via 'Daily Update Inventory' policy …"
/usr/local/bin/jamf policy -id 1 -verbose

echo -e "\nExecution Duration: $(printf '%dh:%dm:%ds\n' $((SECONDS/3600)) $((SECONDS%3600/60)) $((SECONDS%60)))"

Sample Output

###
# macOS Update Inventory via Daily Update Inventory policy (0.0.1)
# (Estimated Duration: 0h:0m:37s)
###

• Update Inventory via 'Daily Update Inventory' policy …
verbose: JAMF binary already symlinked
 verbose: Checking for an existing instance of this application...
Checking for policy ID 1...
 verbose: Checking for active ethernet connection...
verbose: No active ethernet connection found...
verbose: Removing any cached policies for this trigger.
 verbose: Parsing servers...
 verbose: The Management Framework Settings are up to date.
No policies were found for the ID 1.

Execution Duration: 0h:0m:2s
macOS Force-update Inventory via jamf binary (0.0.1)

Description

Force-updates the Jamf Pro server with this Mac’s current inventory data via the jamf binary

#!/bin/zsh

# macOS Force-update Inventory via jamf binary (0.0.1)
# (Estimated Duration: 0h:0m:37s)

echo -e "\n\n\n###\n# macOS Force-update Inventory via jamf binary (0.0.1)\n# (Estimated Duration: 0h:0m:37s)\n###\n"

# Initialize SECONDS
SECONDS="0"

# Jamf binary-related Variables
jamfVersion=$( /usr/local/bin/jamf -version | cut -d "=" -f2 )
jamfPid=$( pgrep -a "jamf" | head -n 1 )
if [[ -n "${jamfPid}" ]]; then
    echo "• jamf ${jamfVersion} binary already running …"
    ps -p "${jamfPid}"
    echo "• Killing  ${jamfPid} …"
    kill "${jamfPid}"
fi

echo "• Update Inventory via jamf binary …"
/usr/local/bin/jamf recon -verbose

echo -e "\nExecution Duration: $(printf '%dh:%dm:%ds\n' $((SECONDS/3600)) $((SECONDS%3600/60)) $((SECONDS%60)))"

Sample Output

###
# macOS Force-update Inventory via jamf binary (0.0.1)
# (Estimated Duration: 0h:0m:37s)
###

• Update Inventory via jamf binary …
verbose: Timeout: 10
 verbose: Checking availability of https://jamfpro.company.com/...
verbose: The JSS is available.
Retrieving inventory preferences from https://jamfpro.company.com/...
Finding extension attributes...
Locating accounts...
Locating applications...
Locating hard drive information...
Locating package receipts...
Locating plugins...
Gathering application usage information from the JamfDaemon...
Searching path: /Applications
Locating hardware information (macOS 15.1.1)...
Submitting data to https://jamfpro.company.com/...
<computer_id>007</computer_id>
 verbose: Calling JamfDaemonremoveOldAppUsageLogs...
 verbose: Removing existing launchd task /Library/LaunchDaemons/com.jamfsoftware.task.bgrecon.plist...

Execution Duration: 0h:0m:27s
macOS jamf binary Kickstart (0.0.5)

Description

Kick-starts the jamf binary

#!/bin/zsh

# macOS jamf binary Kickstart (0.0.5)
# (Estimated Duration: 0h:3m:0s)

echo -e "\n\n\n###\n# macOS jamf binary Kickstart (0.0.5)\n# (Estimated Duration: 0h:3m:0s)\n###"

# Initialize SECONDS
SECONDS="0"

# Functions
restartJamfLaunchDaemon() {
  launchctl bootout system /Library/LaunchDaemons/com.jamfsoftware.task.1.plist
  launchctl bootstrap system /Library/LaunchDaemons/com.jamfsoftware.task.1.plist
  launchctl bootout system /Library/LaunchDaemons/com.jamf.management.daemon.plist
  launchctl bootstrap system /Library/LaunchDaemons/com.jamf.management.daemon.plist
}

startJamfLaunchDaemon() {
  launchctl bootout system /Library/LaunchDaemons/com.jamfsoftware.task.1.plist
  launchctl bootstrap system /Library/LaunchDaemons/com.jamfsoftware.task.1.plist
  launchctl bootout system /Library/LaunchDaemons/com.jamf.management.daemon.plist
  launchctl bootstrap system /Library/LaunchDaemons/com.jamf.management.daemon.plist
}

# Uptime
lastBootTime=$( sysctl kern.boottime | awk -F'[ |,]' '{print $5}' )
currentTime=$( date +"%s" )
upTimeRaw=$((currentTime-lastBootTime))
upTimeMin=$((upTimeRaw/60))
upTimeHours=$((upTimeMin/60))
uptimeDays=$( uptime | awk '{ print $4 }' | sed 's/,//g' )
uptimeNumber=$( uptime | awk '{ print $3 }' | sed 's/,//g' )

if [[ "${uptimeDays}" = "day"• ]]; then
    if [[ "${uptimeNumber}" -gt 1 ]]; then
        uptimeHumanReadable="${uptimeNumber} (days)"
    else
        uptimeHumanReadable="${uptimeNumber} (day)"
    fi
elif [[ "${uptimeDays}" == "mins"• ]]; then
    uptimeHumanReadable="${uptimeNumber} (mins)"
else
    uptimeHumanReadable="${uptimeNumber} (HH:MM)"
fi

echo "• Uptime: ${uptimeHumanReadable}"

# Jamf binary-related Variables
jamfVersion=$( /usr/local/bin/jamf -version | cut -d "=" -f2 )
jamfPid=$( pgrep -a "jamf" | head -n 1 )
if [[ -n "${jamfPid}" ]]; then
    jamfPidDuration=$( ps -ao etime= "${jamfPid}" )
    echo "• Jamf ${jamfVersion} binary PID [${jamfPid}] running for: ${jamfPidDuration}"
    ps -p "$jamfPid"

    if [[ -e /Library/Application\ Support/JAMF/Remote\ Assist/Uninstall ]]; then
        echo "• Removing Jamf Remote Assist …"
        sh /Library/Application\ Support/JAMF/Remote\ Assist/Uninstall
    fi

    jamfRemoteAssistVersion=$( ls /Library/Application\ Support/JAMF/JamfRemoteAssist/ 2>/dev/null )
    if [[ -n "${jamfRemoteAssistVersion}" ]]; then
        echo "• Removing Jamf Remote Assist version ${jamfRemoteAssistVersion} …"
        sh "/Library/Application Support/JAMF/JamfRemoteAssist/${jamfRemoteAssistVersion}/uninstall.sh"
    fi

    echo "• Killing 'jamf' binary …"
    /usr/bin/killall jamf

    echo "• Restarting Jamf-related LaunchDaemons …"
    restartJamfLaunchDaemon
    startJamfLaunchDaemon

    echo "• Updating jamf management …"
    /usr/local/bin/jamf manage -rebootIfNeeded -deleteLaunchdTask -verbose 2>&1

    # echo "• Updating inventory …"
    # /usr/local/bin/jamf recon -verbose 2>&1 &

    # echo "• Executing pending policies …"
    # /usr/local/bin/jamf policy -verbose 2>&1 &

    echo -e "\nPlease run the 'macOS Update Inventory via Policy' script"

else

    echo "• jamf ${jamfVersion} binary not running"

fi

echo -e "\nExecution Duration: $(printf '%dh:%dm:%ds\n' $((SECONDS/3600)) $((SECONDS%3600/60)) $((SECONDS%60)))"

Sample Output

###
# macOS jamf binary Kickstart (0.0.5)
# (Estimated Duration: 0h:3m:0s)
###

• Uptime: 1:17 (HH:MM)
• jamf 11.7.1-t1721056075 binary not running

Execution Duration: 0h:0m:0s
macOS User-friendly Reboot Prompt (0.0.4)

Description

Edit rebootDays to specify the allowed number of days before a forced reboot. The user will be prompted with the following reboot options:

  • 15 minutes
  • 30 minutes
  • 1 hour
#!/bin/bash

# macOS User-friendly Reboot Prompt (0.0.4)
# (Estimated Duration: 0h:5m:0s)
# Inspired by: https://community.jamf.com/t5/jamf-pro/jamf-helper-reboot-script-with-deferral/td-p/188511#responseChild164611

echo -e "\n\n\n###\n# macOS User-friendly Reboot Prompt (0.0.4)\n# (Estimated Duration: 0h:5m:0s)\n###"

# Number of days before reboot
rebootDays="${1:-"30"}"

# Reverse Domain Name
reverseDomainName="com.company.division"

# Initialize SECONDS
SECONDS="0"

# Date & Time Variables
lastBootRaw=$( sysctl kern.boottime | awk -F'[= |,]' '{print $6}' )
lastBootFormat=$( date -jf "%s" "$lastBootRaw" +"%d-%b-%Y" )
today=$( date +%s )
uptimeDays=$(( (today - lastBootRaw) / 86400 ))
icon="/usr/local/company/icons/Restart.png"
echo -e "\n• Days since last reboot: ${uptimeDays}"


# If days of uptime is less than specified reboot days, exit.
if [[ ${uptimeDays} -le ${rebootDays} ]] ; then

    echo -e "\nExiting: ${uptimeDays} Uptime (days) is less than or equal to ${rebootDays}"
    echo -e "\nExecution Duration: $(printf '%dh:%dm:%ds\n' $((SECONDS/3600)) $((SECONDS%3600/60)) $((SECONDS%60)))"
    exit 0

fi

function cleanUp(){
    # Remove reboot-related files
    /bin/echo "#!/bin/bash
    # Remove reboot-related files
    /bin/rm -f /Library/LaunchDaemons/${reverseDomainName}.rebootDelay.plist
    /bin/rm -f /Library/LaunchDaemons/${reverseDomainName}.rebootDelayWarning.plist
    /bin/rm -f /usr/local/company/scripts/rebootWarning.sh
    /bin/launchctl remove ${reverseDomainName}.rebootDelay
    /bin/launchctl remove ${reverseDomainName}.rebootDelayWarning
    /bin/sleep 2
    ## Update Device Inventory
    /usr/local/jamf/bin/jamf recon
    ## Remove LaunchDaemon
    /bin/rm -f /Library/LaunchDaemons/${reverseDomainName}.rebootCleanup.plist
    ## Remove Script
    /bin/rm -f /usr/local/company/scripts/rebootCleanup.sh
    exit 0" > /usr/local/company/scripts/rebootCleanup.sh

    # Set permission on the file just created
    /usr/sbin/chown root:admin /usr/local/company/scripts/rebootCleanup.sh
    /bin/chmod 755 /usr/local/company/scripts/rebootCleanup.sh

# rebootCleanup LaunchDaemon
cat << EOF > /Library/LaunchDaemons/${reverseDomainName}.rebootCleanup.plist
<?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>${reverseDomainName}.rebootCleanup</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>-c</string>
        <string>/usr/local/company/scripts/rebootCleanup.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>
EOF

    # Set permission on the file just created
    /usr/sbin/chown root:wheel /Library/LaunchDaemons/${reverseDomainName}.rebootCleanup.plist
    /bin/chmod 644 /Library/LaunchDaemons/${reverseDomainName}.rebootCleanup.plist
}

function jamfhelper(){
/Library/Application\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper \
-windowType utility \
-title "Church Security Required Reboot [KB0117342]" \
-description "This computer was last restarted ${lastBootFormat}.

Church Security requires computers to be rebooted every ${rebootDays} days. (See KB0117342.)

Click \"Restart Now\" or choose a delay option within the time specified below. (You will receive a five-minute warning with any delay option.)" \
-icon "${icon}" \
-timeout "60" \
-countdown \
-button1 "Delay" \
-button2 "Restart Now" \
-showDelayOptions "900, 1800, 3600" # 15 minutes, 30 minutes, 1 hour
}

# variables
result=$( jamfhelper )
delayint=$( echo "${result}" | /usr/bin/sed 's/.$//' )
warndelayint=$( expr ${delayint} - 300 )
defercal=$(($(/bin/date +%s) + delayint))
hour=$( /bin/date -j -f "%s" "${defercal}" "+%H" )
minute=$( /bin/date -j -f "%s" "${defercal}" "+%M" )
warndefercal=$(($(/bin/date +%s) + warndelayint))
warnhour=$( /bin/date -j -f "%s" "${warndefercal}" "+%H" )
warnminute=$( /bin/date -j -f "%s" "${warndefercal}" "+%M" )

# Write LaunchDaemon populated with variables from jamfHelper output
function delay(){
/bin/cat <<EOF > /Library/LaunchDaemons/${reverseDomainName}.rebootDelay.plist
<?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>${reverseDomainName}.rebootDelay</string>
    <key>ProgramArguments</key>
    <array>
        <string>reboot</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>$hour</integer>
        <key>Minute</key>
        <integer>$minute</integer>
    </dict>
</dict>
</plist>
EOF
}

function warndelay(){
/bin/cat <<EOF > /Library/LaunchDaemons/${reverseDomainName}.rebootDelayWarning.plist
<?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>${reverseDomainName}.rebootDelayWarning</string>
    <key>ProgramArguments</key>
    <array>
        <string>sh</string>
        <string>/usr/local/company/scripts/rebootWarning.sh</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>$warnhour</integer>
        <key>Minute</key>
        <integer>$warnminute</integer>
    </dict>
</dict>
</plist>
EOF
}

function warnScript(){
/bin/cat <<EOF > /usr/local/company/scripts/rebootWarning.sh
#!/bin/bash

/Library/Application\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper \
-windowType utility \
-title "Church Security Required Reboot [KB0117342]" \
-description "This computer was last restarted ${lastBootFormat}.

Church Security requires computers to be rebooted every ${rebootDays} days. (See KB0117342.)

This computer will restart in the time indicated below.

" \
-timeout 300 \
-countdown \
-lockHUD \
-icon "${icon}" \
-button1 "OK"

EOF
}

function finalPrep(){
# ScriptLog "Calling the finalPrep function ..."
# Unload LaunchDaemons
# shellcheck disable=SC2143
if [[ $( /bin/launchctl list | grep ${reverseDomainName}.reboot ) ]]; then
    /bin/launchctl bootout system /Library/LaunchDaemons/${reverseDomainName}.rebootDelay.plist
    /bin/launchctl bootout system /Library/LaunchDaemons/${reverseDomainName}.rebootDelayWarning.plist
fi

# Set ownership on delay LaunchDaemon
chown root:wheel /Library/LaunchDaemons/${reverseDomainName}.rebootDelay.plist
chmod 644 /Library/LaunchDaemons/${reverseDomainName}.rebootDelay.plist

# Set ownership on delaywarning LaunchDaemon
chown root:wheel /Library/LaunchDaemons/${reverseDomainName}.rebootDelayWarning.plist
chmod 644 /Library/LaunchDaemons/${reverseDomainName}.rebootDelayWarning.plist

# Load LaunchDaemons
/bin/launchctl bootstrap system /Library/LaunchDaemons/${reverseDomainName}.rebootDelay.plist
/bin/launchctl bootstrap system /Library/LaunchDaemons/${reverseDomainName}.rebootDelayWarning.plist

# Start LaunchDaemons
/bin/launchctl start /Library/LaunchDaemons/${reverseDomainName}.rebootDelay.plist
/bin/launchctl start /Library/LaunchDaemons/${reverseDomainName}.rebootDelayWarning.plist
}

# select action based on user input

case "$result" in
    *1 )    echo "${uptimeDays} Uptime (days); User delayed reboot until: ${hour}:${minute} local time"
            delay
            warndelay
            warnScript
            finalPrep
            cleanUp
            echo -e "\nExecution Duration: $(printf '%dh:%dm:%ds\n' $((SECONDS/3600)) $((SECONDS%3600/60)) $((SECONDS%60)))"
            ;;
    *2 )    reboot
            echo "User clicked \"Restart Now\""
            echo -e "\nExecution Duration: $(printf '%dh:%dm:%ds\n' $((SECONDS/3600)) $((SECONDS%3600/60)) $((SECONDS%60)))"
            ;;
esac

Sample Output

###
# macOS User-friendly Reboot Prompt (0.0.3)
# (Estimated Duration: 0h:5m:0s)
###

• Days since last reboot: 47
47 Uptime (days); User delayed reboot until: 07:31 local time
Execution Duration: 0h:0m:42s

Posted in CrowdStrike Falcon, Scripts, SecOps, Tips & Tricks

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.