Uptime Extension Attribute script help needed.

quedayone
Contributor

Greetings JAMF Nationers
I am looking to create a uptime Extension Attribute.
I have created an Extension Attribute with the data type: Integer
Input Type: Populated by Script
Mac OS C Script Contentes:

#!/bin/sh
echo -n"<result>"
uptime
"</result>"
exit 0

This results in:
23:40 up 14:02, 2 users, load averages: 0.50 0.35 0.35 /private/tmp/extensionAttributeScript: line 7:

I would like a simple number in days, so I need to edit the result.
Something like:
uptime | awk -F'( |,)' '{print $2}'
Results in:
up 45 mins or up 4 days
How do I get a simple number in days?

Thanks in advance for any help!

1 ACCEPTED SOLUTION

acidprime
New Contributor III
#!/bin/bash
# Commands required by this script
declare -x awk="/usr/bin/awk"
declare -x sysctl="/usr/sbin/sysctl"
declare -x perl="/usr/bin/perl"

declare -xi DAY=86400
declare -xi EPOCH="$($perl -e "print time")"
declare -xi UPTIME="$($sysctl kern.boottime |
                        $awk -F'[= ,]' '/sec/{print $6;exit}')"

declare -xi DIFF="$(($EPOCH - $UPTIME))"

if [ $DIFF -le $DAY ] ; then
        echo "<result>1</result>"
else
        echo "<result>$(($DIFF / $DAY))</result>"
fi

https://gist.github.com/2046271

Here is an epoch style calculation using sysctl

View solution in original post

22 REPLIES 22

jarednichols
Honored Contributor

try:

uptime | cut -d "," -f 1 | awk '{print $3,$4;}'

You could go straight from uptime into awk, but that'll leave you with a trailing ",". You could sed it out, but I think this is a bit easier to understand.

Result:

uptime
11:32  up 35 mins, 3 users, load averages: 2.93 2.93 2.34

With some cut and awk:

uptime | cut -d "," -f 1 | awk '{print $3,$4;}'
35 mins

stevewood
Honored Contributor II
Honored Contributor II

I like Jared's method, although once you have gone past an hour of uptime you would not have a $4 variable for the print command. So instead of "35 mins" for your response, you'd have something like "1:18".

If you are not concerned with anything less than 1 day in uptime, and not concerned with the "extra" time past 1 day (1 day 11:04 for example), then you could do something like this:

#!/bin/sh

days=`uptime | awk '{ print $4 }' | sed 's/,//g'`
num=`uptime | awk '{ print $3 }'`

# now check how long they've been awake
if [ $days = "days" ];

    <result>$num</result>
fi

That is part of a larger script I use to irritate users that do not restart at least every 5 days.

Steve

rockpapergoat
Contributor III

if this appeals to you, you can install facter (part of puppet but can be used standalone) and get 'facter uptime_days' to plug into your results.

http://downloads.puppetlabs.com/mac

if you use facter to generate all these system facts, you don't need to add more complexity by scripting them in an ad hoc fashion.

quedayone
Contributor

stevewood, I like your script idea.

#!/bin/sh

days=`uptime | awk '{ print $4 }' | sed 's/,//g'`
num=`uptime | awk '{ print $3 }'`

# now check how long they've been awake
if [ $days = "days" ];

    <result>$num</result>
fi

But the result I get from the JSS is:
$num

Any ideas?

Wi11

stevewood
Honored Contributor II
Honored Contributor II

Oops...there's an echo missing. Change the <result> line to this:

<result>echo $num</result>

That should do the trick.

Steve

jarednichols
Honored Contributor

+1 Steve

quedayone
Contributor
Oops...there's an echo missing. Change the <result> line to this: <result>echo $num</result> That should do the trick. Steve

Unfortunately it did not.

#!/bin/sh

days=`uptime | awk '{ print $4 }' | sed 's/,//g'`
num=`uptime | awk '{ print $3 }'`

# now check how long they've been awake
if [ $days = "days" ];

    <result>echo $num</result>
fi

Result:
Uptime: echo $num

My knowledge of scripting is obviously limited. Comparing this script to other Extension Attribute scripts it looks like they have the <result> in " like:

"<result>echo $num</result>"

And have the echo before the <result>

echo "<result>$lastUser</result>"

But I have tried booth variations to no avail.
Thoughts?

Seems like JAMF should just make something like available from a template.
:-/

rob_potvin
Contributor III
Contributor III

+1. That would be a great idea!!

stevewood
Honored Contributor II
Honored Contributor II

Well, if I had the right syntax in there for the if/then statement, it might work better. I had cut out pieces that you didn't need and missed the crucial "then":

Try this instead:

#!/bin/sh

days=`uptime | awk '{ print $4 }' | sed 's/,//g'`
num=`uptime | awk '{ print $3 }'`

# now check how long they've been awake
if [ $days = "days" ];

then
    echo "<result>$num</result>"
fi

I tested on a machine here and it gave the expected results.

