Using data in JSS within scripts

winningham_2
Contributor

How does one go about calling data from the JSS for use in BASH scripts?

For example, I have the following code:

/System/Library/CoreServices/ManagedClient.app/Contents/Resources/createmobileaccount -n $username -h /Users/$username -S -v

For $username I would it to equal "Username" from a targeted computer within JSS> ComputerName> User and Location> Username.

My use case would be for users of Casper Remote who were to migrate Network managed users to Local managed users. They would select the target machine within Casper Remote and a script that basically performs the above. They don't really need to lookup who the user is because JSS knows what user this computer belongs to. So for them, this process is very easy because I am leveraging JSS's database.

2 ACCEPTED SOLUTIONS

Josh_S
Contributor III

The API in Casper v9 is quite improved. You could do this with a call similar to the following:

apiUsername='apiusername'
apiPassword='apipassword'
jssServer='https://jss.company.com:8443'
serialNumber='SERIALNUMBER'
username=$(curl -s -k -u "${apiUsername}:${apiPassword}" -H "Content-Type: application/xml" -X 'GET' "${jssServer}/JSSResource/computers/serialnumber/${serialNumber}/subset/Location" | xmllint --format - | awk -F '[<>]' '/username/ { print $3 }' )

Check out your api information at https://jss.company.com:8443/api/

I chose to use the serial number, mainly because it's something that is fairly easy to obtain. But you could use something else.

Edit: Of course, test (test and test again) in your own environment. This also doesn't really do any error checking to make sure something valid was returned. So make sure to verify the data you get back makes sense before running with it.

View solution in original post

winningham_2
Contributor

@Josh_S][/url][/url Thank you for the push in the right direction... I decided to do something like the below.

## Remember that $2 is reserved for *computer name* and we will use that here to allow the script to know the *username* of the computer it is ran against.
    apiUsername='apiusername'
    apiPassword='apipassword'
    jssServer='https://jss.company.com:8443'
    username=$(curl -s -k -u "${apiUsername}:${apiPassword}" -H "Content-Type: application/xml" -X 'GET' "${jssServer}/JSSResource/computers/match/$2" | xmllint --format - | awk -F '[<>]' '/username/ { print $3 }' )

## Below I am using $username, set above from the curl match, to automate the migration of the owner of this computer from a network-based account to a local-based account. 
/System/Library/CoreServices/ManagedClient.app/Contents/Resources/createmobileaccount -n $username -h /Users/$username -S -v

After limited testing, I think this will work great for what I need to accomplish. Cheers,
Tim

View solution in original post

5 REPLIES 5

mm2270
Legendary Contributor III

Hmm.. My first response was going to be to use the API, but unfortunately, for what you're looking for it may not be possible via that route. My knowledge of this is only as good as Casper Suite version 8.73, (I'm not clear on exactly what's new with version 9.x of the JSS) so take this with a grain of salt. But in version 8.x, getting the associated Machine to a user stored in the Location field is going to be tough. You can pull a list of computers and each record with have the associated username in its xml or json output, etc, but you'd have to somehow loop through each Mac one by one pulling out that data until it locates a match. This is obviously an unworkable scenario, even if you have a modest amount of Macs. It would take ages.

The only other way may be with some direct MySQL query or an application that can send a query to the JSS and get some output back. I don't know much of anything about doing that though so i can't help there. Perhaps others will have better information.

The again, its also possible version 9.x has some better capability of querying for a username and getting Macs associated with it from the API. Since I don't have a version 9 server here I can't really tell.

Josh_S
Contributor III

The API in Casper v9 is quite improved. You could do this with a call similar to the following:

apiUsername='apiusername'
apiPassword='apipassword'
jssServer='https://jss.company.com:8443'
serialNumber='SERIALNUMBER'
username=$(curl -s -k -u "${apiUsername}:${apiPassword}" -H "Content-Type: application/xml" -X 'GET' "${jssServer}/JSSResource/computers/serialnumber/${serialNumber}/subset/Location" | xmllint --format - | awk -F '[<>]' '/username/ { print $3 }' )

Check out your api information at https://jss.company.com:8443/api/

I chose to use the serial number, mainly because it's something that is fairly easy to obtain. But you could use something else.

Edit: Of course, test (test and test again) in your own environment. This also doesn't really do any error checking to make sure something valid was returned. So make sure to verify the data you get back makes sense before running with it.

mm2270
Legendary Contributor III

@Josh_S you know what, I completely misread the OP's comment. i didn't originally see that the computer name was already known when running this, In that case, yes, even in Casper Suite version 8 this can be done pretty easily. If the Mac name is known its simply a matter of pulling the xml record for that system and parsing the username in the record out and using that as a variable. In general whenever I do this I have the scrip running against the Mac pull the Mac's primary en0 Ethernet address and use that in my API query. Computer names can be tougher since they can have odd characters or spaces in them that need to be reformatted for the API.

So ignore my previous rambling. I was thinking the comp name wasn't known but he was looking to pull the computer name by only knowing the user name associated with it, IOW, the complete opposite of what he's asking! Doh! :{

winningham_2
Contributor

@Josh_S][/url][/url Thank you for the push in the right direction... I decided to do something like the below.

## Remember that $2 is reserved for *computer name* and we will use that here to allow the script to know the *username* of the computer it is ran against.
    apiUsername='apiusername'
    apiPassword='apipassword'
    jssServer='https://jss.company.com:8443'
    username=$(curl -s -k -u "${apiUsername}:${apiPassword}" -H "Content-Type: application/xml" -X 'GET' "${jssServer}/JSSResource/computers/match/$2" | xmllint --format - | awk -F '[<>]' '/username/ { print $3 }' )

## Below I am using $username, set above from the curl match, to automate the migration of the owner of this computer from a network-based account to a local-based account. 
/System/Library/CoreServices/ManagedClient.app/Contents/Resources/createmobileaccount -n $username -h /Users/$username -S -v

After limited testing, I think this will work great for what I need to accomplish. Cheers,
Tim

Building off the script you posted here following is what I've come up with:

#!/bin/zsh
apiUsername=
apiPassword=
jssServer=
loggedInUser=$( /usr/bin/stat -f %Su "/dev/console" )
echo $loggedInUser
serialNumber=$(ioreg -c IOPlatformExpertDevice -d 2 | awk -F\" '/IOPlatformSerialNumber/{print $(NF-1)}')
curl -s -k -u $apiUsername:$apiPassword -H "Content-Type: application/xml" -X 'GET' "$jssServer/JSSResource/computers/serialnumber/$serialNumber/subset/Location" | xmllint --format - | grep "email_address" | sed -e 's/email_address//g' | tr -d '< / >' | cut -d'"' -f2 > /private/var/tmp/username.txt
username=$(cat /private/var/tmp/username.txt)
dscl . -append /Users/$loggedInUser RecordName $username
jamf recon -email $username