Uptime or Last Shutdown/Restart

TomDay
Release Candidate Programs Tester

I recently applied a policy to a Smart Group that installs some software and then restarts the computers. Checking the logs, I see the software installed properly but no mention of reboot on any so I am thinking that shutdown or restart doesn't get logged? If not, wondering if there is a custom attribute or something else that I could use to track uptime or last shutdown/restart on these computers or even all managed clients?

1 ACCEPTED SOLUTION

jhbush
Valued Contributor II

Last Reboot

#!/bin/bash

lastReboot=`who -b | awk '{print $3" "$4}'`

echo "<result>"$lastReboot"</result>"

exit 0

Uptime in Hours

#!/bin/sh

DAYS="days,"
HRS=" hrs"

DAYScheck=$(uptime | awk {'print $4'})

if [ $DAYScheck = "$DAYS" ]; then

result=$(uptime | awk {'print $3.$4.$5'} | sed 's/,/ /g' | sed 's/d/ d/g')

        echo "<result>$result$HRS</result>"

        else

result=$(uptime | awk {'print $3'} | sed 's/,//g')

        echo "<result>$result$HRS</result>"
fi

exit

Hope that helps.

View solution in original post

19 REPLIES 19

jhbush
Valued Contributor II

Last Reboot

#!/bin/bash

lastReboot=`who -b | awk '{print $3" "$4}'`

echo "<result>"$lastReboot"</result>"

exit 0

Uptime in Hours

#!/bin/sh

DAYS="days,"
HRS=" hrs"

DAYScheck=$(uptime | awk {'print $4'})

if [ $DAYScheck = "$DAYS" ]; then

result=$(uptime | awk {'print $3.$4.$5'} | sed 's/,/ /g' | sed 's/d/ d/g')

        echo "<result>$result$HRS</result>"

        else

result=$(uptime | awk {'print $3'} | sed 's/,//g')

        echo "<result>$result$HRS</result>"
fi

exit

Hope that helps.

TomDay
Release Candidate Programs Tester

Works perfectly! Thx @jhbush1973

asditsupport
New Contributor III

I'm trying to put this is as an Extension Attribute but it doesn't display the result. Any ideas?

TomDay
Release Candidate Programs Tester

Run recon on your test machine, should see it then

mm2270
Legendary Contributor III

Correct. As with any Extension Attribute that gets populated from inventory, you won't see anything until your Macs begin submitting new inventory and run the script. It actually brings up an important point on something like an "uptime" EA. The information will only be as good as the last inventory date, which could be only minutes before or as much as a day before (or more) depending on your setup. Just something to keep in mind.

asditsupport
New Contributor III

@mm2270 That's great info! I had overlooked on the update inventory policy we have set up. I've edited it to get the results on a more timely manner. Now I realize that it wasn't a scripting issue
Thanks!

mm2270
Legendary Contributor III

Just wanted to post an alternative Last Reboot EA. This one will output it in a date format that can be used in a "Date format" Extension Attribute the way Casper expects it to be. So you could use a search like "Before" or "After" a certain date, or something like "In the last X days" and it should work.

#!/bin/bash

echo "<result>$(date -jf "%s" "$(sysctl kern.boottime | awk -F'[= |,]' '{print $6}')" +"%Y-%m-%d %T")</result>"

Orleck
New Contributor

@mm2270 Many thanks, this is exactly what I was in need of, after the tenth syntax error I remember someone, like you, had probably already found a good (and working) method for this! :) Thanks!

robby_c137
New Contributor III

Love it, @mm2270. Thanks.

jalcorn
Contributor II

you helped me out with this twice now @TomDay

mm13
New Contributor II

Hah; I'm getting some responses like " 6 days 46 hours". Anybody have any idea why that's happening?

easyedc
Valued Contributor II

Not trying to be snarky, but @ken.cieszykowski What result are you trying to get? Sounds like an uptime report to me.

mm2270
Legendary Contributor III

Well, unless he lives on another planet, I'd say that the "46 Hours" bit is the part that's head scratching, y'know ;-)
Sounds like a math problem to me, but I haven't looked close enough to see why they would be.

easyedc
Valued Contributor II

@mm2270 Don't mind me. I've been doing some wood working lately and breathing in a large amount of chemicals from staining furniture. I read that and my brain said 46 minutes... Maybe I should open a window here... Moving along now...

mm13
New Contributor II

Hah, thanks for explaining @mm2270

I'm trying to set some Smart Groups based on this extension; but the hours report > 24 is difficult.

Basically, I changed the EA to be an integer; and then set the criteria of the group to be "System Uptime" is more than 30. Running into a wall here since it's pulling things such as '31 hours' into the group, and so on.

Please let me know if anybody has any advice or can help with this!

Cheers

tlarkin
Honored Contributor

I also use sysctl to track this, or at least I found it the easiest to parse. Parsing uptime or last reboot was a bit more of a pain to covert into something you can return a value of just days to.

bash example:

sysctl kern.boottime | awk '{ print $5 }' | sed 's/,//g'

that will return epoch time since reboot in bash

Then compare it to current epoch time with date "+%s"

Python example might be:

#get last reboot epoch time
>>> import subprocess
>>> cmd = ['sysctl', '-h', 'kern.boottime']
>>> ps = subprocess.check_output(cmd)
>>> output = ps.strip().split()[4].replace(',','')
>>> print output
1485380162

