Use jamfHelper to notify of Self Service policies waiting

barnesaw
Contributor III

I am starting to use Self Service to push out Office Updates (primary concern), Flash player updates, run RUM to update CS 6 installs...pretty much all updates (even Apple Software Updates soon). I do this by promoting the updates through a series of smart groups. Is there any good way to notify a logged in user that they have new Self Service items waiting?

So far I'm having no luck with scripting a decent solution.

2 ACCEPTED SOLUTIONS

Munkeee
New Contributor III

Run a policy on the every30 trigger (or whatever your time is) that runs jamfHelper from the run command option, scope it to the same smart group your using for the install (Self Service) policy. Make sure to set the frequency to something reasonable for your environment.

For the jamfHelper command, something like this....

/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -startlaunchd -windowType hud -title "Update Required" -heading "Your Message Heading" -description "Your Update Description" -button1 "OK" -defaultButton 1

View solution in original post

mm2270
Legendary Contributor III

Should be fairly simple to do. Just create a script calling jamfHelper, if that's what you really want to use. Scope the script to a policy that uses the same Smart Group your Self Service item is scoped to, and maybe have it run only once a day or even once a week, if you don't want to bug them quite so much.
We have something similar in place regarding pending Office updates, but it can trigger the update process depending on the button the user clicks.

Note that there are other options besides jamfHelper. You can also use cocoaDialog, either its regular message boxes, or the bubble/notify option, which is much less obtrusive than a jamfHelper window. It kind of all depends on how 'in their face' you want to be with this.

Do you need some script examples of displaying a message to a user with jamfHelper, or are you OK on that?

In the future, it would be awesome if JAMF could find some way to "badge" the Self Service app icon in the user's Dock. But I have a feeling this option only works with apps that are either Apple branded or are issued through the Mac App Store. Maybe I'm wrong though.

View solution in original post

23 REPLIES 23

Munkeee
New Contributor III

Run a policy on the every30 trigger (or whatever your time is) that runs jamfHelper from the run command option, scope it to the same smart group your using for the install (Self Service) policy. Make sure to set the frequency to something reasonable for your environment.

For the jamfHelper command, something like this....

/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -startlaunchd -windowType hud -title "Update Required" -heading "Your Message Heading" -description "Your Update Description" -button1 "OK" -defaultButton 1

Munkeee
New Contributor III

Also, make sure you update the inventory after the install, so the user is taken out of the smart group (assuming that your scoping them by the app and version).

mm2270
Legendary Contributor III

Should be fairly simple to do. Just create a script calling jamfHelper, if that's what you really want to use. Scope the script to a policy that uses the same Smart Group your Self Service item is scoped to, and maybe have it run only once a day or even once a week, if you don't want to bug them quite so much.
We have something similar in place regarding pending Office updates, but it can trigger the update process depending on the button the user clicks.

Note that there are other options besides jamfHelper. You can also use cocoaDialog, either its regular message boxes, or the bubble/notify option, which is much less obtrusive than a jamfHelper window. It kind of all depends on how 'in their face' you want to be with this.

Do you need some script examples of displaying a message to a user with jamfHelper, or are you OK on that?

In the future, it would be awesome if JAMF could find some way to "badge" the Self Service app icon in the user's Dock. But I have a feeling this option only works with apps that are either Apple branded or are issued through the Mac App Store. Maybe I'm wrong though.

Lhsachs
Contributor II

You don't even need to use jamfHelper... You can create a policy triggered by every 15 to run once a day (or whenever) scoped to a smart group based on something like flashNOT1.6.602.167, no packages, no scripts, only a message (reboot options) and have Display message if not rebooting checked... Therefore, you can nag once a day, and when the update is run, the user will drop out of the smart group and stop getting the message.

barnesaw
Contributor III

Many thanks. Got a script set up to Prompt to install from self service (OK/Cancel-style). OK triggers an osascript statement to activate Self Service, cancel exits cleanly. Runs once a day, during business hours only.

So far this is done for Office updates only. Still working on smart-grouping for Apple updates and flash player updates.

quedayone
Contributor

Can you post the script?

Thanks!

Wi11

barnesaw
Contributor III

It's a simple variation on one someone else posted elsewhere here on jamfnation (might even have been mm2270).

#!/bin/sh
# Script to prompt to open self service

jhPath="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"

Title="$4"
Heading="$5"
Desc1="$6"
Desc2="$7"
Icon="$8"

Msg="$Desc1
$Desc2"

