Extension attribute help

bbot
Contributor

I'm trying to use an extension attribute to tell if a program is installed by looking at a few folders to see if the folder/files exist. It's reporting if it's Not Installed, but it's not telling me if it's installed. Am i doing something wrong?

#!/bin/bash

 #xclient is a unix executable
    if [ ! -f /usr/local/bin/xClient ]; then
        echo "<result>Not Installed</result>"

#xmetering is a unix executable
        if [ ! -f /usr/local/bin/xMetering ]; then
            echo "<result>Not Installed</result>"

#snowclient.conf is a config file
            if [ ! -f /etc/snowclient.conf ];then
                echo "<result>Not Installed</result>"

#Snow software is a directory
                if [ ! -d /Library/Application Support/Snow Software ]; then
                    echo "<result>Not Installed</result>"

        else
    echo "<result>Installed</result>"

                fi
            fi
        fi
    fi
13 REPLIES 13

CapU
Contributor III

Another way is to create a smart group with the Criteria as Packages installed by Casper

bbot
Contributor

@CapU That was a million times easier. I got it setup in less than 5 minutes... Thanks!

CapU
Contributor III

Glad I could help

pcrandom
Contributor

I know you've already gotten it done an easier way, but FYI - your script would only generate an "Installed" result for the EA if the Snow Software directory existed. The else is within the if ... fi for that check only. If you want the result to be "Installed" if all the conditions are met, I mean not met (since you're testing for the absence of the files), then you'd want the else at the top level:

#!/bin/bash

#xclient is a unix executable
if [ ! -x /usr/local/bin/xClient ]; then
    echo "<result>Not Installed</result>"
    exit 0

    #xmetering is a unix executable
    if [ ! -x /usr/local/bin/xMetering ]; then
        echo "<result>Not Installed</result>"
        exit 0

        #snowclient.conf is a config file
        if [ ! -f /etc/snowclient.conf ];then
            echo "<result>Not Installed</result>"
            exit 0

            #Snow software is a directory
            if [ ! -d /Library/Application Support/Snow Software ]; then
                echo "<result>Not Installed</result>"
                exit 0
            fi #Snow software is a directory

        fi #snowclient.conf is a config file

    fi #xmetering is a unix executable

else
    echo "<result>Installed</result>"

fi #xclient is a unix executable

exit 0

I'm sure there are more efficient ways of doing the above, but I just moved your pieces around. I changed some of the tests to -x since you want to know if some files were executable. I also had the script exit after echoing one of the "Not Installed" results, since it doesn't need to process the rest of the checks.

If it's the case that the result should be "Not Installed" if any of the files/directories do not exist, then you don't actually need to nest the if statements, which makes it an easier read. You can also replace the repetitive results echoing and exiting with a function, and leaving the last echo line for "Installed" will only run if all the if conditions are not met.

#!/bin/bash

function ea_not {
    echo "<result>Not Installed</result>"
    exit 0
}

#xclient is a unix executable
if [ ! -x /usr/local/bin/xClient ]; then
    ea_not
fi

#xmetering is a unix executable
if [ ! -x /usr/local/bin/xMetering ]; then
    ea_not
fi

#snowclient.conf is a config file
if [ ! -f /etc/snowclient.conf ];then
    ea_not
fi

#Snow software is a directory
if [ ! -d /Library/Application Support/Snow Software ]; then
    ea_not
fi

echo "<result>Installed</result>"

exit 0

Just for fun, and because I'm still a novice at scripting, I made up a version of this second script using arrays and a for loop. No idea if this would work...

#!/bin/bash

filechecks=( "-x /usr/local/bin/xClient" "-x /usr/local/bin/xMetering" "-f /etc/snowclient.conf" "-d /Library/Application Support/Snow Software" )

for check in "${filechecks[@]}"
do
    if [ ! "$check" ] ; then
        echo "<result>Not Installed</result>"
        exit 0
    fi
done

echo "<result>Installed</result>"

exit 0

Look
Valued Contributor III

Rather than excluding when something is missing, include if everything is present, it just seems cleaner...
With the way bash works it should still exit out at the first failed file without having to force exit the statement.
Alternatively do it the way it was done originally using or || instead. Although I do quite like the editable list of requirements in the loop version.

#!/bin/bash

if [ -x /usr/local/bin/xClient ] && [ -x /usr/local/bin/xMetering ] && [ -f /etc/snowclient.conf ] && [ -x /usr/local/bin/xMetering ] && [ -f /etc/snowclient.conf ] && [ -d /Library/Application Support/Snow Software ]; then
    echo "<result>Installed</result>"
