Skip to main content

So I stole the script from https://jamfnation.jamfsoftware.com/featureRequest.html?id=751 and tweaked the wording a bit.



#!/bin/sh

HELPER=`/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -icon /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/Resources/Message.png -heading "Software Updates are Available" -description "Would you like to install updates? System may need to be rebooted." -button2 "Install" -button1 "Cancel" -cancelButton "1"`


echo "jamf helper result was $HELPER";

if [ "$HELPER" == "2" ]; then
/usr/sbin/jamf policy -trigger SWUJH
exit 0
else
echo "user chose No";
exit 1
fi


I also tweaked the cancel button due to when I was using it in it's default form everything returned "user chose No" and it wouldn't run the trigger.



Now when I select install, the box disappears then immediately reappears and I have to choose install again, and then teh box stays gone, but the trigger never starts the updates.

And look at their innovative Self Service portal!! This seems familiar:



http://robotcloud.screenstepslive.com/s/2459/m/5322/l/76738-self-service


Its no secret RobotCloud is using the Casper Suite. They've been using it for years, but they've done some nice stuff around pulling data via the API and other methods into a completely custom UI. Looks nothing like the JSS, but the data is all from the JSS.



@dvasquez - as far as I know, there is no way to get around the line limitation in jamfHelper. I ran into it several times myself when doing this kind of thing a year or so back. Its partly why I chose to do my windowing in cocoaDialog. jamfHelper still has some useful modes, like fullscreen and hud, but for general user facing window stuff, I stick with cocoaDialog.


@acdesigntech][/url Hello. I am still seeing in test where when new updates are available the Helper prompt that lists updates that require an update does not come up. Instead it displays right away the "Installing Updates prompt". I made the adjustments you mentioned above. The logs do not mention anything specific or mentions successful completion. Also if I manually run the script and cancel at first sign of no list prompt then manually run it again it works correctly, I see the prompt with the list of updates. I also check the .SoftwareUpdateTimer.txt and it has been reset. Any ideas why this might still be happening. It seems to me that the script when run triggered by policy is not properly reading or locating the .SoftwareUpdateTimer.txt files when it first runs. I could be wrong though, of course.



Here is what I have:



## Once the user OKs the updates or they run automatically, reset the timer to 5
echo "5" > /Library/Application Support/JAMF/.SoftwareUpdateTimer.txt



and



if [ ! -e /Library/Application Support/JAMF/.SoftwareUpdateTimer.txt ]; then
echo "5" > /Library/Application Support/JAMF/.SoftwareUpdateTimer.txt
fi



and



let CurrTimer=$Timer-1
echo "user chose No"
echo "$CurrTimer" > /Library/Application Support/JAMF/.SoftwareUpdateTimer.txt
exit 1
fi



I also had cut off text but shortened the text lines.
Thank you for your help.


dominic, if you post your script I might be able to help you. If you copy and paste my script above into your text editor and save it up to the JSS, it should work via policy. Make sure you check your line breaks and formatting though when copy/pasting. Copying from a website sometimes screws with my formatting.


@acdesigntech I should check that. It is essentially your script edited to fit. I did not make any changes to major parts of your script. Thank you.


I hope that I am just doing something stupid, and this is a quick fix here. I just started testing this out, and I really like where this could go. My first time trying this on a machine running 10.9.1, I get the following error:



Software Updates are available, and a user is logged in. Moving to initial dialog... There are some non reboot updates available. Showing selection screen to user User chose to Cancel. Exiting...


Tried this a few times, rebooted, tried different user, but I don't see a selection box pop up, and I am certainly not hitting cancel.



Yup, it was pretty stupid. Answer was here:



The only real requirements are the 3.0 beta 7 version of cocoaDialog to be on the Mac, and a Mac with at least one available Software Update to run it against. The script exits silently if no updates are available,

Ladies and gentlemenssss.



junki is here..



https://jamfnation.jamfsoftware.com/discussion.html?id=10636


Is there's a way to tweak this script to look for a policy with manual trigger instead of looking for an updates and let user postpone installation 3 times?


I am fairly new to Casper to take it easy on me. We would like to automate the deployment of OS updates. All of the scripts in this thread great. We are running on to the following problem for the scripts we have tried so far. The message is No policies were found for the "runsoftwareupdate" trigger.



What does this mean? Do we need to create a second policy with a custom trigger value of "runsoftwareupdate"?


@ksanborn



Do we need to create a second policy with a custom trigger value of "runsoftwareupdate"?


Yes, anytime you do something like sudo jamf policy -trigger <sometriggername> The sometriggername must be set up as a policy with a custom trigger (referred to as "events" in Casper Suite 9). Generally this is enabled in place of any other triggers, like Recurring check-in, login, etc, but its possible to check more than one trigger.


Yes, a trigger would be the custom trigger for another policy. As to what that other policy would contain, I'm not sure. As you can tell from this thread, there are a lot of different ways people are approaching this so I'm not sure what that particular script you are using had in mind specifically.


@bpavlov Thank you. This helped. I don't have many computers in our testing environment that need updates still but I just ran the two policies on a computer and the update didn't install even though an update was found. Is this normal?


@ksanborn There are probably like 15 different scripts on this thread. I'm not sure if anyone can help you troubleshoot unless you let us know which script you are using and perhaps even post the script itself, even if its basically identical to what is already here, and some details on how you have this setup in your JSS. Otherwise, its going to be pretty hard to help out.


The last version I posted in this crazy long thread should still work, though would need the syntax changed to be Casper 9 compatible on the line that calls the second policy.



If you are still stuck I can give you a little bit of help, though I don't know whose script and which iteration you are using :)


All, thank you for your assistance. Everything is working now. My only question is, whether or not we can add a company logo to the message box? We already have the logo on the Macs. You guys are great. I did the following:



1.) I copied and pasted the script below in to a script in to JSS.