SelfServ=`"$jhPath" -windowType hud -title "$Title" -heading "$Heading" -description "$Msg" -button1 "Install" -button2 "Cancel" -defaultButton 1 -cancelButton 2 -icon "$Icon"`

if [ $SelfServ == 0 ]; then
    osascript -e 'tell application "Self Service"' -e "activate" -e 'end tell'
fi

Then use the fields in your policy to populate the variables.

mm2270
Legendary Contributor III

Yeah, that looks like a variation on a sample script I had put together for someone. I was helping them figure out a way to get a multi line description into a policy parameter. Hence the Desc1 and Desc2 and the Msg variable in the script that combines them together for jamfHelper.

zmbarker
Contributor

@mm2270 - Can you provide a few scripts that use CocoaDialog?

I have the cocoadialog.app rolled out to my clients. Now what I need to do is create a bash script that calls cocoadialog that will prompt the user to select button 1, button 2, button 3, etc...

Each button will then kick off different policies to install certain apps from the JSS.

EX: When a computer gets enrolled I was the very next thing to kickoff a policy that has a message like "Is this a XYZ Department computer; 123 Department computer; Test Lab Computer; etc...?" Button 1=XYZ Department; Button 2=123 Department computer; Button 3="Test Lab computer".

Button 1 = kicks off > xyz policies
Button 2 = kicks off > 123 policies
Button 3 = kicks off > Test Lab Policies


I also need a script that uses the cocoadialog.app that has a list of checkboxes that will also kick off the particular policy assigned to the checkbox.

EX: checkbox 1 = Office 2011 checkbox 2 = adobe checkbox 3 = text wrangler

Each checkbox is associated with the particular software install policy in JSS.

nessts
Valued Contributor II

http://mstratman.github.io/cocoadialog/#documentation

nessts
Valued Contributor II

The documentation has examples in perl or bash for almost every option.

mm2270
Legendary Contributor III

@zmbarker][/url][/url - Sure! I use cocoaDialog a lot. I'm slightly nervous that it will one day stop working altogether as the primary developer doesn't seem to have time to continue updating it. But the day it stops working hasn't come yet. It still works OK in Mavericks. Phew!

So, using what you posted above, here is an idea of how to get cocoaDialog to display that and take some actions.
I'm assuming that for your above policies, you have some manual triggers set up for them? If not, it will be tricky to call them from a button press. Manual triggers will be the only real way to do it.

#!/bin/sh

## Edit this to put in the full path to cocoaDialog, all the way to the executable
#cdapp="/full/path/to/cocoaDialog.app/Contents/MacOS/cocoaDialog"

## Edit messaging parameters here
Title="IT Message"
Heading="Make a choice from the options below"
Message="Is this a:

XYZ Department computer?
123 Department computer?
Test Lab Computer?" 

## If you want to use an icon, put path here.
## Some of the common icon shortcuts for CD work OK and some don't. See the manual on the github page for more
Icon="/Applications/Self Service.app/Contents/Resources/Self Service.icns"

## The message
Dialog=$( "$cdapp" msgbox --title "$Title" --text "$Heading" --informative-text "$Message" --icon-file "$Icon" 
--button1 "XYZ Department" --button2 "123 Department" --button3 "Test Lab computer" --string-output )

## case statement taking actions based on button press
case "$Dialog" in
    "XYZ Department")
    echo "User clicked XYZ Department. Running xyz polciies"
    jamf policy -trigger xyz_policies ;;
    "123 Department")
    echo "User clicked 123 Department. Running 123 polciies"
    jamf policy -trigger 123_policies ;;
    "Test Lab computer")
    echo "User clicked Test Lab computer. Running Test Lab polciies"
    jamf policy -trigger Test_Lab_Policies ;;
esac

Note that in this case I used a case statement (no pun intended) but this could just as easily be done with some if/then/else statements. As mentioned, edit the text or paths to stuff where needed.

As for your second dialog with the checkboxes, although the latest beta version of cocoaDialog, which I use, has an advanced option for checkboxes, its poorly implemented, or else has bugs with any recent versions of OS X. The docs state that it should accept a text description as well as the checkboxes, but I've never been able to get it to work, so it no worky. What that means is you end up with a dialog with nothing but checkboxes and text after each. No description on what to do to the end user, so its not very friendly.
One option, something I've used to help with stuff like this, is to call cocoaDialog twice in the script and use its precise pixel placement and --width and --height parameters to align the 2 dialogs up so they almost look like one window. Basically, call it first using msgbox and put it into the background, but don't use any buttons for it, then call it again with say, the checkboxes. The first one becomes the description and the other becomes the choices. it could work in this case.
If you're interested in that, let me know and I'll see if I can help.

