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.4) 🆕

Description

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

#!/bin/zsh

# macOS Computer Information (0.0.4)
# Outputs Computer Name, User Name, macOS version, Serial Number, Uptime, Pending Updates, `jamf` binary status and the Mac's connection to the Jamf Pro server
# (Estimated Duration: 0h:0m:5s)

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

# Initialize SECONDS
SECONDS="0"

# Last Logged-in User
lastUser=$( defaults read /Library/Preferences/com.apple.loginwindow.plist lastUserName )

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

# 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 "• Computer Name: ${computerName}"
echo "• User Name: ${lastUser}"
echo "• Serial Number: ${serialNumber}"
echo "• Operating System: macOS ${macOSproductVersion} (${macOSbuildVersion})"
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 "• Jamf Pro server connection: $( /usr/local/bin/jamf checkJSSConnection )"



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

Sample Output

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

• Computer Name: X*****-****
• User Name: dan
• Serial Number: X********7
• Operating System: macOS 14.7 (23H124)
• Uptime: 9:41 (HH:MM)
• Pending Software Updates: === OS Update Item ===
Product Key:               062-78429
Title:                     macOS Sequoia
Version:                   15.0 <Build: (null)> <PMV: (null)>
Deferred:                  no  (Date: )
Tags:                      SUBUNDLE:com.apple.InstallAssistant.macOSSequoia; CUSTOMER
MacOSUpdate:               no
MSU:                       no  (Major: no  Full: no  DL: no  label: (null))
Splat:                     no  <(null)> (Revoked: no)
IsMacOSUpdate():           no
  Major Version:           15.0
  Major BundleID:          com.apple.InstallAssistant.macOSSequoia
  Major Title:             macOS Sequoia
Ignoring IA-based installer
=== OS Update Item ===
Product Key:               MSU_UPDATE_24A335_patch_15.0_major
Title:                     macOS Sequoia 15.0
Version:                   15.0 <Build: 24A335> <PMV: 15.0>
Deferred:                  no  (Date: )
Tags:                      (null)
MacOSUpdate:               YES
MSU:                       YES  (Major: YES  Full: no  DL: no  label: macOS Sequoia 15.0-24A335)
Splat:                     no  <(null)> (Revoked: no)
IsMacOSUpdate():           YES
  Major Version:           15.0
  Major BundleID:          (null)
  Major Title:             macOS Sequoia 15.0
Available updates (install debug profile for more details): (
        {
        AllowsInstallLater = 0;
        AppIdentifiersToClose =         (
        );
        Build = 24A335;
        DownloadSize = 6624852495;
        HumanReadableName = "macOS Sequoia 15.0";
        HumanReadableNameLocale = "en-US";
        IsConfigDataUpdate = 0;
        IsCritical = 0;
        IsFirmwareUpdate = 0;
        IsMajorOSUpdate = 1;
        IsSecurityResponse = 0;
        ProductKey = "MSU_UPDATE_24A335_patch_15.0_major";
        RequiresBootstrapToken = 1;
        RestartRequired = 1;
        SupplementalBuildVersion = 24A335;
        Version = "15.0";
    }
)
• Jamf 11.9.1-t1726060704 binary not running
• Jamf Pro server connection: Checking availability
The JSS is available.

Execution Duration: 0h:0m:6s
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
macOS Forensically Sound Workstation Lockout 🆕

macOS Forensically Sound* Workstation Lockout with CrowdStrike Falcon and Jamf Pro

Designed as a possible last step before a MDM “Lock Computer” command, FSWL.bash *may aid in keeping a Mac computer online for investigation, while discouraging end-user tampering

Background

When a macOS computer is lost, stolen or involved in a security breach, the Mobile Device Management (MDM) Lock Computer command can be used as an “atomic” option to quickly bring some peace of mind to what are typically stressful situations, while the MDM Wipe Computer command can be used as the “nuclear” option.

For occasions where first forensically securing a macOS computer are preferred, the following approach may aid in keeping a device online for investigation, while discouraging end-user tampering.

Continue reading …

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