!/usr/bin/perl -w



use strict;



my $AVAILABLEUPDATES="";
my $CHANCESTOUPDATE=3;
my $COUNTFILE='/etc/SUScount.txt';
my $UPDATECOUNT=0;



$AVAILABLEUPDATES=/usr/sbin/softwareupdate --list;
chomp $AVAILABLEUPDATES;



printf "available updates is %s

", "$AVAILABLEUPDATES";



unless (-e $COUNTFILE){
system "/bin/echo 0 > $COUNTFILE";
}



$UPDATECOUNT=/bin/cat $COUNTFILE;
printf "update count is $UPDATECOUNT

";



If available updates contains * there are updates available



if ($AVAILABLEUPDATES=~/*/){



printf "there are updates available
";



if ($AVAILABLEUPDATES=~/(restart)|(shutsdown)/){



printf "updates need a restart
";



my $LOGGEDINUSER='';



$LOGGEDINUSER=/usr/bin/who | /usr/bin/grep console | /usr/bin/cut -d " " -f 1;
chomp $LOGGEDINUSER;



printf "value of logged in user is $LOGGEDINUSER..
";



if ($LOGGEDINUSER=~/[a-zA-Z]/) {



printf "as there is a logged in user checking count
";



my $CHANCESLEFT=$CHANCESTOUPDATE - $UPDATECOUNT;
printf "Chances left is $CHANCESLEFT
";



if ($CHANCESLEFT <= 0) {
printf "No chances left installing updates and will reboot..
";
system '/usr/sbin/jamf displayMessage -message "Your computer is installing updates and will reboot shortly."';
system "/usr/sbin/jamf policy -trigger runsoftwareupdate";
system "/bin/echo 0 > $COUNTFILE";
exit 0;
}



else {
printf "$CHANCESLEFT chances left... checking whether ok to restart
";
my $ATTEMPT = $UPDATECOUNT 1;
my $FINAL = $CHANCESTOUPDATE
1;



my $COMMAND= "'/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper' -startlaunchd -windowType utility -icon '/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/Resources/Message.png' -heading "Software Updates are Available for Your Computer" -description "This is installation attempt $ATTEMPT of $CHANCESTOUPDATE. On attempt $FINAL, updates will install automatically and your machine will restart." -button1 "Yes" -button2 "Defer" -cancelButton "2"";



my $RESPONSE = "";
$RESPONSE=system $COMMAND;



if ($RESPONSE eq "0") {
printf "
User said YES to Updates
";
system "/usr/sbin/jamf policy -trigger runsoftwareupdate";
system "/bin/echo 0 > $COUNTFILE";
exit 0;
} else {
printf "
User said NO to Updates update count is $UPDATECOUNT
";
$UPDATECOUNT=$UPDATECOUNT + 1;
system "/bin/echo $UPDATECOUNT > $COUNTFILE";
printf "
Update count is now $UPDATECOUNT
";
exit 0;
}
}
} else {
printf "no logged in user so ok to run updates
";
system "/usr/sbin/jamf policy -trigger runsoftwareupdate";
system "/bin/echo 0 > $COUNTFILE";
exit 0;
}
}
else {
printf "no restart required
";
system "/usr/sbin/jamf policy -trigger runsoftwareupdate";
system "/bin/echo 0 > $COUNTFILE";
exit 0;
}
}
else {
printf "there are no updates available
";
system "/bin/echo 0 > $COUNTFILE";
exit 0;
}



exit 0;



2.) I created two policies. One policy runs at trigger Reoccurring Check-in, Execution Frequency Once per Month, and with a scope of smart group that contains all Macs that need updates.



3.) The second policy is called RunSoftwareUpdate and has the below set with a trigger of custom runsoftwareupate




You can choose the icon to use with the -icon option when calling jamfHelper, or you can replace the icon included with jamf helper.



jamfHelper options can be viewed with this command:



/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -help

Not to bring alive an old thread, but since it was so helpful, I thought I would add something I added to make it work in an environment that has an internal SUS.



function check_corp {

CORP_URL="internalcompanyurl.com"
check_corp="False"
ping=`host -W .5 $CORP_URL`

# If the ping fails - check_corp="False"
[[ ! -z $ping ]] && check_corp="True"

# Check if we are using a test
[[ -n "$1" ]] && check_corp="$1"
}

check_corp

function reset_sus_url {
## Reset the SUS URL to whatever was being used prior to the script running.
if [ "$SUS_URL_SET" == "1" ]; then
/usr/sbin/softwareupdate --set-catalog $SUS_URL
else
/usr/sbin/softwareupdate --clear-catalog
fi
}

internal_sus_url="http://yoursus.company.com:8088/index.sucatalog"

## Check to see what SUS URL is currently being used and set a variable to call later.

SUS_URL=$(defaults read /Library/Preferences/com.apple.SoftwareUpdate CatalogURL | grep $internal_sus_url)

if [ -z "$SUS_URL" ]; then
echo "Using Apple Server"
SUS_URL_SET=""
else
echo "Using Mac Server"
SUS_URL_SET="1"
fi

## If connected ensure that VPN is not active

if [ $check_corp == "True" ]; then
vpn_status="$(ifconfig -lu | grep tun0 )"
if [ ! -z "$vpn_status" ]; then
echo "Currently Connected to VPN"
reset_sus_url
exit 100
else
/usr/sbin/softwareupdate --set-catalog $internal_sus_url
fi
else
/usr/sbin/softwareupdate --clear-catalog
fi

Late to the party, but here is what I've written to handle this. It downloads the updates before it does anything to interact with the user. It then notifies the user updates are about to be installed and waits for acknowledgement before proceeding, so the user doesn't reboot in the middle of it. Once installed, if no reboot is required it notifies the user that no reboot is required and exits, so that they may reboot as desired without causing problems. If a reboot is required, it counts down 15 minutes before doing so,giving three prompts along the way, every 5 minutes. Each one says "reboot required, will happen automatically in N minutes" and has two buttons. "Reboot now" and "OK". If the user is logged in and the screensaver is active, indicating they are AFK, the script holds in a loop until the user is available to acknowledge. This prevents users screaming because they didn't save a document they had been working on all morning. If no user is logged in, the updates install and reboot automatically if needed.



The only thing I cannot get to work is the authenticated restart for encrypted volumes. I've tried the fde* command directly and tried to kick off a policy which has that configured. Neither ever boots back into the OS, which leaves the system at the filevault login with no way to remotely access it for further updates/inventory. Suggestions on that front welcome.



# Written by Paul Dickson

## Note: JAMF policy #350 is a policy that reboots with filevault authentication


touch /tmp/su.log
chmod 777 /tmp/su.log


b=softwareupdate -al | grep "found the following" | cut -d " " -f 3-5

# If updates were found, notify the user and begin install.
if [ "$b" == "found the following" ];
then

# Marking updates as found for later script processing actions
found="yes"

# Caching/downloading updates before installation attempt
softwareupdate -ad

# Figure out if any of the updates require a restart
softwareupdate -al | grep "[restart]"
restart=$?


osascript << eof
-- Look to see if finder is running. If it is then a user is logged in, so we will notify them about what is going on.
if application "Finder" is running and application "ScreenSaverEngine" is not running then
tell application "Finder"
activate
with timeout of 301 seconds
display dialog "System updates are now being installed. Please DO NOT shutdown or reboot until notified that the update process is complete." buttons {"Understood"} giving up after 300
end timeout
end tell
end if
eof

# Installing all updates
softwareupdate -ai

fi



# If updates were found this will run the jamf policy to update inventory on the server so that the server info on the computer reflects the new updates.
if [ "$found" == "yes" ]; then /usr/local/bin/jamf recon; fi


if [ "$restart" == "0" ];
then
# A restart is required to finish updates. Notify user.

osascript << eof
-- Look to see if finder is running. If it is then a user is logged in, so we will notify them about what is going on.
set a to 1
repeat until a = 0
if application "Finder" is running and application "ScreenSaverEngine" is running then
set a to 1
--display dialog "1"
do shell script "echo 'repeat 1 waiting' >> /tmp/su.log"
delay 5
else
set a to 0
--display dialog "0"
do shell script "echo 'repeat 1 proceeding' >> /tmp/su.log"
end if
end repeat
if application "Finder" is running then
do shell script "echo 'Finder running 1' >> /tmp/su.log"
tell application "Finder"

activate
with timeout of 86400 seconds
set question to display dialog "A reboot will be performed in 15 minutes to complete system updates. Please save your work and exit all applications" buttons {"OK", "Reboot now!"} default button 1 giving up after 70000
set answer to button returned of question

if answer is equal to "Reboot Now!" then
--tell application "Finder" to restart
do shell script "jamf policy -id 350"
else
--delay 5
delay 600
if application "Finder" is running and application "ScreenSaverEngine" is not running then
do shell script "-n echo 'Finder running 2' >> /tmp/su.log"
tell application "Finder"

activate
with timeout of 86399 seconds
-- This dialog will only wait for user confirmation for 60 seconds before continuing.
set question to display dialog "A reboot will be performed in 5 minutes to complete system updates. Please save your work and exit all applications" buttons {"OK", "Reboot now!"} default button 1 giving up after 60
set answer to button returned of question

if answer is equal to "Reboot Now!" then
--tell application "Finder" to restart
do shell script "jamf policy -id 350"
else
--delay 5
delay 240
if application "Finder" is running and application "ScreenSaverEngine" is not running then
do shell script "-n echo 'Finder running 3' >> /tmp/su.log"
tell application "Finder"

activate
with timeout of 86398 seconds
-- This dialog will only wait for user confirmation for 60 seconds before continuing.
set question to display dialog "A reboot will be performed in 1 minute to complete system updates." buttons {"OK", "Reboot now!"} default button 1 giving up after 60
set answer to button returned of question
end timeout
end tell

if answer is equal to "Reboot Now!" then
--tell application "Finder" to restart
do shell script "jamf policy -id 350"
else
--delay 5
delay 60
if application "Finder" is running and application "ScreenSaverEngine" is not running then
do shell script "-n echo 'Tell Finder Restart 1' >> /tmp/su.log"
--tell application "Finder" to restart
do shell script "jamf policy -id 350"
end if
end if
end if
end if
end timeout
end tell
end if
end if
end timeout
end tell
end if
eof

echo 'jamf policy -id 350' >> /tmp/su.log
jamf policy -id 350

# Checking to see if updates were found. As dictated by being an "elif", This only happens if a reboot isn't required but updates were found. This lets them know a reboot is not required.
else
if [ "$b" == "found the following" ];
then
osascript << eof
if application "Finder" is running then
tell application "Finder"
activate
with timeout of 3601 seconds
display dialog "The software update process is now complete. No reboot is required" buttons {"OK"} default button 1 giving up after 3600
end timeout
end tell
end if
eof
fi
fi

exit 0

@MrP
Have you tried



do shell script "jamf policy -id 350 &"


to kick off your authenticated restart? I've had luck in the past shifting policy trigger to the background when they are problematic in scripts.


@mm2270 running your Selectable_SoftwareUpdate.sh script on 10.11.5 comes back with syntax errors:



selectable_SoftwareUpdate.sh: line 461: syntax error near unexpected token `<'
selectable_SoftwareUpdate.sh: line 461: `done < <(echo "${readSWUs}")'



Any updates on this script?


Hi @dmw3 Can i ask how you're running the script? From the error you posted, I think you may be calling the script in Terminal by doing something like sh /path/to/Selectable_SoftwareUpdate.sh If so, the problem with doing that is by specifying sh up front, you're overriding the shell interpreter for the script, which is /bin/bash, not /bin/sh. This script uses some bash specific items in it, namely process substitution, which is what the error you posted is showing.



If you were running it that way, try by making the script executable first and then running it by just putting in the path to the script. It should work that way I think. That being said, I'm not sure if I've tried running this script on 10.11.5, so I'll work on that later today to see if I see any similar errors or other issues with it.


crazy questions @mm2270 How much work would it be to change your script to not include check boxes? Make more of a "here's what's available to install" in a list. I've taken a quick look at the code, but curious on your thoughts.



Thanks!
Matt


@mbezzo Not crazy. Instead of removing the checkboxes, how about having them all checked but greyed out/disabled instead? Something like this?





Another option I thought of just now would be to have all the non-reboot updates checked and disabled, so the user can't refuse installs of those, but have the Reboot Required ones optional. It can be either not checked but check-able, like so:





Or, checked by default, but enabled for the user to uncheck it if they needed or wanted to.





All these options are possible, because cocoaDialog supports checked and disabled arrays that you can pass to it to tell it which checkbox items in the index should be set those ways. (Its why I continue to love the product and wish it would get some love to keep it viable)



Note that although I just whipped this up in about 5 minutes, I haven't actually tested an install run just yet. I will do that and see if it works as designed. I assume it should, but you know what they say about assuming. :)


Looks good! Will definitely be playing with this next week. :)



Thanks as always @mm2270!



Enjoy the weekend,
Matt


@mm2270 thanks for the great script! Can you give a more advice on what items to change to have all updates checked but greyed out/disabled? We pretty much force all the updates to machines because they have gone through a couple rounds of test deployments before being sent out to all. Management also want the users to be able to defer updates that cause a reboot for a bit (15, 30, 1 hour or install now). Right now I have the reboot time parameter set to 30 min (if needed). So any advice on adding deferment like in your reboot_scheduler.sh (another great script)? Unfortunately my script-fu is not near good enough to meld to two scripts together successfully.