Sorry about that. Guess I gotta wait until the Full Throttle energy drink kicks in before responding.....

Steve

acidprime
New Contributor III
#!/bin/bash
# Commands required by this script
declare -x awk="/usr/bin/awk"
declare -x sysctl="/usr/sbin/sysctl"
declare -x perl="/usr/bin/perl"

declare -xi DAY=86400
declare -xi EPOCH="$($perl -e "print time")"
declare -xi UPTIME="$($sysctl kern.boottime |
                        $awk -F'[= ,]' '/sec/{print $6;exit}')"

declare -xi DIFF="$(($EPOCH - $UPTIME))"

if [ $DIFF -le $DAY ] ; then
        echo "<result>1</result>"
else
        echo "<result>$(($DIFF / $DAY))</result>"
fi

https://gist.github.com/2046271

Here is an epoch style calculation using sysctl

rockpapergoat
Contributor III

how would you like your yak shaved today, sir?

mm2270
Legendary Contributor III

Nice scripts. I had done something like this a while ago, but wanted to get a more accurate picture of uptime when the Macs recon'ed, not just whether it had been more than one day. Here is the script I made. It has perhaps too many "seds", so if anyone has suggestions on a better way, I'm all ears/eyes.
Basically this will check to see if the Mac has been up for more than one day and then pull the days + hours values from uptime and clean up the output to make it more readable. If it hasn't been up for more than one day, it just pulls the hrs. It can probably be modified to check for systems only up for 1 day and some num hrs and pull that properly, but I haven't bothered with that.

This would also be a little hard to use in a SmartGroup to nag users as is, like with Steve's script, so YMMV. Maybe use both.

#!/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

quedayone
Contributor
how would you like your yak shaved today, sir?

LOL!

quedayone
Contributor

I gave the answer to acidprime as his script returned a 1 when uptime is less then one day, Steve your script returned nothing when uptime is less then one day but worked just fine when uptime was more then one day.

Thank you all for your help!
Now if you will excuse me I have some recon to run.
:-)
Getting some crazy results some over 30 days!

chris_kemp
Contributor III

Another variation that I hacked together, taking some cues from the above:

#! /bin/sh

# if $4 from `uptime` is "mins," then the system has been up for less than an hour. 
# We set $timeup to the output of $3, appending only "m".
timechk=`uptime | awk '{ print $4 }'`

if [ $timechk = "mins," ]; then
        timeup=`uptime | awk '{ print $3 "m" }'`

# if $4 is "days," then we generate a readable string from $3, $4, and $5;
elif [ $timechk = "days," ]; then

                timeup=`uptime | awk '{ print $3 $4 " " $5 }' | sed 's/days,/d/g' | sed 's/:/h /g' | sed 's/,/m/g'`

# otherwise, generate a readable string from $3.
else

                timeup=`uptime | awk '{ print $3 }' | sed 's/:/h /g' | sed 's/,/m/g'`

fi

echo "<result>$timeup</result>"

This will return a compact string suitable for display in a Search field, such as:

5d 2h 29m 12h 42m 52m

Thank you, chris_kemp! I wish everyone wrote code and comments this.  It helps people learn how to write their own scripts.

There's an old saying about writing clear, readable code:  Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.

To that, I would only add "The same goes for commenting your code."

allencreech
New Contributor II

Snook, muchas gracias senor. I needed this in a big way.

gokoudes
New Contributor III

Cheers, all, for this thread! Thanks @chris.kemp for your modified script, it's currently working well with our 10.10 machines.

sean
Valued Contributor

I'd have probably just gone with:

#!/bin/bash

RESULT=`ps -p 1 -o etime | sed -n '2p'`

echo "<result>"$RESULT"</result>"

exit 0

or if as requested you just want days:

#!/bin/bash

getDays=`ps -p 1 -o etime | grep "-" | cut -d "-" -f 1`

if [[ "$getDays" == "" ]]
then
        theDays="0 days"
else
        theDays="$getDays days"
fi

echo "<result>"$theDays"</result>"

exit 0

j_meister
Contributor II

Thanks for all your ideas, guys!

I especially like the script of @stevewood and added an else in case the uptime is less than 1 day. I tested it on Catalina and Big Sur and it seems to work.

#!/bin/sh

#grab uptime and save time in num and unit in days
days=`uptime | awk '{ print $4 }' | sed 's/,//g'`
num=`uptime | awk '{ print $3 }'`

# now check how long they've been awake; if less than one day it echoes 0
if [ $days = "days" ];

then
    echo "<result>$num</result>"

else
    echo "<result>0</result>"

fi

joethedsa
Contributor II

I'm looking for a way to create a SmartGroup with the criteria of "greater than" or "less than" for this extension attribute string.  I only have the options of "is, is not, like, not like, etc..."

Anyone have any ideas on how to get a SmartGroup to work that meets the criteria if uptime is greater than a specified "n" of days?

joethedsa
Contributor II

Never mind, I had to change the input type to "Integer" and I can now see it.  Great script by the way!