dvasquez
Contributor III

Hello.
I am trying to implement the script Barnesaw posted through policy and it seems to work cleanly all by itself. No matter what button is clicked the package the script is scoped too runs. I want our users to have the option to cancel. I appreciate the script post and any help. To clarify when the policy runs the jamf helper prompt does come up and gives options but when "Install" is clicked self service opens but the install just starts in the background. I tested by adding a policy trigger. When I run the script by itself the prompt pops up then SelfService opens or does not open depending on what is clicked. Maybe I am adding the script wrong or not placing something in the correct order. I am using JAMF 8.71. I would ideally want jamf helper to be called through policy and the packages that is scoped to be installed or not installed through self service only. I have set a smart group and scoped the policy to that smart group and have the script to be called before like I mentioned. Sorry I feel like I should have this. Thanks for the help.

dvasquez
Contributor III

I ended up getting this. I needed one policy for the script and one policy for the smart group with a trigger. I ended up reading another post that lead me in the right direction and I got help from Jamf support. I tested and things seem to be really nice. I customized the icon and text to fit my ENV. Thank you.

ctangora
Contributor II

Cache all packages you want installed. Have an EA that counts the number of updates available in ASU and are currently cached in Casper. Have a smart group that these folks would fall into (greater than 0). Have a policy tied to this smart group that launches this script. This script will show them a window saying they have updates, then launch self service when they click "I Understand".

We have this script/policies running twice a day. So if someone has something we think they should have installed they will be reminded about it twice a day, every day, until they take action. Added benefit of cacheing the installers is that we can have packages install at login/logout/startup if they haven't taken action through Self Service yet. I'm not 100% sure on the Cocoa Dialog part, as we ended up using jamfhelper, but I believe it would work.

We then create a self service policy for each cached update that finishes with a recon. We also have an "install all" option that folks can runs and will shut down apps and install all cached packages and all Apple updates.

#!/bin/sh

## Set the variables and such…
CD="/Applications/Utilities/cocoaDialog.app/Contents/MacOS/cocoaDialog"
JH="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"

icon_folder="/path/to/where/you/store/companylogos"
logo_K="Logo_Square_Black.png"

## PREP MESSAGE

title="Company IT Department"
heading="Company IT Department Update Notification"
descrip=$(echo -e "You have updates pending…

Be a good person, install them.
")
button_value="I Understand"

## And on to the good stuff.

## Make some noise.
afplay /System/Library/Sounds/Hero.aiff

## Displaying Notification Window (CocoaDialog or JAMFHelper, your choice).
#$CD msgbox --title "$title" --text "$heading" --informative-text "$descrip" --string-output --no-timeout --debug --icon-file $icon_folder/$logo_K --button1 "$button_value" 2>/dev/null
"$JH" -startlaunchd -windowType utility -title "$title" -heading "$heading" -description "$descrip" -button1 "I Understand" -defaultButton 1 -lockHUD -icon $icon_folder/$logo_K

## Finding local user (so we can launch Self Service under their user and have it show up under their session)
user=`ls -l /dev/console | cut -d " " -f 4`

## Launching Self Service as that user (had some issues with this in the early stages)
sudo -u $user open -a /Applications/Self Service.app

Chris

msallen
New Contributor

Is there any way to put a mailto link in the message? Like "if you have any questions, please send an email to helpdesk@example.com?

mm2270
Legendary Contributor III

@msallenJAMA If you mean in a cocoaDialog or jamfHelper message (or even a regular Applescript dialog for that matter), then no, there's no easy way to get clickable links in those dialogs. Someone who used to be here on JAMFNation once put a simple app together and posted it on github or someplace that could use a formatted html file for the dialog text, which could of course have a clickable link. But it was more a concept application I believe than anything else - I doubt its being actively maintained beyond the initial "beta" version.

Other than that, you could label a button in a dialog to open a link. Like in the dialog text, say something like "for more information, click the "More Info" button below" and when that's clicked it can do a simple 'open' command against a URL coded into the script. That should open the address in the user's default browser.

EDIT: Sorry, you mentioned a mailto link. That's also possible with a button. Just substitute what I wrote above with a 'mailto' link instead of a URL.

msallen
New Contributor

@mm2270

Do you have an example?

Thanks

GabeShack
Valued Contributor III

@mm2270 Old thread I know, but wondering if you had an example of CocoaDialog being used to show progress on running jamf policy via triggers?  Ive found that I can use JamfHelper to show a Window during setup assistant, so I am using that with a countdown timer while some policies run however, its not an accurate timer of what is really happening when the script is just calling some policy triggers.  I just wondered if cocoaDialog can run over the login window as well, or is that just a feature of jamf helper?  (real reason I ask is because DEPNotify cannot run until a user is logged in, and Jamf Connect Notify is running as the end user logs in, and I really want to have all the software installed before the end user is logging in.  I can edit the DEPNotify script to not try to use a logged in user and just open everything with root, and it works to run through the installs, but never shows the pop up for the app. Also Jamf tells me that adding too many Pre-Stage Enrollment packages could harm the enrollment and ive already seen a few miss the enrollment step using it that way.) so for the most easy of use I want to call policies (or a policy) using the enrollment complete trigger which then runs it on the "set location screen" of the setup assistant, and have it show progress on the policy's i'm calling in a window like DEP Notify does lol).  This is all probably impossible...but I'm so close....

