jamfhelper software update trigger

ImAMacGuy
Valued Contributor II

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.

1 ACCEPTED SOLUTION

acdesigntech
Contributor II

Hey John, I went a few steps further and added some logic into the script to count how many times the user chooses no before the script runs automatically anyway. To me, it gives the user a greater sense of control even if only perceived.

#!/bin/sh

fRunUpdates ()
{

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

    /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType hud -lockhud -heading 'ISD is updating software on your computer' -description 'We are now updating your Mac System software. These updates should not take longer than 30 to 45 minutes depending on how many updates your Mac needs. If you see this screen for more than 45 minutes please call our Service Desk at X4949. Please do not turn off this computer. This message will go away when updates are complete.' -icon /Library/Application Support/JAMF/EndUserSupport/AGRose.icns > /dev/null 2>&1 &

    ## We'll need the pid of jamfHelper to kill it once the updates are complete
    JHPID=`echo "$!"`

    /usr/sbin/jamf policy -trigger SoftwareUpdate & 
    ## Get the Process ID of the last command run in the background ($!) and wait for it to complete (wait)
    SUPID=`echo "$!"`
    wait $SUPID

    ## kill the jamfHelper. If a restart is needed, the user will be prompted. If not the hud will just go away 
    kill -s KILL $JHPID
    exit 0
}



######### Set variables for the script ############

########## Get the group membership for the client #####################
## Get MAC Address using networksetup
MAC=$( networksetup -getmacaddress en0 | awk '{ print $3 }' | sed 's/:/./g' )