else
echo "<result>Not Installed</result>"
fi

pcrandom
Contributor

Thanks @Look, I originally thought of flipping it around from testing for the negative (also easier to talk about without getting confused) but I just stuck with the OP's original structure, in case s/he had a reason for the negative checks.

I like the array too. One question for you (or anyone with more scripting experience) would be whether the last item in the array, "-d /Library/Application Support/Snow Software", would need the escaping the spaces in the filename since it's included in quotes. I know in some cases, like paths with the scp command you actually have to use multiple escapes because as the command gets passed from system to system, it "uses up" each layer of escapes...

So I feel like when the array is slotted into the $check in the for loop, it might lose the quotes (though I did put "$check" in quotes too, per shellcheck.net's recommendation to prevent globbing and word splitting), so it's good to also escape with . However, I assume having too many escape "layers" isn't good either. I guess I could test it myself but just in case people knew off the top of their heads.

bbot
Contributor

@pcrandom Unintentional negative checks.. just a rookie scripter.

Thanks for all your input @Look and @pcrandom Definitely bookmarking this for the next time I need to write an EA.

Look
Valued Contributor III

@pcrandom To be honest on the escape character I'm not certain how it will pass that. I have a personal preference for not using escape characters unless I need to and usually just use quote marks around it when I call it to ensure it reads as written.
I really don't play with arrays much at all though.

pcrandom
Contributor

Glad to help @bbot. I'm definitely a novice too, but I like coming across these and trying to "fix" them (especially as it's low risk since you already an alternative method to get what you needed). Definitely check out shellcheck.net, it's helped me a lot with my bash scripts. And There's definitely better threads out there to bookmark on creating EAs than with my examples. ;-)

bcbackes
Contributor III

Sure glad I ran by this. I was using a Smart Group to determine if SNOW was installed by using the JSS installed packages criteria. However, if someone installed it and then uninstalled it, the computer would still populate the Smart Group - from what I'm seeing in my testing.

I used part of @Look's script above and tweaked it to my liking. I was able to pull in those with SNOW installed via Extension Attribute. Now, I have a more accurate Smart Group that I can use.

#!/bin/bash

if [ -x /opt/snow/snowagent ] && [ -f /opt/snow/snowagent.config ]; then
    echo "<result>Installed</result>"
else
echo "<result>Not Installed</result>"
fi

daniel_ross
Contributor III

@bcbackes so I to am glad I found this as I was struggling with this and still to a degree am. So I have the one you see below:

#!/bin/bash

if [ -d /Library/Application Support/CrowdStrike/Falcon ] && [ -d /Applications/Falcon.app/Contents/Resources ]; then
    echo "<result>Installed</result>"
else
echo "<result>Not Installed</result>"
fi

But it came back on a known good machine with not installed. So I thought ok break each one down and whats odd is that

/Library/Application Support/CrowdStrike/Falcon

Doesn't work and I'm wondering if thats due to SIP protection? Even on its own it shows no folder is "installed" but I can get to it without issue within finder or see it in terminal. Any thoughts?

Mauricio
Contributor III

@daniel_ross Hi Daniel you will need to escape the space in 'Application Support'.

I've run your script with this change.

#!/bin/bash
if [ -d /Library/Application Support/CrowdStrike/Falcon ] && [ -d /Applications/Falcon.app/Contents/Resources ]; then
 echo "<result>Installed</result>"
else
 echo "<result>Not Installed</result>"
fi

It worked fine. However as you are looking for directories one could have a false positive.
Could I suggest looking for the binary executable instead?

#!/bin/bash

if [ -d /Library/Application Support/CrowdStrike/Falcon ] && [ -x /Applications/Falcon.app/Contents/MacOS/Falcon ]; then
  echo "<result>Installed</result>"
else
  echo "<result>Not Installed</result>"
fi

I hope this helps.
Regards

bcbackes
Contributor III

I know this is an old post but if someone comes across this and is looking to find a way to report back the version of SNOW that is installed on their Macs I was able to create this extension attribute to report that information back. If SNOW isn't installed it will report "Not Installed" instead. Hope this helps others!

#!/bin/bash

if [ -x /opt/snow/snowagent ]; then
    version=$(/opt/snow/snowagent version)
    echo "<result>$version</result>"
else
echo "<result>Not Installed</result>"
fi