Gabe Shackney
Princeton Public Schools

mm2270
Legendary Contributor III

@GabeShack I don't use cocoaDialog anymore. I've moved on to using IBM Notifier, which is a great successor to cocoaDialog, and is being actively developed and will work on all current OSes (and future ones, assuming the team working on it keeps up the development)

I highly recommend you take a look at it for any dialoging needs, especially things like progress bars, etc. It's a very robust tool with lots of nice options, and more coming down the line if you look at some of the feature requests.

https://github.com/IBM/mac-ibm-notifications

That said, I don't know if even IBM Notifier would fit your needs for what you described. I have a feeling getting progress to run at the login screen will be tricky to do, even with that application.

Just curious, but why are you averse to having DEPNotify run after a user logs in? That's what I do. My enrollment policy runs a script that creates a LaunchAgent, which kicks off after log in and starts the workflow to open DEPNotify as full screen, and installs everything, showing nice progress with custom icons and text along the way.

It sounds like you're trying to recreate a more traditional imaging workflow of having all software installed before someone logs in to the Mac, which is ambitious to be sure, but is going to be very complicated to maintain in my opinion.

GabeShack
Valued Contributor III

Wow that does look quite robust.  

However, I think I found a way to do what I want just using a script from Talking Moose that pops a message before each policy call.  I've been successful in having this run during enrollmentComplete, Over the "Location Services" setup screen.  

This is ideal since we have the tech assistants running the initial enrollment and then the end user logs in usually a bit later.  I then have the script you helped me with (naming the computer based on the user logging in) which runs during JamfConnectNotify, but I keep that one pretty clean, with just the naming script running and no packages.  The goal for me has always been saving as much time during the end user login as possible, so prepping before with the major software installs during enrollment would save that time.

Im going to test the below but I'm unsure if I should add the policy calls below the Jamf Helper calls, (just learned about the & to run it in the background) or above them with an & after the policy call.  I think though this will solve me loading too many prestage enrollment packages, and will still accomplish having the software preloaded by our techs before the end user logs in.  (this also helps since we can have the machine hardwired to ethernet during the enrollment and during this script running and then can have it just be on wifi for the end user login).

I originally had a timer countdown that just made the tech assistants wait 12 min before continuing, but since I loaded up the prestage enrollment with packages, I had no way to tell if they were completed installing or not.  Since I know that jamf helper can run though on an enrollment complete trigger, I figure this is still probably the best way to do this for now.  Script below.  @mm2270 Thoughts?

 

#!/bin/sh

/Library/Application\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper \
-windowType utility \
-title "Base App Installs" \
-heading "Micosoft Office" \
-description "Completing Step 1 of 4" \
-icon /Library/Desktop\ Pictures/PPSLogo.jpg &
jamf policy -trigger Office2019
sleep 2

/Library/Application\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper \
-windowType utility \
-title "Base App Installs" \
-heading "Chrome" \
-description "Completing Step 2 of 4" \
-icon /Library/Desktop\ Pictures/PPSLogo.jpg &
jamf policy -trigger chrome
sleep 2

/Library/Application\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper \
-windowType utility \
-title "Base App Installs" \
-heading "Firefox" \
-description "Completing Step 3 of 4" \
-icon /Library/Desktop\ Pictures/PPSLogo.jpg &
jamf policy -trigger firefox
sleep 2

