Passing Record Info to Scripts?

chadlawson
Contributor
Contributor

Disclaimer: I've only spent about 30 minutes researching this before posting, but I haven't seen it covered yet.

I would like to have a client run a script and pass in fields from it's computer record. For example, I am managing a lab and I have an extension attribute that lists their position in the room. I would like to be able to pass that field to a script so the computers can use that to rename themselves.

Is it possible to have a client read its own JSS record?

Thanks in advance.

17 REPLIES 17

mm2270
Legendary Contributor III

Yeah, you can use the JSS API. Though to be completely honest, using the API via bash is a bit tedious. Its possible though. I've done it in a script or two I've worked on.
The basic idea is, set up a read only API account, something that has no JSS login, just the ability to read data out of the API.
Get the Mac name in your script and set it into a variable. Then use that in a curl command along with your API read only account for authentication to pull down info on the computer from the API and then... well, here's where things get a little icky. You need to somehow scrape through the huge amount of info that it pulls in as an xml file format and get just the bits you want. Its not so easy, or I should say, I have not found any nice easy ways to do it.
But.. its possible to get what you're looking for if you're creative enough.

OTOH, if you know anything about Ruby there was a good session on pulling data from the API at JNUC using Ruby on Rails. I don't know it, but I'm planning on getting to know it better at some point. It seemed much much easier to glean data from the API using that language. Bash simply isn't a good way to read info from xml format apparently.

jarednichols
Honored Contributor

Backup a minute here. This seems like it could get awfully Rube Goldberg awful quick.

What is the exact problem you're having? You just want a machine to re-name itself in accordance to the host name the JSS has for it?

chadlawson
Contributor
Contributor

Thanks for your reply, mm2270. I'll look into that.

Jared, your concern is valid. I tend to over-think things, but I'm not sure if this is one of them.

I want to rename the computer with information in the JSS but not the hostname. That would be far more trivial.

I have a classroom of computers and I am now using Casper to image the machines. I like that I can use autorun data and have them re-image themselves.

There are two extension attributes I've added to their location record to determine if they are a classroom computer (which I use for a smart group) and the other is their position in the room.

It is that last one I want to use. I want to be able to have the computers rename themselves something like "Classroom - x.y" where x is the row and y the seat.

In the course of running a class, the hostnames get changed by the students, so I want to be able to rename them back based on this extension attribute, but I don't know how to write a script that pulls that data.

jarednichols
Honored Contributor

Okay, a few comments/concerns:
1. It'll be easier to simply rename the machine in the JSS (based on your position scheme) and then use the JSS to push down the hostname frequently to re-set the name.

  1. RFC 921 specifically calls out periods (.) as a reserved character for delimiting domains. RFC 952 states that periods are allowed but refers to 921 on when to use them (e.g. separating domains). While mDNS/ZeroConf/Bonjour would allow it, you're playing with fire on that one. Don't do it. Use a hyphen instead. (See http://www.ietf.org/rfc/rfc921.txt and http://www.ietf.org/rfc/rfc952.txt)

  2. Why do students have admin rights (and thus the ability to change hostnames)?

  3. If they actually need admin rights (doubt it) consider using various management to hide the sharing preference pane and restrict the use of Terminal. If this isn't possible, consider looking at /etc/authorization to give standard users (where your students should actually be) the bare minimum rights to do what they need to do and nothing more.

Bottom line, there's no reason a student needs the sort of rights that escalate to the ability to change a system's hostname.

stevewood
Honored Contributor II
Honored Contributor II

What might be easier is to use a file on the computer to hold those variables. You can have a policy, or launchd, that runs a script at a set interval to check the computer host name against the name in that file. If it does not match, the script renames the computer based on the name in that file. You can have that file created as part of your post imaging script.

Post imaging script, add the following line, since we know Casper Imaging has set the name the right way:

/var/usr/bin/scutil --get ComputerName > /your/storage/path/properName.txt

And then in your policy can have a script that does this:

#!/bin/sh

# set path to name file
myPath="/Library/IntegerIT/"

# grab the current name of computer
compName="`scutil --get ComputerName`"

# grab the name from the file
properName="`cat $myPath/properName.txt`"

if [[ $compName != $properName ]]
    then
        scutil --set ComputerName "$properName"
fi

exit 0

I whipped that up pretty fast, so test, test, test. This does not reset LocalHostName and HostName variables of scutil, but that's an easy addition to the script.

You could set this to run at the end of the school day, or at various times throughout the day. Or, you could serve this up as a Self Service item that the teacher could run.

If you wanted to do it for the teacher, you could setup a self service policy that triggers another policy that runs this rename script on all of the classroom computers, and then runs a recon.

HTH

chadlawson
Contributor
Contributor

Jared,

I appreciate your reply. My situation is atypical of most deployments I've seen, so let me address each of your points:

1) The purpose was to automate this so I don't have to do that, but it's still a better option than most.

2) I can ditch the period. Fair point.

3 and 4) I should point out these are adult students. The entire purpose of these classes is to teach them how to manipulate Macs in order to support them. These are the Apple Authorized Training Classes in question. Each class starts with a fresh machine (except I have the JAMF binary on them) and they spend three days changing settings and exploring how it all works.

After class, I blow them all away with another fresh image.

During downtime between classes, we use these computers for people taking the exams as well as other projects.

I'm pretty confident with my reasoning and the need, it's the "how" that still eludes me.

chadlawson
Contributor
Contributor

Steve,

I like your thought. It's not quite what I want and it would require changing my workflow, but the gist works.

