EA for uptime check in days/minutes

kquan
Contributor

Hey Guys,

Just wondering what you guys are using for EA on checking uptime on the macs. I did find this :https://www.jamf.com/jamf-nation/discussions/10009/uptime-or-last-shutdown-restart

Curious to see if you guys have an EA that works to report back in Days/Minutes and works on macOS Sierra!

1 ACCEPTED SOLUTION

jmahlman
Valued Contributor

Our System Uptime EA looks like this:

#!/usr/bin/python2.7
import plistlib
import subprocess

data = subprocess.check_output(['/usr/sbin/system_profiler', 'SPSoftwareDataType', '-xml', '-detailLevel', 'mini'])
plist = plistlib.readPlistFromString(data)
uptime_string = plist[0]['_items'][0]['uptime']
time_list = uptime_string.split('up ')[1].split(':')
time_stamp = '{} d {} h {} m {} s'.format(*time_list)

print("<result>{}</result>".format(time_stamp))

And it looks like this in inventory: 66d92816e0b340908afe5cbcc3d3df04

View solution in original post

7 REPLIES 7

jmahlman
Valued Contributor

Our System Uptime EA looks like this:

#!/usr/bin/python2.7
import plistlib
import subprocess

data = subprocess.check_output(['/usr/sbin/system_profiler', 'SPSoftwareDataType', '-xml', '-detailLevel', 'mini'])
plist = plistlib.readPlistFromString(data)
uptime_string = plist[0]['_items'][0]['uptime']
time_list = uptime_string.split('up ')[1].split(':')
time_stamp = '{} d {} h {} m {} s'.format(*time_list)

print("<result>{}</result>".format(time_stamp))

And it looks like this in inventory: 66d92816e0b340908afe5cbcc3d3df04

kquan
Contributor

thanks @jmahlman ! works like a charm!

jmahlman
Valued Contributor

No problemo.

If you want more accurate uptime, you'll have to have something run every check-in instead of Inventory time. We haven't found the need for that but if you do something like that post it here for reference.

mm2270
Legendary Contributor III

Just to throw in another variation, here's one that I extracted from another script I built. We don't actually use this for our uptime EA, preferring instead to use a straight hours value, so we can use it in Smart Groups with greater than/less than if needed.

This looks like a long script, but it actually only takes about .02 seconds to run

real    0m0.020s
user    0m0.006s
sys 0m0.011s

The script is below. It uses the boot time from sysctl.kern.boottime and compares against the current unix time and does a bunch of calculations from there.

#!/bin/bash

lastBootTime=$(sysctl kern.boottime | awk -F'[ |,]' '{print $5}')   ## Raw unix time in seconds of last boot up
currentTime=$(date +"%s")                                           ## Current time in unix seconds
upTimeRaw=$((currentTime-lastBootTime))                             ## Calculation of difference between boot and current time ( total time up in seconds )
upTimeMin=$((upTimeRaw/60))                                         ## Calculation of uptime in minutes total ( uptime in seconds div by 60 )
upTimeHours=$((upTimeMin/60))                                       ## Calculation of uptime in hours total ( uptime in minutes div by 60 )
upTimeDays=$((upTimeHours/24))                                      ## Calculation of uptime in whole days total ( uptime in hours  div by 24 )
minusMinutes=$((((upTimeDays*24))*60))                              ## Total minutes up in whole days ( [uptime in whole days x 24] x 60 minutes )
remainingMin=$((upTimeMin-minusMinutes))                            ## Calculation of remaining minutes to subtract
remainingHrs=$((remainingMin/60))                                   ## Calculation of remaining hours to subtract
minusHours=$((upTimeHours-remainingHrs))

## Figure out minutes value for uptime display
total1=$((upTimeDays*24*60))
total2=$((remainingHrs*60))
minusMinutes2=$((total1+total2))
remainingMinFin=$((upTimeMin-minusMinutes2))

UptimeThreshold1alt=$((UptimeThreshold1-1))
UptimeThreshold2alt=$((UptimeThreshold2-1))

if [ "$upTimeDays" == "1" ]; then
    daysText="Day"
else
    daysText="Days"
fi

if [ "$remainingHrs" == "1" ]; then
    hrsText="Hour"
else
    hrsText="Hours"
fi

if [ "$remainingMinFin" == "1" ]; then
    minsText="Minute"
else
    minsText="Minutes"
fi

echo "<result>$upTimeDays $daysText, $remainingHrs $hrsText, $remainingMinFin $minsText</result>"

How it displays as an example:

3 Days, 10 Hours, 48 Minutes

As @jmahlman mentioned, this will only be as accurate as your last full inventory collection, so it could be off by quite a few hours in either direction. Just something to keep in mind, and true with any uptime EA, no matter what you use.

robertliebsch
Contributor

nm. Extension Attribute.

tlarkin
Honored Contributor

I built one that just returns the value in days, if it is under 1 day it will return 0.

#!/usr/bin/python

'''
This will track last reboot time and flag systems that have rebooted on their own
'''

# import modules

import subprocess
import time

# global varibles if any


# start functions

def get_last_reboot():
    '''use system control binary to read reboot time from kernel
    use sub process to grab that'''
    cmd = ['sysctl', '-h', 'kern.boottime']
    ps = subprocess.check_output(cmd) 
    output = ps.strip()
    output_list = output.split()
    epoch_reboot_date = output_list[4].replace(',','')
    return epoch_reboot_date

def diff_times(reboot_time):
    '''get current epoch time to get a difference of seconds a system has been running'''
    current_epoch_time = int(time.time())
    epoch_since_reboot = current_epoch_time - int(reboot_time)
    return epoch_since_reboot

def get_days_reboot(seconds):
    '''return days since reboot'''
    days = int(seconds) / 86400
    return days

def run():
    reboot = get_last_reboot()
    reboot_diff = diff_times(reboot)
    reboot_days = get_days_reboot(reboot_diff)
    print "<result>%s</result>" % reboot_days

run()

output:

/usr/bin/python /Users/tlarkin/IdeaProjects/python/reboot_check.py
<result>10</result>

Process finished with exit code 0

My EA is labeled: Days Since Last Reboot

EDIT -

The reason I went with an integer based on days is that makes it easier to scope things and report on things. At a high level if something needs a sanity check (like we patch/update/deploy something and ask an end user to nicely reboot) I would rather deal with how many days have passed since a reboot occurred.

brunerd
Contributor

I too like the simplicity of reporting Days only and having the EA type be an integer which allows for less-than/greater than scoping, here's that same thing in shell only:

#!/bin/bash
#Joel Bruner
#Jamf EA - Uptime Days (integer)

#get uptime output
uptimeOutput=$(uptime)

#detect "day" by removal and then string comparison, awk gets number of days between "up " and  " day"
[ "${uptimeOutput/day/}" != "${uptimeOutput}" ] && uptimeDays=$(awk -F "up | day" '{print $2}' <<< "${uptimeOutput}")

#less than a day echo 0
echo "<result>${uptimeDays:-0}</result>"