## Use the JSS API to get the Mac's group memberships
JSSGroups=$( curl -s -u username:password https://<casper server>:8443/JSSResource/computers/macaddress/$MAC 
| xpath //computer/groups_accounts/computer_group_memberships[1] 
| sed -e 's/<computer_group_memberships>//g;s/</computer_group_memberships>//g;s/<group>//g;s/</group>/
/g' )

## Set up the software update time if it does not exist already
if [ ! -e /Library/Application Support/JAMF/.SoftwareUpdateTimer.txt ]; then
    echo "5" > /Library/Application Support/JAMF/.SoftwareUpdateTimer.txt
fi

## Get the timer value
Timer=`cat /Library/Application Support/JAMF/.SoftwareUpdateTimer.txt`

## Get the currently logged in user, if any. Also check for updates that require a restart and ones that do not.
UpdatesNoRestart=`softwareupdate -l | grep recommended | grep -v restart`
RestartRequired=`softwareupdate -l | grep restart | grep -v '*' | cut -d , -f 1`
LoggedInUser=`who | grep console | awk '{print $1}'`

################ End Variable Set ################

## Use echo and grep to find known-core (non system) software update groups. If these groups are found, run these installers silently since no restarts are required for these updates. Use an array to see which updates we take account of. The names of the array elements are also trigger names for each update. This way when there's a new software package to keep updated, we add the trigger name into the array, and the update policy to the JSS. Casper does the rest
NonSysCore=( 'SoftwareUplift-FlashPlayer' 'SoftwareUplift-Flip4Mac' 'SoftwareUplift-FontNuke' 'SoftwareUplift-PrintWindow' 'SoftwareUplift-MicrosoftOffice' 'SoftwareUplift-MicrosoftOutlook' )

for (( i = 0; i < ${#NonSysCore[@]}; i++ ))
do
    CheckUpdate=`echo "$JSSGroups" | grep "${NonSysCore[$i]}"`
    if [ "$CheckUpdate" != "" ]; then
        jamf policy -trigger "${NonSysCore[$i]}"
    fi
done

## If there are no system updates, quit
if [ "$UpdatesNoRestart" == "" -a "$RestartRequired" == "" ]; then
    echo "No updates at this time"
    exit 0
fi

## If we get to this point and beyond, there are updates. 
## if there is no one logged in, just run the updates
if [ "$LoggedInUser" == "" ]; then
    /usr/sbin/jamf policy -trigger SoftwareUpdate
else
    ## someone is logged in. prompt if any updates require a restart ONLY IF the update timer has not reached zero
    if [ "$RestartRequired" != "" ]; then
            ## If someone is logged in and they have not canceled 5 times already, prompt them to install updates that require a restart and state how many more times they can press 'cancel' before updates run automatically.
        if [ $Timer -gt 0 ]; then
            HELPER=`/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -icon /Library/Application Support/JAMF/EndUserSupport/AGRose.icns -heading "AG ISD Approved Software Updates are Available for Your Mac" -description "These updates will require you to restart your Mac. If you would like to install these now, click 'Install Updates.' If you would not like to install now, click 'Cancel Updates.' You may choose not to install updates $Timer more times before this computer will automatically install them. These updates require a restart of your Mac: $RestartRequired" -button1 "Install Updates" -button2 "Cancel Updates" -cancelButton "2" -defaultButton 2 -timeout 60`
            echo "jamf helper result was $HELPER";
            ## If they click Install Updates then run the updates
            if [ "$HELPER" == "0" ]; then
                fRunUpdates
            else
            ## If no, then reduce the timer by 1. The script will run again the next day 
                let CurrTimer=$Timer-1
                echo "user chose No"
                echo "$CurrTimer" > /Library/Application Support/JAMF/.SoftwareUpdateTimer.txt
                exit 1
            fi
        else
            ## If Timer is already 0, run the updates automatically, the user has been warned!
            fRunUpdates
        fi
    fi
fi

## Install updates that do not require a restart
if [ "$UpdatesNoRestart" != "" ]; then
    /usr/sbin/jamf policy -trigger SoftwareUpdate 
fi

View solution in original post

226 REPLIES 226

jennifer
Contributor

Has anyone been able to run the jamfhelper when no one is logged in?

I'm trying to run software update after imaging and/or when users have logged off for the day, but I want the splash screen to come up to prevent someone from logging in while the updates are in progress.

Just a side note, lots of thanks for the scripts already posted in this thread. They've been really helpful!

mm2270
Legendary Contributor III

@jennifer_unger, its not that easy to do because of security features in the OS, but you can look through this older thread. There are some solutions posted, including a LaunchAgent that calls a script to do a full screen jamfHelper message.

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

maiksanftenberg
Contributor II

@ Lachlan is there any place where I can get junki shell script/s?
I really would like to look into this as this is what we are looking for since quite a while.

Thanks,
Maik

loceee
Contributor

Hi @maik.sanftenberg,

I will release in a month or two once I've finalised testing and tidied things up (I am also about to go on paternity leave for a couple of weeks - sorry!). It's almost feature complete now, I only need to add a --priority / --forced mode so that Casper pkgs that need to be prioritised / installed by themselves are handled (ie. OSUpgrade pkgs from Greg Neagle's awesome createOSXinstallPkg) then it's testing and tidy up.

As a teaser I have got the "bootstrap" mode up and running well. In the same way munki bootstraps, the Macs boot, lock the loginwindow, check, then install all updates, reboot as necessary, then loop again until completely patched.

Screenshots... just using jamfhelper -fs to give some UI feedback.

https://interpublic.box.com/s/jg9l7mx3on2kw6sipc74

haircut
Contributor

@loceee Any chance of taking a look at the code as it stands?

loceee
Contributor

@bmwarren][/url - soon I promise!

I just need to make the logout mechanism a little more robust and quash a couple of final bugs.

I've update my presentation to convey a couple of changes - https://interpublic.box.com/s/yj4iudzllxizs3z9r03a

and improved the UI feedback during bootstrap - https://interpublic.box.com/s/jg9l7mx3on2kw6sipc74

loceee
Contributor

Good news is it's now feature complete for a testing release. I will finalise my internal testing and get some docs together. I hope to have something to share by the end of next week.

Here's a shot of the new --osupgrade mode that is designed to handle unattended installers made by Greg Neagle's awesome createOSXInstall.

https://interpublic.box.com/s/4buc4y32o9pxol0hzifr

clifhirtle
Contributor II

Thanks for putting this together Lachlan. Looks similar to what we hacked together off Andrew and others' custom scripts (see below), but the overall problem at hand remains one of my biggest frustrations with the Casper suite: minimal OOTB user dialog options. There have been times when all I want to do is present a multiple-choice dialogue to a user and end up spending hours pouring through old scripts to hodgepodge something together that will fit the need. SW updates are something that are such a core element of ensuring a secure endpoint that I really hate rolling the dice with custom anything every time I make change to our workflow. More stuff like this is a good thing.

external image link

loceee
Contributor

That looks pretty neato @clifhirtle][/url][/url !

Part of the junki magic is that Casper deployed software would also appear in the dialog.

Sorry to hijack this thread, but there is a bit of an issue with junki output and Casper 9. If you could all vote this up it would help with usability on the JSS v 9.

https://jamfnation.jamfsoftware.com/featureRequest.html?id=1670

haircut
Contributor

@loceee Yes, no part of JSS v9.x respects line breaks of any type. I'd call it a defect. I had a brief support case and was told

Thanks for contacting us today about line breaks in Self Service. We are currently looking to correct that issue in an upcoming release but I'm not sure when that will occur.

Unfortunate; it breaks functionality and makes things looks messy and unprofessional, for instance Self Service descriptions can only be long run-ons. I definitely up voted your feature request!

mikedodge04
New Contributor II

Hey @loceee,
I wanted to check out your code but it seems that you box link died. Would your consider hosting on github? or re share the box link?

ssmurphy
New Contributor III

hello @loceee,

Any updates on your software? Would like to see if it would fit our users needs.

Thanks,

ssmurphy
New Contributor III

Hello @loceee

Ping you again on any updates to the junki script you had talked about last year. Your method looked like the best method of getting updates to our clients systems. Any info on where this stands would be great. Even if its to just let the JAMF Community know that it may never see the light of day.

Thanks of your time.

clifhirtle
Contributor II

Looking back at the preso you have posted above Lachlan, is it correct to assume the junki script prompts for all updates/installs in the same dialog (versus each individual update selectable like Munki's managed software install dialog)?

The way Munki permits individualized installers is really the "special sauce" I would love to see implemented in the Casper suite.

The script I am using currently for SW updates (inspired off great work @acdesigntech and others above have contributed) already allows for integration of 3rd party installers/updates, specifying # of postpones, etc so the really big missing piece just remains the lack of user opt-in/out for specific updates similar to the ASU/Munki UI.

mm2270
Legendary Contributor III

@clifhirtle, would something like this be more what you;re looking for?

external image link

In case you're wondering that's simply cocoaDialog using the checkbox option available in the 3.0 beta releases. The items listed in it weren't hardcoded, but generated dynamically by running a softwareupdate -l command and parsing the output, then dropping it all into an array that cocoaDialog can use.

Although this is only a start, I'm pretty sure I could put something together that would take any checked items and correctly install only those updates and skip the others. I've done some similar things recently, so I can take what I've already scripted and adapt it to this purpose.

If that's something you might be interested in, let me know and I'll see what I can put together.

loceee
Contributor

Sorry all, been crazy with every spare moment taken up outside of work spent on selling, finding, buying a new home + new baby and endless illness going through home! That and one of our guys has gone and left to take a role with JAMF so I've been picking up more overflow support stuff (naughty Rusty) :)

Finally all settling down now, moving next weekend and I might have some more time to nail down the last couple of things. I will also need clearance from legal to release it, so thanks for your patience!

I like the optional installs @mm2270][/url !

As for junki's design, it doesn't allow optional installations as such, it's really ONLY about patching stuff. I didn't want to re-invent the bits of Casper that are already are great.

Here are my thoughts around this is, we have 3 solutions for deploying software with Casper, policies (silently), policies (self service - hence optional installs) and via Casper Imaging.

The workflows we are using (and I will be recommending in my documentation) will be as follows.

- New Mac
- Casper Imaging (thin or erased and install a vanilla OSX unbooted with an overload of apps, and configuration via scripts, MCX, profiles - nothing should be "baked in" any base images). -- (Casper Imaging and configurations is a supported, and quite easy way to deploy initial software on to a computer. I DO think it should be renamed to "Casper Deploy" as you don't have image with it.)
- Reboot
- Casper Imaging does it firstboot script (which includes junki bootstrap enable script)
- Reboot
- junki bootstrap does a recon, update install, apple software update loop until all updates are applied - this will compensate for any version drift in your computer configurations.

From then on, junki patching is run on a regular schedule (daily if you like) and machines are patched going forward, but allowing optional installs is not part of this workflow. If a user wants Firefox installed, they perform this via Self Service... since junki scopes update patches via smart groups, once Firefox is installed, it falls in the smart group and junki will then perform updates on it... but if it's not present it won't be installed via junki, nor am I planning on making any installations optional (apart from deferring).

A new feature I've added since last chat is an emulation of the munki "mainfests".. so you can scope testing / dev / production patches via JSS groups. eg. you add a few power users to your junkiBeta group, put all your testing Macs into the junkiDev group.

I know some people run a completely separate JSS for dev, which I don't really like when we are talking about patch deployment. It makes sense to test other things in Casper, but moving a patch (policy, pkg and smart group) between environments is cumbersome, (I did see Bryson at JAMF is working on something to make it easier), but I don't think it's the right approach myself. Using this method you have visibility of patches in testing in a single JSS, and even the ability to have a number of "testing levels" eg. dev/alpha/beta/powerusers/itstaff/brave/suckers/production.

on patching runs junki does the following,

queries the JSS to see if the computer is in junkiBeta, junkiDev group.
- if so, it fires an update-dev / update-beta trigger, you can then attach your "beta" version of the patch via this policy. Production machines that aren't in special groups will just fire the "update" trigger.
- it also dynamically re-writes the apple software update catalog if you are using reposado / netsus... so you can also have Macs in the junkiBeta group get pointed to http://yoursoftwareupdateserver.domain:8088/content/catalogs/others/index-$osxversion.merged-1_beta.sucatalog based on JSS group membership!

Super cool, and it works great! You can setup dev / beta / production branches for your Apple Software Updates as well!

Now for release, I plan on releasing the bash version which has somewhat spiralled out of control. It's not pretty, but functionally I think it does all most will need. I am hoping if I open source it smarterer people than I can refine it.

In the longer term, it should all be re-written in Python (which I am learning myself).

Stay tuned.. I promise it is coming! Lach

maiksanftenberg
Contributor II

@mm2270 I'm interested how you are leveraging this option and script to allow the people to choose what update they want.
Is it possible for you to share it? Thanks in advance.

mm2270
Legendary Contributor III

@maik.sanftenberg - stay tuned. I'm hashing something together for this, since I'm guessing it may be of some interest to some here.
What I posted above was an example. Yes, its a script, but it wasn't going any further than that dialog. I plan on making it more functional, more as an experiment or contribution to the community than anything else. We very likely would not use it where I am since all our clients are local admins and can run Mac App Store/Software Update whenever they want.

dvasquez
Valued Contributor

@chifhirtle I am testing your updates script. Very nice work. I am using it on Mavericks and JAMF 8.73. I am a little confused on the "NonSysCore" functions/variables. Can you explain a little on that? Thanks and sorry for coming in late here.

clifhirtle
Contributor II

@dvasquez see @acdesigntech's explanation on the NonSysCore calls here:

https://jamfnation.jamfsoftware.com/discussion.html?id=5404#responseChild33797
and here:
https://jamfnation.jamfsoftware.com/discussion.html?id=5404#responseChild38161

In short, these variables are a way to fire off additional, non-Apple SW update calls to other Casper policies. This could be updates for things like Flash, Java, or whatever. The catch is that you will need to be running HTTP-based distribution point(s) to take advantage of a policy within a policy, since SMB (AFP as well?) policies will already have the DP mounted for your primary SW update policy, thereby generating a "could not mount DP" error when it tries to call the NonSysCore sub-policies. For this reason I actually do not use them, instead simply running my Java/Flash/Office updates through separate policies, scoped to tiered deployment timeframes (from testing to users to directors), and scheduled through a traditional change management process.

Ultimately, I think we are all barking up the same tree here: pushing core security updates on X timeframe, permitting deferment within reason for major reboot updates, and integrating 3rd party security updates through either sub-policies or additional dialoging.

What I like about the pick and choose approach presented by @mm2270 above is that any of these dialogs are really just a veneer that can be tied back into any number of different Casper policies/deployments/actions/etc. This permits a greater freedom in imagining new approaches to user engagement, filling in the grey area between traditional Self Service (opt-in) and push policies (opt-out).

JPDyson
Valued Contributor

@clifhirtle:

The catch is that you will need to be running HTTP-based distribution point(s) to take advantage of a policy within a policy, since SMB (AFP as well?) policies will already have the DP mounted for your primary SW update policy, thereby generating a "could not mount DP" error when it tries to call the NonSysCore sub-policies.

The workaround is to keep your kick-off/notification script in the end user's system, somewhere like /Library/Management/Scripts, and have your root policy simply invoke that script. No DP mounted, and the script can call your patching policies (like I've said before, I do this with a jamf policy -trigger patchme, and we have a group of policies with that custom trigger).

dvasquez
Valued Contributor

Ah, ok so I would place the name of the smart group or group in the variable in the script and it will look for it when the array is triggered. example from mm2270: SoftwareUplift-Flip4Mac 2.4.4.2
The script will look for that and if a client is in that group it will also update that or those clients. I am not using HTTP-based distribution though. I also run my other updates like you mentioned by leveraging smart groups looking for X application and making the update available if needed. If that sounds right thanks so much. I guess I over looked those other posts. I appreciate your details and information. Theses scripts have been so helpful in achieving better Apple software update deployment for me and my environment.

acdesigntech
Contributor II

@dvasquez you don't want to put in the entire group name though - only the most-generic-while-still-being-unique part of the group name: example "SoftwareUplift-FlipForMac" instead of "SoftwareUplift-FlipForMac 2.4.4." Make sure that is also your Flip 4 Mac 2.4.4.2 update policy trigger.

This way you don't have to maintain the script per version that you release. All the script knows is that "oh there's an update group called SoftwareUplift-Flip4Mac and this Mac is in it, let's attempt a policy call with SoftwareUplift-Flip4Mac as the trigger.' And you just need to make sure the right packages are added to Casper and the upgrade policies. If you call out the entire name in the script, then you need to edit the script every time there's a new version.

acdesigntech
Contributor II

I also just noticed that I have a logic error in my above script where it attempts to prompt the logged in user if there are updates that require a restart. Basically it's supposed to look for whether there were updates requiring a restart, THEN check to see if the timer is 0 or not (it does the opposite right now). I've posted the fixed script above and below. I also made it a bit nicer to tell the user WHAT updates are requiring a restart. Hat tip to @clifhirtle][/url for that bit of code:

#!/bin/sh

fRunUpdates ()
{

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

    /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType hud -lockhud -heading 'ISD is updating software on your computer' -description 'We are now updating your Mac System software. These updates should not take longer than 30 to 45 minutes depending on how many updates your Mac needs. If you see this screen for more than 45 minutes please call our Service Desk at X4949. Please do not turn off this computer. This message will go away when updates are complete.' -icon /Library/Application Support/JAMF/EndUserSupport/AGRose.icns > /dev/null 2>&1 &

    ## We'll need the pid of jamfHelper to kill it once the updates are complete
    JHPID=`echo "$!"`

    /usr/sbin/jamf policy -trigger SoftwareUpdate & 
    ## Get the Process ID of the last command run in the background ($!) and wait for it to complete (wait)
    SUPID=`echo "$!"`
    wait $SUPID

    ## kill the jamfHelper. If a restart is needed, the user will be prompted. If not the hud will just go away 
    kill -s KILL $JHPID
    exit 0
}



######### Set variables for the script ############

########## Get the group membership for the client #####################
## Get MAC Address using networksetup
MAC=$( networksetup -getmacaddress en0 | awk '{ print $3 }' | sed 's/:/./g' )

## Use the JSS API to get the Mac's group memberships
JSSGroups=$( curl -s -u username:password https://<casper server>:8443/JSSResource/computers/macaddress/$MAC 
| xpath //computer/groups_accounts/computer_group_memberships[1] 
| sed -e 's/<computer_group_memberships>//g;s/</computer_group_memberships>//g;s/<group>//g;s/</group>/
/g' )

## Get the timer value
Timer=`cat /Library/Application Support/JAMF/.SoftwareUpdateTimer.txt`

## Get the currently logged in user, if any. Also check for updates that require a restart and ones that do not.
UpdatesNoRestart=`softwareupdate -l | grep recommended | grep -v restart`
RestartRequired=`softwareupdate -l | grep restart | grep -v '*' | cut -d , -f 1`
LoggedInUser=`who | grep console | awk '{print $1}'`

################ End Variable Set ################

## Use echo and grep to find known-core (non system) software update groups. If these groups are found, run these installers silently since no restarts are required for these updates. Use an array to see which updates we take account of. The names of the array elements are also trigger names for each update. This way when there's a new software package to keep updated, we add the trigger name into the array, and the update policy to the JSS. Casper does the rest
NonSysCore=( 'SoftwareUplift-FlashPlayer' 'SoftwareUplift-Flip4Mac' 'SoftwareUplift-FontNuke' 'SoftwareUplift-PrintWindow' 'SoftwareUplift-MicrosoftOffice' 'SoftwareUplift-MicrosoftOutlook' )

for (( i = 0; i < ${#NonSysCore[@]}; i++ ))
do
    CheckUpdate=`echo "$JSSGroups" | grep "${NonSysCore[$i]}"`
    if [ "$CheckUpdate" != "" ]; then
        jamf policy -trigger "${NonSysCore[$i]}"
    fi
done

## If there are no system updates, quit
if [ "$UpdatesNoRestart" == "" -a "$RestartRequired" == "" ]; then
    echo "No updates at this time"
    exit 0
fi

## If we get to this point and beyond, there are updates. Check to see if there is a timer file on the Mac. This file tells the script how many more times it is allowed to be canceled by the user before forcing updates to install
if [ ! -e /Library/Application Support/JAMF/.SoftwareUpdateTimer.txt ]; then
    echo "5" > /Library/Application Support/JAMF/.SoftwareUpdateTimer.txt
fi

## if there is no one logged in, just run the updates
if [ "$LoggedInUser" == "" ]; then
    /usr/sbin/jamf policy -trigger SoftwareUpdate
else
    ## someone is logged in. prompt if any updates require a restart ONLY IF the update timer has not reached zero
    if [ "$RestartRequired" != "" ]; then
            ## If someone is logged in and they have not canceled 5 times already, prompt them to install updates that require a restart and state how many more times they can press 'cancel' before updates run automatically.
        if [ $Timer -gt 0 ]; then
            HELPER=`/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -icon /Library/Application Support/JAMF/EndUserSupport/AGRose.icns -heading "AG ISD Approved Software Updates are Available for Your Mac" -description "These updates will require you to restart your Mac. If you would like to install these now, click 'Install Updates.' If you would not like to install now, click 'Cancel Updates.' You may choose not to install updates $Timer more times before this computer will automatically install them. These updates require a restart of your Mac: $RestartRequired" -button1 "Install Updates" -button2 "Cancel Updates" -cancelButton "2" -defaultButton 2 -timeout 60`
            echo "jamf helper result was $HELPER";
            ## If they click Install Updates then run the updates
            if [ "$HELPER" == "0" ]; then
                fRunUpdates
            else
            ## If no, then reduce the timer by 1. The script will run again the next day 
                let CurrTimer=$Timer-1
                echo "user chose No"
                echo "$CurrTimer" > /Library/Application Support/JAMF/.SoftwareUpdateTimer.txt
                exit 1
            fi
        else
            ## If Timer is already 0, run the updates automatically, the user has been warned!
            fRunUpdates
        fi
    fi
fi

## Install updates that do not require a restart
if [ "$UpdatesNoRestart" != "" ]; then
    /usr/sbin/jamf policy -trigger SoftwareUpdate 
fi

jhalvorson
Valued Contributor

@acdesigntech - Thanks for sharing the script. Please verify what you have for a custom event (aka trigger) titled "SoftwareUpdate".

I have my custom event policy set to the following Options:
General: Enabled, Custom with the name that matches the update script, Frequency = Ongoing.
(Not available offline and no other options filled in.)
Software Updates: Configured to use Apple's software update server
Restart Options: Restart if package or update requires it for both No User and User logged in. Delay is set to 5 minutes.

For short awhile I had enabled Maintenance with the option to Update Inventory, but that I believe that was just wasting time or causing issues if a restart was needed.

What I really want to know is if your using JAMF's Software Updates option in the policy or if you are using a Execute Command within the Files and Processes options, such as ```
software update -ia
```
[Casper Suite 9.22]

acdesigntech
Contributor II

yeah it was just a policy that ran the single command softwareupdate -ia. Do I really need that to be in a separate policy? No I guess not.

I haven't relied on Caspers built in software update server tools for quite a while, especially as they became so unreliable in v8.x

clifhirtle
Contributor II

Thanks for the reminder @JPDyson. Always tried to all my stuff server-side, but given some of our clients don't check in but 1x/mo I have increasingly been leveraging offline policies, which are similar enough for me to make an exception.

The workaround is to keep your kick-off/notification script in the end user's system

mm2270
Legendary Contributor III

Hi all,

Just wanted to post some progress on what I showed up above. Here are some updated screenshots of what I'm hacking together.

An updated selection screen:
external image link

The dialog forces a selection to be made to click "Install" or they need to Cancel:
external image link

With some selections made:
external image link

Starting installations (at this point its checking the SUS or Apple's servers for the updates selected)
This is actually two oocoaDialog windows up simultaneously:
external image link

Now its going through (one of) the installations. In this shot, I chose some items that require a reboot, so the message reflects that:
external image link

Installs done. Reminder that a reboot is required.
external image link
The dialog times out after 30 seconds and then moves on to...

…the reboot countdown. Code courtesy of this thread (thanks to @alexjdale for his excellent enhanced version):
https://jamfnation.jamfsoftware.com/discussion.html?id=8360
external image link

A few more. This time installing updates with no required reboot. Note the different wording in the window
external image link

A final message when installing non-reboot updates
external image link

A couple of notes on this:
1- The script can use some Casper Suite script parameters that will let you customize a few aspects without needing to modify the script directly. For example:
a) the "Company" name in the Title bars of the windows
b) the number of minutes you want the countdown to run until restart. I set the default to 5 minutes, but you'll be able to pass any integer you want, like 10, 15, 60, whatever.
c) Some of the icons used in the dialogs
… and possibly a few other things

All of the above will use default values if you don't pass a parameter to it, so using parameters won't be a requirement for the script to run, just optional.

2 - The script has two "modes" The default mode you see in the screenshots above shows progress for each update as it installs, then resets the progress bar back to 0 as it starts on the next update. The other mode will show one progress bar for all installs that slowly moves from 0 - 100. The only issue with the latter mode is the text will likely need to be generic, as in "Installing 5 updates…" or something, because I'm having trouble getting that mode to correctly see which update is being installed as it goes along. The other mode doesn't have this issue.
The mode will probably end up also being a Casper Suite script parameter, so you can change it on the fly without needing to change the script itself.

3- I've tested this so far on 10.8 and 10.9, with some limited testing on 10.7. We don't have much Lion Macs in our environ right now so I don't know how much I'll be able to test it against that OS.

Finally, although this is directed at Apple software updates, this model could easily be adapted to work with regular Casper Suite polices, such as in the scripts posted above by @acdesigntech and @clifhirtle. Also, it could be integrated into some existing script workflows that allow for X number of deferrals before eventually forcing the installations. I haven't actually done that part yet, but it will definitely be possible.

I've got a little more work to do on fixing a few items, but otherwise in some basic test runs it seems to work pretty well.

RaulSantos
Contributor

@mm2270 this looks great any way I can contact you directly i have a few question.

mm2270
Legendary Contributor III

@RaulSantos, best way is via email, mm2270 [at] me [dot] com

alexjdale
Valued Contributor III

Great stuff! Very similar to what I've implemented, but I have fewer options. My script reads in a list of updates we want to install and the user doesn't get to choose, they just know they have X number of critical updates that need to be installed and if one needs a restart. The script runs a "softwareupdate -l" to see what is available and on our list, then downloads the required updates before prompting the user to install them.

I also added in a mandatory date option. For the first week the user can cancel to defer until the next day, but it's forced after that date (the dialog tells them when that will happen). It's as simple as a parameter in YYYYMMDD format and checking to see if the current date is greater than/equal.

Mandatory date, reboot timer delay, and SWU list location (I keep the lists in text files uploaded to the JSS so they are in the Scripts folder) are configured in the script parameters, so each patch cycle we just update them as needed and start over again.

I'm very curious to see how you are executing the softwareupdate command. I had problems with it when running it from bash with a list of software updates and had to come up with a really stupid workaround (writing the command string to a file and then executing that file).

dvasquez
Valued Contributor

@acdesigntech thank you for clarifying that. I think I understand that now, good stuff. With regards to @clifhirtle script I was unable to get the window to display available updates even though they are available. is that part dependent on this alone: (RestartRequired=softwareupdate -l | grep restart | grep -v '*' | cut -d , -f 1). I am still working on testing. I was able to get @lisacherie script to work like a charm. Thank you for that script! I think giving the user a list of updates that were detected to install that do require a reboot would be very nice. And speaking to what @JPDyson mentioned have any of you leveraged cron to execute tasks locally while still calling policy triggers? This would work nicely I believe.

acdesigntech
Contributor II

@dvasquez][/url @alexjdale][/url yes, the ```
RestartRequired=softwareupdate -l | grep restart | grep -v '*' | cut -d , -f 1
``` line runs a list of available updates and only looks at the ones requiring a restart. the grep -v * line gets the user-friendly name, like 'Mac OS X Update (10.8.5)' and not the ugly MacOSXUpdate10.8.5-blahblah nastiness. I spit that out in my jamfhelper line. Unfortunately bash is not as elegant as some languages with its text parameters, so if there are multiple restart-requiring updates, it just shows them as a single string. But it's good enough for my needs.

And no, I do not use a local daemon or anything to kick this off. My reasoning here is that the computer has to be on the internal network anyway to leverage our SUS, right? So it wouldn't help anything if the client was off the reservation and had a local daemon to launch a script that just contacts the internal JSS. Plus if there were ever changes to that initial script, it might be hard to get them out there. I guess that's where you get into a JSS in the DMZ. We're not quite there yet. Maybe next fiscal. Instead I have a second set of policies that use the same update script that are available via self service (and also offline) that are scoped to those Macs needing updates. Both of the policies first warn the user that they need to be on the internal network or VPN before they run them. So currently that's my workaround to the 'client that checks in once a month' issue - which by the way is becoming more and more of a legit issue now that we are a 'globally minded workforce' (I take that as code for I WANT A LAPTOP! HMPH!!!).

@mm2270][/url yet again another great looking masterpiece! If my management wasn't already incensed about the pathetically low level of user interaction I'm already giving people, I would poach those ideas in a heartbeat! Kudos again to an amazing use of CD. I really do have to start getting into progress bars...

This really is great work, everyone! It's really cool to see all us Mac Admins chiming in and building solutions to problems. I'm glad I could add my little contribution!

dvasquez
Valued Contributor

@acdesigntech Thanks for the reply. Right, when a machine is off the domain it would not have connection to the SUS. I put some checks to make sure that it is ping able. If not contactable it waits to check again later. But definitely a consideration. I did get the script you and @clifhirtle and @mm2270 added to this discussion to partially work it is quite amazing stuff. I am seeing some issues with scaling in the text and buttons. I also I added my own customizations to the title and others, maybe this is the cause. One issue I cannot get around is if I click to continue with the installations I always get the following error:

Jamf helper result was HELPER=2
user chose No

If I let it move through the postpones on the final one all works very well. I only get an error when I choose to install immediately. I added -startlaunchd to the helper portion of the scripts. This seemed to help in the past. I am still testing and thanks for all the contributions.

Dominic Vasquez

dvasquez
Valued Contributor

I seem to have fixed the issues I was having. I believe editing this down "HELPER=HELPER=`/Library/Application..." helped. I edited that and made sure everything else was tidy and all is good. I took a "HELPER=" out. Not sure if that was intentional. Thanks again.

acdesigntech
Contributor II

yeah that is certainly a typo

tuinte
Contributor III

I just… I'm so impressed with the abilities on display in this thread.

mm2270
Legendary Contributor III

Hi all,

I debated on whether to start up a new thread on this, but decided to keep this in here, despite the length this thread is getting to.

So, I’ve posted a version of the script that I showed above in the screenshots to a github page.
That page is here:
https://github.com/mm2270/CasperSuiteScripts/blob/master/selectable_SoftwareUpdate.sh

I’m admittedly a noob regarding Github, so hopefully how I’ve set it up will be easy for everyone to pull down the script.

Here are a few recent additions to this script I made since I last posted:

1- If there are Software Updates that do not require e reboot available to the Mac, an additional 3rd button shows up in the initial dialog, called “Install No Reboot Updates” Its a long-ish name for a button, but I wanted to make it descriptive enough that it was self explanatory without really needing to read a description in the dialog itself. That button does exactly what it describes - goes right into installing all updates available that don’t require a reboot. My goal with this was to make it easy for an end user to install at least some of the presented updates. Giving them a one button install function that wouldn’t majorly disrupt their workflow seemed like a logical addition.
If the only updates available require a reboot this 3rd button doesn't show up (since that wouldn't make much sense :)

2- When installing updates, the progress bar now shows the number of the update its currently working on, in context of all selected updates. In other words, if a user selected 4 updates to install, the progress bar will indicate “Now installing 1 of 4 - <Update Name>…” and iterate up by one for each that it moves to. This gives some better context to the user on how far along we are in the installations.

3- So this last one is a bit of a hack, but I put something together to help get around a known issue/bug with cocoaDialog. Namely, CD responds to the Command + Q keystroke and will close CD windows if they are active at the time. I personally think this is a bug, because, I believe any application that doesn’t have its own menubar or show up in the Cmd + Tab switcher should never respond to Cmd + Q.
Anyway, this behavior presents an issue because if the user does Cmd + Q, the progress bar and/or other windows will disappear, but the script continues to run, i.e. installs continue unabated, and that could be pretty confusing.
I came up with a workaround for this. Not the most elegant solution, but essentially, if the user quits one of the progress bars, as its going through the loop process, it checks to see if CD is in the process list and will re-run a sub-function to show the progress bar again. This is essentially a function within a function that can be called by a set of conditions. Cool thing is, it picks up exactly where it needs to and displays the progress bar already filled to where it needs to be, so it doesn’t really miss a beat in the install or reboot countdown. In my tests, this actually pops back up pretty quickly. so there's little lag between the quit and the progress bar reappearing.
While this only works right now on the progress bar functions, those are the most important ones. I believe the script responds to a Cmd + Q on any normal dialogs as if the user clicked Cancel, assuming that’s available. Otherwise it should act as if the default button was clicked. (Haven't thoroughly tested this last bit)

Couple more notes:
While this was developed around Software Update installs, this script could be adapted to work with Casper Suite policy runs, for those of you who are using custom solutions that use carefully named Smart Groups, like outlined above.

Lastly, the script is pretty self contained. You can pass a number of Casper Suite script parameters to it to change some items, but none of them are necessary. It will choose default values and strings if you don’t pass anything to it. It actually doesn’t even really rely on the Casper Suite as its designed. If Self Service isn’t available for one of the icons, it defaults to a System level icon. Its all commented pretty well in the script if you want to modify any of it, or understand which parameters you can pass to it.
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,

Here’s an updated screen shot of the selection dialog
external image link

An updated shot of the progress bar, showing the new “Installing num of total” behavior:
external image link

There's a bit of stuff that could be added to this, like some proper error checking and trapping. Right now it will (edit) NOT correctly report if an installation failed. That could be integrated, but I didn't want to wait until everything was perfect or in place before letting folks take a look at it. So… work in progress.

If you have questions about anything, feel free to ask. Feedback welcome. Its all written in bash since that's all I can really script in right now. If you make improvements to it, feel free to let me know. Hopefully some of you will find it useful.

mojo21221
Contributor II

@mm270 Sweet flow! Thanks I will definitely give this some testing.

johnnasset
Contributor

Good stuff in both scripts from @mm270 and @acdesigntech][/url

@mm270

Love the cocoadialog boxes and just the look and feel. Definitely gives more granular control to the end users. I could see this one being used for teacher machines. It would be nice to include the Postpone option as seen in @acdesigntech][/url version.

@acdesigntech][/url

I had to fiddle with this script a bit more. One thing I noticed when displaying the jamfhelper with the list of updates, some of the text gets cut off.

https://www.dropbox.com/s/22h24vr6spzsbnq/Screen%20Shot%202014-03-18%20at%202.16.03%20PM.png

Great for the minimal user interaction-I'd use this for student machines. I also like the ability to put non-core updates in the script (with some mods to the smart groups of course). Thanks to both of you for the awesome work!!