Please help with script for EA

mhasman
Valued Contributor

I am working on updating the EA, and stuck on format of evaluating an expression.



CURRENT_EXCEL_VERSION="15.20"

if [ -d /Applications/Microsoft Excel.app ]

then

EXCEL_VERSION=$( sudo defaults read /Applications/Microsoft Excel.app/Contents/Info.plist CFBundleShortVersionString )

else

echo "<result>OfficeNotInstalled</result>"

fi

if [ $EXCEL_VERSION -lt $CURRENT_EXCEL_VERSION ]

then

echo "<result>True</result>"

else

echo "<result>False</result>"

fi


The first "if" works as well, 2nd "if" returns "False" all the time. I understand that it is because of non-number, string value like "15.19.1" vs "15.20", but do not know how to the evaluating an expression should be changed.

Would you please help?

Thanks!

16 REPLIES 16

CAJensen01
Contributor

Here's what I'm doing for a Microsoft Office EA, to make it an integer for easier scoping. Ultimately, it makes the number five digits. 15.18.0 would convert to 15180, and 15.19.1 becomes 15191. A smart group can then be set to update to 15.19.1 if the value is greater than 0 (meaning installed) and less than 15190

#!/bin/sh

if [ -x "/Applications/Microsoft Outlook.app" ]; then
    IFS='.'
    ## Here we read in the current version number, and put it into an array.
    VERSIONNATIVE=`defaults read "/Applications/Microsoft Outlook.app/Contents/Info.plist" CFBundleShortVersionString`;
    arrVERSIONNATIVE=($VERSIONNATIVE)
    ## Here we remove the periods and spaces in the version number.
    VERSION=`echo $VERSIONNATIVE | sed 's/[.]//g' | sed 's/ //g'`
    var0='0';
    ## Counting gets the number of total digits
    COUNT=`echo ${#VERSION}`;  
    COUNTsubV=`echo ${#arrVERSIONNATIVE[0]}`;

    ## Check to see if there is a build number, if not, add zero digit. Eg 15.19 becomes 15190.
    if [ -z "${arrVERSIONNATIVE[2]}" ]; then
        arrVERSIONNATIVE[2]="$var0"
        echo "No build number, so appending a zero on the end of the number, to: " $VERSION
    fi
    ## Next, we need to see how many digits the secondary version number has, and ensure it ultimately has two.
    if [ $COUNTsubV -lt 2 ]; then
        arrVERSIONNATIVE[1]="$VERSION$var0";
        COUNT=`echo ${#VERSION}`
    fi

    VERSION=""${arrVERSIONNATIVE[0]}""${arrVERSIONNATIVE[1]}""${arrVERSIONNATIVE[2]}""
else
    VERSION="Not installed";
fi
echo "<result>$VERSION</result>;"

Taylor_Armstron
Valued Contributor

@CAJensen01 ... you are my hero. The "fake integer" version strings have been the bane of my existence since we set up Casper, I think I'm going to have to steal that approach. It will make like SOOOOO much easier for package management for us!

thoule
Valued Contributor II

Here's my section of code that does versioning... Part of a much larger piece of code.

#!/bin/sh

