Script should only run after successful package install

denmoff
Contributor III

I have a cocoadialog script that runs after a package is installed. So, when i have the latest java is installed/updated, a bubble will appear for the user notifying them that Java has been installed/updated. The problem i run into on occasion is that the package fails to install but the script runs anyway. Is there any way around this without having multiple policies and smart groups?

Here's a feature request for this that i've created:
https://jamfnation.jamfsoftware.com/featureRequest.html?id=2107

1 ACCEPTED SOLUTION

mm2270
Legendary Contributor III

@denmoff][/url][/url - It might be possible to have a single script work with almost any install. What you'd need to do is set up a script parameter that would be the path to the Info.plist file for the installed application to grab either the "CFBundleVersion" or "CFBundleShortVersionString" Then a second script parameter that holds the version string you expect to see,

Take a script like the below for example:

#!/bin/sh

pathToPlist="$4"

expectedAppVers="$5"

## Quick check to make sure $4 and $5 are set
if [[ "$4" == "" ]] || [[ "$5" == "" ]]; then
    echo "Script paramaters are not set for this script. Please set up parameters 4 & 5 for this script as appropriate"
    exit 1
fi

installedAppVers=$( /usr/bin/defaults read "$4" CFBundleShortVersionString )

if [[ "${installedAppVers}" != "${expectedAppVers}" ]]; then
    echo "App installs may have failed. Exiting silently..."
    exit 1
else
    echo "App install successful. Notifying user"
    ## do cocoaDialog stuff here, or call a function block, for example:
    "/Library/Application Support/JAMF/bin/cocoaDialog.app/Contents/MacOS/cocoaDialog" notify 
    --no-growl --title "Flash Player" --text "Flash Player has been updated on your Mac." 
    --background-top ffffff --background-bottom ffffff --text-color 000000 --alpha 1
fi

Save this script somewhere and run it with the following syntax as a test-

sudo jamf runScript -script "scriptname.sh" -path "/path/to/script/" -p1 "/Library/Internet Plug-Ins/Flash Player.plugin/Contents/Info.plist" -p2 "13.0.0.182"

This will send up a white "bubble" cocoaDialog message with the text indicated only if FlashPlayer is updated to or is version "13.0.0.182", otherwise it exits silently.

You could conceivably also place all the messaging text into script parameters, like $6 and $7 as well to make it really flexible. Since using defaults against a plist is a pretty standard way to get version information for Apps, plug-ins, etc, I'd imagine this could be used for most checks. Although it may not work with certain installations.

View solution in original post

14 REPLIES 14

mm2270
Legendary Contributor III

You can just have the script check for the installed version of Java before running, using something like the java -version command. If you need it be flexible as far as the version, pass down the version string to check for as a script parameter instead of hardcoding it into the script. That way you can use the same script each time you push out a new version of Java.

In the script, either exit if the install failed, i.e, the version of Java does not match what should have been installed, or if it does match, send up the cocoaDialog notification.

I do something similar with a Self Service policy that will install an OS X Combo update. Since the OS gets the new OS version information even before a reboot, I can have the script check to see if the version now matches what I intended to install and if successful, runs a function to alert the user and schedule a reboot. If unsuccessful, it alerts the user that the install failed and to contact support.

JPDyson
Valued Contributor

Yep; the script needs to do the work of detecting whether it should alert or now.

denmoff
Contributor III

Thanks @mm2270. I was planning to use this script for every app install. So it would need to be very flexible. Jamf may have to come up with a solution to this. Quit on any failure type of option. Or more fitting would be for that to be the default process and you'd have an option to ignore failures.

mm2270
Legendary Contributor III

@denmoff][/url][/url - It might be possible to have a single script work with almost any install. What you'd need to do is set up a script parameter that would be the path to the Info.plist file for the installed application to grab either the "CFBundleVersion" or "CFBundleShortVersionString" Then a second script parameter that holds the version string you expect to see,

Take a script like the below for example:

#!/bin/sh

pathToPlist="$4"

expectedAppVers="$5"

## Quick check to make sure $4 and $5 are set
if [[ "$4" == "" ]] || [[ "$5" == "" ]]; then
    echo "Script paramaters are not set for this script. Please set up parameters 4 & 5 for this script as appropriate"
    exit 1
fi

installedAppVers=$( /usr/bin/defaults read "$4" CFBundleShortVersionString )

if [[ "${installedAppVers}" != "${expectedAppVers}" ]]; then
    echo "App installs may have failed. Exiting silently..."
    exit 1
else
    echo "App install successful. Notifying user"
    ## do cocoaDialog stuff here, or call a function block, for example:
    "/Library/Application Support/JAMF/bin/cocoaDialog.app/Contents/MacOS/cocoaDialog" notify 
    --no-growl --title "Flash Player" --text "Flash Player has been updated on your Mac." 
    --background-top ffffff --background-bottom ffffff --text-color 000000 --alpha 1
fi

Save this script somewhere and run it with the following syntax as a test-

sudo jamf runScript -script "scriptname.sh" -path "/path/to/script/" -p1 "/Library/Internet Plug-Ins/Flash Player.plugin/Contents/Info.plist" -p2 "13.0.0.182"

This will send up a white "bubble" cocoaDialog message with the text indicated only if FlashPlayer is updated to or is version "13.0.0.182", otherwise it exits silently.

You could conceivably also place all the messaging text into script parameters, like $6 and $7 as well to make it really flexible. Since using defaults against a plist is a pretty standard way to get version information for Apps, plug-ins, etc, I'd imagine this could be used for most checks. Although it may not work with certain installations.

mm2270
Legendary Contributor III

I also just wanted to say that I do agree with you that there should be a built in way to indicate that a script set to 'After" should only run on the condition that previous steps in the policy exited with a 0 status, otherwise skip them.
While my workaround above may do the trick in this particular case, there are dozens of other possible cases where having the policy determine its own status and then running scripts would be beneficial.

denmoff
Contributor III

Again, thanks @mm2270. You always come thru with great solutions. This certainly solves my issue. I'm still going to leave the feature request up for the reason you just mentioned.

mm2270
Legendary Contributor III

Just to post a more "complete" version of the script above, this one will let you set parameters for the installed version, the version to check, the bubble title (optional), the bubble text and a custom icon (optional)

#!/bin/sh

## Set the path to the app or plug-in plist to check
pathToPlist="$4"

## Set the expected app or plug-in version string
expectedAppVers="$5"

## Set the notification title text
titleText="$6"

## Set the notification text
subjText="$7"

## Set a custom icon path
iconPath="$8"

## Quick check to make sure $4 and $5 are set
if [[ "$4" == "" ]] || [[ "$5" == "" ]] || [[ "$7" == "" ]]; then
    echo "Script paramaters are not set for this script. Please set up parameters 4, 5 & 7 for this script as appropriate"
    exit 1
fi

if [[ "$6" == "" ]]; then
    titleText="Some Company IT"  ## Set to appropriate title for your environment
fi

if [[ "$8" == "" ]]; then
    iconPath="/path/to/your/company/logo/or/image.png" ## Use any .png, .jpg, .tif, etc file somewhere on the Mac
fi

## Get the installed version string from the source Info.plist
installedAppVers=$( /usr/bin/defaults read "$4" CFBundleShortVersionString )

if [[ "${installedAppVers}" != "${expectedAppVers}" ]]; then
    echo "App installs may have failed. Exiting silently..."
    exit 1
else
    echo "App install successful. Notifying user"
    ## do cocoaDialog stuff here, or call a function block, for example:
    "/Library/Application Support/JAMF/bin/cocoaDialog.app/Contents/MacOS/cocoaDialog" notify 
    --no-growl --title "$titleText" --text "$subjText" --icon-file "$iconPath" 
    --background-top ffffff --background-bottom ffffff --text-color 000000 --alpha 1
fi

hcodfrie
Contributor

@mm2270 i was looking for a way to send a bubble with coco with the icon file of the app thats been installed or updated , i was ending up running a command after a policy has been started.

I will test your last version of this script hope it works for me, saves me a lot of work the only thing you need to do is find the icns file of for example google chrome .....

/Applications/Google Chrome.app/Contents/Resources/app.icns

Past that in $8 and users get the icon right ?

hcodfrie
Contributor

Hallo @mm2270 nice script ! I got some apps that don't contain an cfbundelversionstring can you make this script with multiple strngs to check the version ?

mm2270
Legendary Contributor III

Sure, that's because some applications don't have that entry in their plist. It might be located in CFBundleVersion (note the difference between that and "CFBundleShortVersionString")

Here's a modified version that should hopefully catch those instances. I bolded the elements I added to it.

#!/bin/sh

## Set the path to the app or plug-in plist to check
pathToPlist="$4"

## Set the expected app or plug-in version string
expectedAppVers="$5"

## Set the notification title text
titleText="$6"

## Set the notification text
subjText="$7"

## Set a custom icon path
iconPath="$8"

## Quick check to make sure $4 and $5 are set
if [[ "$4" == "" ]] || [[ "$5" == "" ]] || [[ "$7" == "" ]]; then
    echo "Script paramaters are not set for this script. Please set up parameters 4, 5 & 7 for this script as appropriate"
    exit 1
fi

if [[ "$6" == "" ]]; then
    titleText="Some Company IT"  ## Set to appropriate title for your environment
fi

if [[ "$8" == "" ]]; then
    iconPath="/path/to/your/company/logo/or/image.png" ## Use any .png, .jpg, .tif, etc file somewhere on the Mac
fi

## Get the installed version string from the source Info.plist
**## Added sending errors to /dev/null to ensure a blank result for any apps that don't store their version in CFBundleShortVersionString**
installedAppVers=$( /usr/bin/defaults read "$4" CFBundleShortVersionString **2> /dev/null** )

**## If CFBundleShortVersionString returned as blank, try getting the version from 'CFBundleVersion' instead
if [[ "${installedAppVers}" == "" ]]; then
    installedAppVers=$( /usr/bin/defaults read "$4" CFBundleVersion )
fi**

if [[ "${installedAppVers}" != "${expectedAppVers}" ]]; then
    echo "App installs may have failed. Exiting silently..."
    exit 1
else
    echo "App install successful. Notifying user"
    ## do cocoaDialog stuff here, or call a function block, for example:
    "/Library/Application Support/JAMF/bin/cocoaDialog.app/Contents/MacOS/cocoaDialog" notify 
    --no-growl --title "$titleText" --text "$subjText" --icon-file "$iconPath" 
    --background-top ffffff --background-bottom ffffff --text-color 000000 --alpha 1
fi

hcodfrie
Contributor

You the man ...it works

hcodfrie
Contributor

Hey @mm2270 i have been using this script to run and notify a user when an application has been installed or updated successfully, the notification works and the last 2 lines look like this:

Script exit code: 0
Script result: App install successful. Notifying user

What i am seeing is that when no user has logged in to that Mac it generates an error like this

Script exit code: 0
Script result: App install successful. Notifying user
_RegisterApplication(), FAILED TO establish the default connection to the WindowServer, _CGSDefaultConnection() is NULL.

The application has been updated but the JSS notes the policy as FAILED, how can i suppress message?

mm2270
Legendary Contributor III

@hcodfrie-
I think back when I posted the above script, I was assuming this would be used from a Self Service policy, perhaps. Although looking back at the original post, that isn't specifically mentioned.

Anywho, the issue is that you can't have a cocoaDialog display of any kind if the Mac is sitting at the login screen. So you need to detect the owner of console and if its not "root" then display the message. If root owns console, no-one is logged in, so just report back if the install was successful and exit without trying to display anything.

Here's an updated version that I think should take care of that. This is a better approach than trying to suppress the error. Just avoid the error altogether.

#!/bin/sh

## Set the path to the app or plug-in plist to check
pathToPlist="$4"

## Set the expected app or plug-in version string
expectedAppVers="$5"

## Set the notification title text
titleText="$6"

## Set the notification text
subjText="$7"

## Set a custom icon path
iconPath="$8"

## Quick check to make sure $4 and $5 are set
if [[ "$4" == "" ]] || [[ "$5" == "" ]] || [[ "$7" == "" ]]; then
    echo "Script paramaters are not set for this script. Please set up parameters 4, 5 & 7 for this script as appropriate"
    exit 1
fi

if [[ "$6" == "" ]]; then
    titleText="Some Company IT"  ## Set to appropriate title for your environment
fi

if [[ "$8" == "" ]]; then
    iconPath="/path/to/your/company/logo/or/image.png" ## Use any .png, .jpg, .tif, etc file somewhere on the Mac
fi

## Get the installed version string from the source Info.plist
## Added sending errors to /dev/null to ensure a blank result for any apps that don't store their version in CFBundleShortVersionString
installedAppVers=$( /usr/bin/defaults read "$4" CFBundleShortVersionString 2> /dev/null )

## If CFBundleShortVersionString returned as blank, try getting the version from 'CFBundleVersion' instead
if [[ "${installedAppVers}" == "" ]]; then
    installedAppVers=$( /usr/bin/defaults read "$4" CFBundleVersion )
fi

if [[ "${installedAppVers}" != "${expectedAppVers}" ]]; then
    echo "App installs may have failed. Exiting silently..."
    exit 1
else
    **if [[ $(ls -l /dev/console | awk '{print $3}') != "root" ]]; then**
        echo "App install successful. Notifying user"
        ## do cocoaDialog stuff here, or call a function block, for example:
        "/Library/Application Support/JAMF/bin/cocoaDialog.app/Contents/MacOS/cocoaDialog" notify 
        --no-growl --title "$titleText" --text "$subjText" --icon-file "$iconPath" 
        --background-top ffffff --background-bottom ffffff --text-color 000000 --alpha 1
    else
        echo "App install successful. No-one logged in. Exiting silently."
    fi
fi

The bolded line above is the main thing I added to it.
Give that a try and see how it works.

All that said, nowadays I think you can just use the built in User Interaction in 9.x to do this in Notification Center, no?

hcodfrie
Contributor

Hey @mm2270 thx for your working version, i prefer a cocodialog instead of using the Notification Center.
If the notification workflow works with casper i will start using it