Script to set Department not running on Enrollment

el2493
Contributor III

I have a script that prompts a tech to set the department of a computer:

#!/bin/sh    

## Establish API Credentials
# https://github.com/jamfit/Encrypted-Script-Parameters

function DecryptString() {
    # Usage: ~$ DecryptString "Encrypted String" "Salt" "Passphrase"
    echo "${1}" | /usr/bin/openssl enc -aes256 -d -a -A -S "${2}" -k "${3}"
}

apiUserEncrypt=$4
apiPassEncrypt=$5

apiUsername=$(DecryptString $apiUserEncrypt 'salt' 'passphrase')
apiPassword=$(DecryptString $apiPassEncrypt 'salt' 'passphrase')

## Use API to get computer Site from UUID
# Get computer's UUID
compUUID=$(system_profiler SPHardwareDataType | awk '/UUID/ { print $3; }')

compRaw=$(curl https://jssurl/JSSResource/computers/udid/${compUUID} --user "$apiUsername:$apiPassword")
echo $compRaw
compSite=$(echo $compRaw | xpath '//general/site/name' 2>&1 | awk -F'<name>|</name>' '{print $2}')
echo "compSite is"$compSite

if [[ $compSite == *"Example" ]]; then
    deptName="Example"
elif [[ $compSite = *"Example2" ]]; then
    deptName="Example2"
elif [[ $compSite == *"Example3" ]]; then
    deptName="Example3"
fi
echo "deptName is "$deptName

## Use API to get list of departments
deptRaw=$(curl https://jssurl/JSSResource/departments --user "$apiUsername:$apiPassword")
echo $deptRaw

# https://bryson3gps.wordpress.com/2014/03/30/the-jss-rest-api-for-everyone/
deptList=$(echo $deptRaw | xpath '//department/name' 2>&1 | awk -F'<name>|</name>' '{print $2}')
echo $deptList

if [ -z "$deptName" ]; then
    echo "deptName not defined"
else
for department in ${deptList[@]}
do
    if [[ $department == "$deptName"* ]]; then
        # https://macscripter.net/viewtopic.php?id=35318
        f=${department##*/}
        if [ "${f:0:1}" = "_" ] ; then
            echo "NOT Processing $department" 1>&2      # for now just a test
        else 
            if [[ ! -z ${deptParsed} ]] ; then
                deptParsed=${deptParsed}","
            fi
            echo "Processing $department" 1>&2
            deptParsed=${deptParsed}"""${f}"""   # to create "item1","item2","item..n"
    fi
done 
    # https://macscripter.net/viewtopic.php?id=35318
    deptChosen="$(/usr/bin/osascript -e 'tell application "System Events" to activate' -e 'tell application "System Events" to return (choose from list {'"$deptParsed"'} with prompt "Choose a Department:" with title "Department Chooser" OK button name "Select" cancel button name "Quit")')"
fi  

sudo /usr/local/bin/jamf recon -department "$deptChosen"
sudo /usr/local/bin/jamf recon

If I run this in Self Service it works fine. However if I try to run it on enroll and have Console open to jamf.log, I see that it starts to run the policy, then hangs, then moves onto the next policy without opening up the AppleScript window.

Any idea why this would happen? I'd like to set this on enroll if possible.

13 REPLIES 13

ryan_ball
Valued Contributor

Why don't you write your echos to a file so you can see at what point the script might stop? Also I think the double recons are redundant. Specifying the department in the recon will still do a full recon.

el2493
Contributor III

@ryan.ball thanks, I thought the double recon might be redundant, added the 2nd after the last time this didn't work. Will remove the 2nd.

If I look in the logs in jamf, it looks like it gives a

36:44: execution error: An error of type -10810 has occurred. (-10810)
message when it's trying to run the AppleScript command. It shows "Processing" for all the departments that I'd expect to see, and then in my actual script I have it echo $deptParsed and $deptChosen after the AppleScript command. It echos $deptParsed so I know it was defined correctly, but $deptChosen is blank (which makes sense; since the popup window didn't come up I couldn't choose anything). Maybe I'll try to build it so that if $deptChosen isn't defined it'll run the AppleScript command again (giving up after a certain amount of tries to it doesn't get stuck in a loop).

boberito
Valued Contributor

Osascript is running as Root I believe. So that's why it's bombing....I THINK. I could be wrong about that.

ryan_ball
Valued Contributor

After looking at it a bit more closely, I have a few things to point out. The biggest one would be that you were missing a 'fi' in this section which would cause an issue:

if [ "${f:0:1}" = "_" ] ; then
            echo "NOT Processing $department" 1>&2      # for now just a test
        else 
            if [[ ! -z ${deptParsed} ]] ; then
                deptParsed=${deptParsed}","
            fi
            echo "Processing $department" 1>&2
            deptParsed=${deptParsed}"""${f}"""   # to create "item1","item2","item..n"

Next, the applescript list seems to be populated by the deptParsed variable, which to me seems like it is undefined. You are setting deptParsed to itself at one point, but at that point in the script deptParsed is null, so I don't see how this would work at all.

I linted the script and quoted a bunch of the variables to prevent globbing and word splitting as shown below (added the missing 'fi'):

#!/bin/bash

## Establish API Credentials
# https://github.com/jamfit/Encrypted-Script-Parameters

function DecryptString() {
    # Usage: ~$ DecryptString "Encrypted String" "Salt" "Passphrase"
    echo "${1}" | /usr/bin/openssl enc -aes256 -d -a -A -S "${2}" -k "${3}"
}

apiUserEncrypt=$4
apiPassEncrypt=$5

apiUsername=$(DecryptString "$apiUserEncrypt" 'salt' 'passphrase')
apiPassword=$(DecryptString "$apiPassEncrypt" 'salt' 'passphrase')

## Use API to get computer Site from UUID
# Get computer's UUID
compUUID=$(system_profiler SPHardwareDataType | awk '/UUID/ { print $3; }')

compRaw=$(curl "https://jssurl/JSSResource/computers/udid/${compUUID}" --user "$apiUsername:$apiPassword")
echo "$compRaw"
compSite=$(echo "$compRaw" | xpath '//general/site/name' 2>&1 | awk -F'<name>|</name>' '{print $2}')
echo "compSite is $compSite"

if [[ $compSite == *"Example" ]]; then
    deptName="Example"
elif [[ $compSite = *"Example2" ]]; then
    deptName="Example2"
elif [[ $compSite == *"Example3" ]]; then
    deptName="Example3"
fi
echo "deptName is "$deptName

## Use API to get list of departments
deptRaw=$(curl https://jssurl/JSSResource/departments --user "$apiUsername:$apiPassword")
echo "$deptRaw"

# https://bryson3gps.wordpress.com/2014/03/30/the-jss-rest-api-for-everyone/
deptList=$(echo "$deptRaw" | xpath '//department/name' 2>&1 | awk -F'<name>|</name>' '{print $2}')
echo $deptList

if [[ -z "$deptName" ]]; then
    echo "deptName not defined"
else
for department in $"{deptList[@]}"
do
    if [[ $department == "$deptName"* ]]; then
        # https://macscripter.net/viewtopic.php?id=35318
        f=${department##*/}
        if [[ "${f:0:1}" = "_" ]]; then
            echo "NOT Processing $department" 1>&2      # for now just a test
        else
            if [[ ! -z ${deptParsed} ]]; then
                deptParsed=${deptParsed}","
            fi
            echo "Processing $department" 1>&2
            deptParsed=${deptParsed}"""${f}"""   # to create "item1","item2","item..n"
        fi
    fi
done
    # https://macscripter.net/viewtopic.php?id=35318
    deptChosen="$(/usr/bin/osascript -e 'tell application "System Events" to activate' -e 'tell application "System Events" to return (choose from list {'"$deptParsed"'} with prompt "Choose a Department:" with title "Department Chooser" OK button name "Select" cancel button name "Quit")')"
fi

sudo /usr/local/bin/jamf recon -department "$deptChosen"
sudo /usr/local/bin/jamf recon

el2493
Contributor III

@boberito thanks, I did see on https://jacobsalmela.com/2014/08/04/infamous-execution-error-error-type-10810-occurred-10810/ that one of the causes of the error message could be if it's running as root. Though wouldn't running it through Self Service (where it worked fine) also qualify as running it as root?

In either case, I'm trying to figure out how to change the command so that it runs as the currently logged in user (it's tripping me up because of the "quotation marks inside quotation marks" thing). Maybe it'd be easier to just call it as a function?

loggedInUser=$(stat -f "%Su" /dev/console)
userprompt() {
/usr/bin/osascript -e 'tell application "System Events" to activate' -e 'tell application "System Events" to return (choose from list {'"$deptParsed"'} with prompt "Choose a Department:" with title "Department Chooser" OK button name "Select" cancel button name "Quit")')
}
su "$loggedInUser" -c userprompt

I'll have to test that and check

boberito
Valued Contributor

So multiple ways to get the currently logged in User

This is the way I like.

LoggedInUser=$(ls -l /dev/console | awk '{ print $3 }')
echo ${LoggedInUser}

But Jamf supplies the currently logged in user as $3. But I've found it to not be as reliable. There are other ways to grab it as well.

LoggedInUser=$3
echo ${LoggedInUser}

I think this may be the more universally liked way. But all 3 do it the same way.

LoggedInUser=$(/usr/bin/python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");')

echo ${LoggedInUser}

so then to run as another user

sudo -u ${LoggedInUser} /my/command/I/want/run

el2493
Contributor III

@ryan.ball thanks for catching the missing "fi", I actually do have it in the script I'm using but I must've accidentally deleted it when stripping out any personal information before posting the script here. If I didn't have it, though, your catch would've been very helpful.

I don't 100% understand how $deptParsed is set (I got the procedure from somewhere else), but I believe the line deptParsed=${deptParsed}"""${f}""" is saying to take the existing $deptParsed value and append $f, which is the current department that's being parsed. So it's not actually setting $deptParsed it to itself. In any case, when the AppleScript does run, the items in $deptParsed are presented the way I want them to be.

ryan_ball
Valued Contributor

It is odd, but if it works then that is the important part.

You could try this:

loggedInUID=$(ls -ln /dev/console | awk '{ print $3 }')
deptChosen="$(launchctl asuser "$loggedInUID" /usr/bin/osascript -e 'tell application "System Events" to activate' -e 'tell application "System Events" to return (choose from list {'"$deptParsed"'} with prompt "Choose a Department:" with title "Department Chooser" OK button name "Select" cancel button name "Quit")')"

Also, have you ever looked at CocoaDialog? There are a lot of threads about it here. You can display a list much easier than with applescript without all the odd escaping and whatnot. Just a thought.

el2493
Contributor III

@boberito thanks for the many options, I was more concerned if I'm going to have problems when I try to run the command and have quotes in quotes:

su "$loggedInUser" -c "/usr/bin/osascript -e 'tell application "System Events" to activate' -e 'tell application "System Events" to return (choose from list {'"$deptParsed"'} with prompt "Choose a Department:" with title "Department Chooser" OK button name "Select" cancel button name "Quit")'"

#or your version, which I think you say doesn't require the quotes

sudo -u ${LoggedInUser} /usr/bin/osascript -e 'tell application "System Events" to activate' -e 'tell application "System Events" to return (choose from list {'"$deptParsed"'} with prompt "Choose a Department:" with title "Department Chooser" OK button name "Select" cancel button name "Quit")'

Will try yours first or play around with these to get something working.

boberito
Valued Contributor

I'd avoid CocoaDialog since it's dead basically.

Pashua is harder and more complex but still alive as a project.

I wish jamfnotifier did all this stuff :(

el2493
Contributor III

@ryan.ball we do install CocoaDialog (I use it on a separate script that sets a computer's hostname), but try to avoid using it in most cases since:

a) I'm not overly familiar with it.
b) I've heard (like @boberito said) that it's not being developed anymore, so if I'm building something new and fairly simple I figure AppleScript is probably more future-proof (though doesn't seem to have as many features as CocoaDialog).

@boberito I've read a little about Pashua, but I feel like (as you pointed out) from what I read it was going to be too difficult for me at the time.

Thank you both again for your assistance, this has been very helpful and hopefully will solve the issue!

cdenesha
Valued Contributor II

A recent blog post addresses a few of these points, including the problem with nested quotes (search for 'here document').

el2493
Contributor III

@cdenesha thanks, that's a very well-written and thorough article! Bookmarking it for any other time I need to use display dialog.