vercomp () {
#    echo "Starting: $1 $2"
    if [[ $1 == $2 ]]
    then
        return 0
    fi
    local IFS=.
    local i ver1=($1) ver2=($2)
    # fill empty fields in ver1 with zeros
    for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
    do
        ver1[i]=0
    done
    for ((i=0; i<${#ver1[@]}; i++))
    do
        if [[ -z ${ver2[i]} ]]
        then
            # fill empty fields in ver2 with zeros 
            ver2[i]=0
        fi
        if ((10#${ver1[i]} > 10#${ver2[i]})); then
            return 1
        fi
        if ((10#${ver1[i]} < 10#${ver2[i]}))
        then
            return 2
        fi
    done
    return 0
}

     latestVersion="13.4.5"
     appPath="/Applications/TextEdit.app"

        installedVersion=`defaults read "$appPath/Contents/Info.plist"  CFBundleShortVersionString'`

    vercomp $latestVersion $installedVersion
    newerApp=$?
    if [ $newerApp == 1 ]; then
    # An update is available. Record it for the GUI
    echo "update for $appPath is available"
    elif [ $newerApp == 2 ]; then
    echo "User has a newer version of $appName than on the server. Do Nothing"
    elif [ $newerApp == 0 ]; then
    echo "User has same version of $appName as is installed.  Do Nothing."
    else
    echo "Unknown Error occurred comparing version on $appName.  You have $installedVersion and the latest is $latestVersion."
    fi

mhasman
Valued Contributor

@CAJensen01 Thank you sir!

mhasman
Valued Contributor

@thoule Thank you very much!

stevewood
Honored Contributor II
Honored Contributor II

And just because, this is a Python script EA that is part of the AutoPKGr process for updating Office apps. This is set for 2011, but could easily be updated for 2016. I'm not sure if this is the work of @elliotjordan or not:

#!/usr/bin/python
'''Office version extension attribute.

Checks the lowest version number for the main apps if found.
Reports OfficeNotInstalled if something is missing.
Reports True if Office is in need of and capable of updating (min version met)
Reports False otherwise

Note: This a pretty minimal check for version and existence!

'''

from distutils.version import  StrictVersion
import subprocess
import os.path
import shlex
import sys

PREFIX = '/Applications/Microsoft Office 2011/'
FILES_TO_CHECK = {'Microsoft Excel.app/Contents/Info.plist',
                  'Microsoft Word.app/Contents/Info.plist',
                  'Microsoft Powerpoint.app/Contents/Info.plist',
                  'Microsoft Outlook.app/Contents/Info.plist'}
CURRENT_VERSION = StrictVersion('14.6.2')
MINIMUM_VERSION = StrictVersion('14.1.0')

results = []

for file in FILES_TO_CHECK:
    args = shlex.split('defaults read "%s" CFBundleShortVersionString'
                       % os.path.join(PREFIX, file))
    process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    output = process.communicate()
    if output[1]:
        result = 'OfficeNotInstalled'
        print '<result>%s</result>' % str(result)
        sys.exit()
    else:
        results.append(StrictVersion(output[0]))

results.sort()
result = results[0]

# 14.1.0 is required for upgrade packages
if result < CURRENT_VERSION and result >= MINIMUM_VERSION:
    result = True
else:
    result = False

print '<result>%s</result>' % str(result)

mhasman
Valued Contributor

@stevewood For some reason it does not work for me with Office 2016. AE shows no value

elliotjordan
Contributor III

@stevewood I think that's Shea Craig's extension attribute, originally created here. It's part of the jss-recipes repository, not actually part of AutoPkgr itself.

@mhasman The EA Steve posted is specific to Office 2011. No such EA is necessary for 2016 because the apps are now standalone, and trying to version them as a unit would serve no purpose. I use smart groups, examples of which can be found here: Word, Excel, PowerPoint, Outlook.

mhasman
Valued Contributor

@elliotjordan I also thought about using smart groups, but still prefer dealing with one EA instead of four smart groups

mhasman
Valued Contributor

@thoule Todd, question for you, please
Any chance I may call for vercomp () from if [] ? What would be the format, please? Like that:

if [ $(vercomp $latestVersion $installedVersion) == 1 ] then...

sean
Valued Contributor

@CAJensen01 Careful with that method.

Eg. which is greater

15.2.10 or 15.18.0

Check out my pre-flight offering on Adobe Versions
The getVersion checkVersion combo will compare each part of the version

elliotjordan
Contributor III

Python's LooseVersion class is a less painful way to compare versions, if you must use a script.

But the real solution is for Casper to intelligently compare versions itself. Take a moment to voice your opinion in this feature request, if you haven't already.

CAJensen01
Contributor

@sean , Not too worried about it. At this point I haven't seen MS release anything over a .1 build, and 15.2 is numbered as 15.20. But it's easily adjustable if it needs to be adjusted.

sean
Valued Contributor

@CAJensen01

You might not be too worried, but you are posting this script as a solution to others who may not totally understand the consequences or may try and apply it to other apps where it might be an issue. So highlighting for their benefit.

But as @elliotjordan has pointed out, this really should be handled by Casper if it doesn't yet.

thoule
Valued Contributor II

@mhasman To wrap it in an if block, it'll expect 0 as success. Or in this case, an update is available. So I adjust the vercomp function to return 0 if an update is avialable, then can call the function in an if block.

vercomp () {
#    echo "Starting: $1 $2"                                                                                                                                                     

    if [[ $1 == $2 ]]
    then
        return 2
    fi
    local IFS=.
    local i ver1=($1) ver2=($2)
    # fill empty fields in ver1 with zeros                                                                                                                                      

    for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
    do
        ver1[i]=0
    done
    for ((i=0; i<${#ver1[@]}; i++))
    do
        if [[ -z ${ver2[i]} ]]
            then
            # fill empty fields in ver2 with zeros                                                                                                                              

            ver2[i]=0
            fi
        if ((10#${ver1[i]} > 10#${ver2[i]})); then
            return 0
            fi
        if ((10#${ver1[i]} < 10#${ver2[i]}))
            then
            return 1
            fi
    done
    return 2
}

update() {
    appName="$1"
    latestVersion="$3"
    appPath="$2"
    updatePolicy="$4"

    installedVersion=`defaults read "$appPath/Contents/Info.plist"  CFBundleShortVersionString`

    if $(vercomp $latestVersion $installedVersion); then
        echo "update available for $appName.  $installedVersion is installed, but $latestVersion is out."
        jamf policy -event $updatePolicy
    else
        echo "no update right now for $appName.  $installedVersion is installed, but $latestVersion is out."
    fi
}

update "Text Edit Pro" "/Applications/TextEdit.app" "13.4.5" "updateTextEdit"
update "Microsoft Word" "/Applications/Microsoft Word.app" "15.20.0" "updateMSWord"

EDIT: wrapped the checking into a function 'update', so you can loop through different programs. And demo how you can update using custom triggers to call a jamf policy.

mhasman
Valued Contributor

@thoule Thank you sir!