Per the points I mentioned for Jared's follow-up, I want the students to be able to change things over time and leave them that way for the duration of the class, so I can't keep setting it back on them.

But... I could just use your script with a policy to change their names back before I re-image which would solve the problem.

This whole exercise was just the situation that caused me to ask if I can use JSS database information passed into a script. While I may not have other examples right now, it was something I wanted to be able to do.

Thanks again to everyone! Please keep the discussion and ideas coming.

jarednichols
Honored Contributor

@Chad

Okay, seems reasonable enough. Why not set them up with netboot and autorun? Once hostnames are set in the JSS, you can have a policy ("reset computer names" box in the advanced tab) that renames the computer automatically. You don't have to do anything once the hostname is properly set in the JSS and you create the policy to rename the computers. Run it once a day or something.

That in combination with netboot & autorun makes the lab pretty easy to blow away, even if you need to give them admin rights.

chadlawson
Contributor
Contributor

Jared,

That is the gist of what I'm doing at this time. Like I said I need to leave these computers for a few days in a row and then bring them back into line with NetBoot and Imaging/autorun.

I have an existing policy that updates inventory daily for other reasons that I'm not 100% happy about, but in the process the names in the inventory get updated mid-class.

I've already put the classroom computers into a "building" so I can scope the policy to ignore them.

But as I said, the purpose of my post was not about solving this one particular problem but more about how to get at database information.

Sadly, as a scripting geek my brain works more in the area of "Hey! Can I do [insert odd thing]?!" usually without a reason. Just because I can (or can't).

What you said about going Rube Goldberg on this stuff is dead on at times.

stevewood
Honored Contributor II
Honored Contributor II

Like Mike said earlier on, you can get at that data via the JSS API in Bash, you'll just need to have your awk and sed fu up to speed. And if you're a scripting nerd like a lot of us in "The Nation", then I'm sure you can scrape together a script to pull exactly what you want from the JSS.

But, if you're running a recon daily, and not forcing the recon to reset the computer name, then the data in the JSS would be suspect. Then using the text file on the system makes more sense, IMHO.

mm2270
Legendary Contributor III

Yeah, if your intention is to be able to pull some custom data out from a computer's JSS record, the JSS API will be your friend (and an enemy at times :)
Like Steve says above, if you can wrangle text well with awk and sed, you'll get it working. I'd be happy to share my hackey way of pulling data from it in bash if you wanted to see that. Its a little ugly though.
I would agree though that for your particular situation, using something like a local file with the info or such may be the batter way. That shouldn't discourage you from exploring the API though. There are definitely some cool uses for it.

chadlawson
Contributor
Contributor

@mm2270,

I would be happy to see any sample code you have. I would very much like to explore the API.

I'm currently looking around for the API documentation.

mm2270
Legendary Contributor III

I'll dig up what I have and post it here, though I'm about to head out for the turkey day holiday so I may not get to it until Friday.

In the interim, the JSS API documentation is right in the JSS itself.
Try these (adjusting for your JSS address)

https://yourjssurl.com:8443/apiFrontPage.rest
https://yourjssurl.com:8443/apiIntro.rest

That should get you started.

john_miller
Contributor

Hey mm2270

I've done some parsing through the XML that is returned using xpath. It's built into the OS, so it's there by default which is nice. It works really well if you know the XML value you're shooting for. For example, the JSS returns a longer xml with things like:

<computer>
<general> 
bunch of general stuff
</general>
<remote_management>
bunch of remote management stuff
</remote_management>
</computer>

and down the line. With xpath, you can define how far down you want to parse into the XML, and just get the specific stuff from the "nested group" you want. So instead of parsing out the location of "general" and then looking for the 35th spot away, you can use xpath to start you at General, or even the specific key within that nested group.

For example, assuming "tmp.xml" is my xml record I just got back using the JSS API, I can run:

cat ./tmp.xml | xpath //computer/general/id[1]

And it'll give me back the <id>234</id>. Then, we just have to parse out the id tagging groups by piping it to something like:

sed s/<id>//g | sed s/<\/id>//g

Does that help? Something I learned not too long ago...figured I might share.

John

mm2270
Legendary Contributor III

@John, that is awesome!! Thanks for sharing that! Never knew about that little app. I just ran a quick test and this works perfectly. You really don't even need to dump the API output to a file.

I used the following syntax and it worked great!

curl -s -u apiuser:password https://my.casper.server.com:8443/JSSResource/computers/macaddress/$(networksetup -getmacaddress en0 | awk '{print $3}' | sed 's/:/./g') | xpath //computer/general/id[1] | sed -e 's/<id>//;s/</id>//'

That returned a line with my computer JSS ID. I can pipe that into a variable or use it in a dialog that pops up on screen. I will test this remotely on some other Macs, but this looks to be a very nice way to get info from the API. I'll have to play with this some more. Thanks again for posting this! :)

john_miller
Contributor

@mm2270

No problem. The other thing to note about xpath is that you can parse through all the returned variables in the specific "group" you're in. So, using the "General" again, looking at the XML shows there's a bunch of different tags in there. If you wanted to iterate through them, find out what they are, and do something with them, you can do that with xpath, too.

The key thing is the "[1]" that's in the xpath command:

xpath //computer/general/id[1]

That returns the first value that has the tag, or is in the tag group "id." If we wanted everything in general, we could change that [1] to [2], [3]. [4], and use that to iterate through. Hope that helps, too.

Malcolm
Contributor II

@mm2270 Looks like your achieving what I am trying to achieve, but I am trying to grab the assigned user to the computer,

any thoughts as to what I would need to change for the api command?