# get current epoch time in Python
>>> import time
>>> epoch = int(time.time())
>>> print epoch
1485480972

I personally like the epoch time stamps because they are easier to do the math in my opinion then just divide by 86400 to get seconds into days conversion. As you can see I recently rebooted so the current epoch time is not too far off the output of sysctl which is expected. Python will return 0 if it is less than one (like a fraction or float). Looks like bash internals also return 0 if the result is less than 1. If you are living in the future and actually have Python 3.x deployed to your Mac fleet I think Python actually has a built in uptime module

bash internal division example:

echo $(( 6000 / 86400 ))
0

-Tom

eseok
New Contributor II

This is not my code but was from the CCA class. I know this was already answered but this was more elegant and you can change the data type to be Date which looks better :)

#!/bin/bash

# Find the last time reboot time
# sysctl -a lists all values for the kernel state
# A specific key can be specified
# sysctl kern.boottime lists the last time the computer was boot time in human format and epoch time. Neither are appropriate for the JSS

#######################################
# Print the boottime, capturing the fifth field (awk uses white space as default field separator), removing the trailing comma
#######################################

boottime=$(sysctl kern.boottime | awk '{print $5}' | tr -d ,)

#######################################
# The date command will list the current date, set system time, or reformat dates
# Time can be formatted with + for example the following will show the date in the format of YEAR-MONTH-DATE
# date +%Y-%m-%d
#
# The date command can be set to format one date to another, the syntax is as follows:
# date -jf  %s $DATETOFORMAT +$NEWFORMAT
#
# To change epoch time 1492527424 (2017 April 18, 10:57:04 A.M.) to a format acceptable for the JSS:
#
# date -jf %s 1492527424 +%F %T
# The j flag says do not try to set the date, this allows you to use the -f flag in addition to the + option to convert one date format to another
# %s is the input format (epoch time), followed by the time to convert and the output format
#######################################
# Format the boottime for the JSS
#######################################

formattedTime=$(date -jf %s "$boottime" +%F %T)

#######################################
# To return a value to the JSS in Extension Attributes it must be wrapped in result tags
#######################################

echo "<result>$formattedTime</result>"

#######################################
# A list of the formatting options for the date command
# %% a literal %
# %a locale's abbreviated weekday name (e.g., Sun)
# %A locale's full weekday name (e.g., Sunday)
# %b locale's abbreviated month name (e.g., Jan)
# %B locale's full month name (e.g., January)
# %c locale's date and time (e.g., Thu Mar 3 23:05:25 2005)
# %C century; like %Y, except omit last two digits (e.g., 21)
# %d day of month (e.g, 01)
# %D date; same as %m/%d/%y
# %e day of month, space padded; same as %_d
# %F full date; same as %Y-%m-%d
# %g last two digits of year of ISO week number (see %G)
# %G year of ISO week number (see %V); normally useful only with %V
# %h same as %b
# %H hour (00..23)
# %I hour (01..12)
# %j day of year (001..366)
# %k hour ( 0..23)
# %l hour ( 1..12)
# %m month (01..12)
# %M minute (00..59)
# %n a newline
# %N nanoseconds (000000000..999999999)
# %p locale's equivalent of either AM or PM; blank if not known
# %P like %p, but lower case
# %r locale's 12-hour clock time (e.g., 11:11:04 PM)
# %R 24-hour hour and minute; same as %H:%M
# %s seconds since 1970-01-01 00:00:00 UTC
# %S second (00..60)
# %t a tab
# %T time; same as %H:%M:%S
# %u day of week (1..7); 1 is Monday
# %U week number of year, with Sunday as first day of week (00..53)
# %V ISO week number, with Monday as first day of week (01..53)
# %w day of week (0..6); 0 is Sunday
# %W week number of year, with Monday as first day of week (00..53)
# %x locale's date representation (e.g., 12/31/99)
# %X locale's time representation (e.g., 23:13:48)
# %y last two digits of year (00..99)
# %Y year
# %z +hhmm numeric timezone (e.g., -0400)
# %:z +hh:mm numeric timezone (e.g., -04:00)
# %::z +hh:mm:ss numeric time zone (e.g., -04:00:00)
# %:::z numeric time zone with : to necessary precision (e.g., -04, +05:30)
# %Z Time Zone (EDT)

Hamlin
New Contributor

Just to add an alternate method to the discussion,

JSS Formatted in one command by pulling from the start time of PID 1 (launchd)

date -jf '%a %b %d %T %Y' "`ps -p 1 -o lstart=`" +%F %T

jkeller13
New Contributor III

I wrote ours slightly different in case anyone has a use for it:

#!/bin/bash

FORMAT_OF_TIME="`uptime | awk '{print $4}' | sed 's/,//g'`"

case $FORMAT_OF_TIME in
    days )
        CURRENT_UPTIME="`uptime | awk '{print $3 "days"}'`"
        ;;
    mins )
        CURRENT_UPTIME="`uptime | awk '{print $3 "mins"}'`"
        ;;
    secs )
        CURRENT_UPTIME="`uptime | awk '{print $3 "secs"}'`"
        ;;
    * )
        CURRENT_UPTIME="`uptime | awk '{print $3}' | sed 's/,//g' | awk -F ':' '{print $1 "hrs", $2 "mins"}'`"
        ;;
esac

PROCESSED_UPTIME="${CURRENT_UPTIME} (Last checked: `date`)"

echo "<result>${PROCESSED_UPTIME}</result>"

exit 0