/Library/Application\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper \
-windowType utility \
-title "Base App Installs" \
-heading "Zoom" \
-description "Completing Step 4 of 4" \
-icon /Library/Desktop\ Pictures/PPSLogo.jpg &
jamf policy -trigger zoom
sleep 2

/Library/Application\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper \
-windowType utility \
-title "Base App Installs" \
-heading "Completed Installs" \
-description "Base App Installs Complete." \
-icon /Library/Desktop\ Pictures/PPSLogo.jpg &

sleep 2
killAll jamfHelper
/Library/Application\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -lockHUD -icon /Library/Desktop\ Pictures/PPSLogo.jpg -title "Tech Office" -heading "Base App Installs Complete" -description "Click Continue for Login Screen" -button1 "Continue" -defaultButton 1
exit 0

 

 

Gabe Shackney
Princeton Public Schools

mm2270
Legendary Contributor III

Hi @GabeShack So in looking over what you have, allow me to make some suggestions. These are just that - suggestions.

Whenever I find myself needing to repeat a sequence of some kind with only minor differences, I tend to use a bash array and a loop, and sometimes a case statement in there. For example, you are calling jamfHelper multiple times in your script with only a small difference in the heading and description text. You can simplify this script quite a bit because of that fact.

Here's an example. Below I've put all your custom policy triggers into a bash array up top, and then a case statement which sets the heading string for each item. It then loops over the bash array and calls a function which will run the policy trigger after popping up the customized jamfHelper window. The "step" we're on (1 of 4, 2 of 4, etc.) is automatically calculated by using the array length (how many items we're looping over) and iterating a value, starting at "1" and increasing.

The advantage of doing things this way is that if you ever need to make edits, additions or changes, you should only need to modify the array and the case statement. No need to add in additional calls to jamfHelper or extra text strings, etc.
Anyway, here is the modified script.

#!/bin/zsh

## Static paths to jamfHelper and the icon
jamf_helper="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"
icon="/Library/Desktop Pictures/PPSLogo.jpg"

## Bash array containing the custom triggers (events)
custom_triggers=(
Office2019
chrome
firefox
zoom
)

## Use the array length to figure out how many steps we have automatically
total_steps=${#custom_triggers[@]}

## Function that calls each policy trigger and customizes the message during each loop
## Uses a case statement to determine the heading text for each custom event trigger
function callPolicy ()
{

## This case statement determines which heading text we need to use in jamfHelper for each policy trigger
case $trigger in
	Office2019)
	heading_text="Microsoft Office"
	;;
	chrome)
	heading_text="Chrome"
	;;
	firefox)
	heading_text="Firefox"
	;;
	zoom)
	heading_text="Zoom"
	;;
esac

## Call jamfHelper and customize the display slightly
"$jamf_helper" \
	-windowType utility \
	-title "Base App Installs" \
	-heading "$heading_text" \
	-description "Completing Step $i of $total_steps" \
	-icon "$icon" &
	## Call the Jamf policy by it's event trigger
	/usr/local/bin/jamf policy -event "$trigger"
	/bin/sleep 2
	## Shut down the jamfHelper background process to get ready for the next one
	killall jamfHelper
}

## Start the loop over the custom event triggers array
## For each one it processes, it calls the function above
## We increase the count of the "step" after each one completes
i=1;
for trigger in "${custom_triggers[@]}"; do
	echo "Calling policy trigger $trigger"
	callPolicy
	let i=$((i+1))
done

## When we get to this point, we're done with the policy loop, so show the installs complete message here
"$jamf_helper" \
	-windowType utility \
	-title "Base App Installs" \
	-heading "Completed Installs" \
	-description "Base App Installs Complete." \
	-icon "$icon" \
	-timeout 2

## Final message
"$jamf_helper" \
	-windowType utility \
	-lockHUD \
	-icon "$icon" \
	-title "Tech Office" \
	-heading "Base App Installs Complete" \
	-description "Click Continue for Login Screen" \
	-button1 "Continue" -defaultButton 1

exit 0

GabeShack
Valued Contributor III

@mm2270 Thats much cleaner for sure! Thanks for that, I had seen some other scripts that included a loop and I again just did what I knew to work already, so this is a great improvement.  I'm still in the process of testing that this works and looks ok but this is a great template for me to continue to use and modify and like I said preliminary testing is showing promise for this workflow!  I really appreciate you time and help as always, you are truly Legendary lol!

 

Gabe Shackney
Princeton Public Schools