Posted on 06-19-2013 01:22 PM
Anyone got an EA that reports back the management account used?
Or a way to smart group machines based on management account?
Solved! Go to Solution.
Posted on 06-19-2013 02:07 PM
Yep.
But... the only way (currently) is to use the Casper API. The information exists in the API for every Mac, but can't be accessed any other way.
So first things first is to set up a 'read-only' API account on your JSS if you haven't done so already. Then plug that info along with your JSS address into the below script
#!/bin/sh
apiURL="https://your.casper.jss:8443/JSSResource/computers/macaddress/"
apiUser="apiusername"
apiPass="apipassword"
MacAdd=$( networksetup -getmacaddress en0 | awk '{ print $3 }' | sed 's/:/./g' )
ManAccount=$( curl -s -u $apiUser:$apiPass "$apiURL$MacAdd" | xpath /computer/general/remote_management/management_username[1] | sed 's/<management_username>//;s/</management_username>//' )
if [[ "$ManAccount" != "" ]]; then
echo "<result>$ManAccount</result>"
else
exit 0
fi
In case you're wondering why the if/then, exit stuff, our JSS is clustered with a limited access server in the DMZ so Macs can connect in outside the network. problem is, the API uses Tomcat which is disabled on the external server (Limited Access JSS) so we had some issues early on where if it couldn't read the information back during inventory while outside, it would blank out the value previously assigned. Since we had a policy that was attempting to correct the management account with a QuickAdd.pkg, it was causing those Macs to be re-enrolled. Not what we wanted and caused a few issues, like some policies re-running.
Truth is though, I'm not sure if the if/then, else exit is actually working as EA's operate a bit differently than regular scripts. Our account rep at JAMF thinks they must upload 'something' regardless of how you designed the script, and I have a feeling that is the case. We had disabled the above referenced policy anyway for other reasons.
Posted on 06-19-2013 02:07 PM
Yep.
But... the only way (currently) is to use the Casper API. The information exists in the API for every Mac, but can't be accessed any other way.
So first things first is to set up a 'read-only' API account on your JSS if you haven't done so already. Then plug that info along with your JSS address into the below script
#!/bin/sh
apiURL="https://your.casper.jss:8443/JSSResource/computers/macaddress/"
apiUser="apiusername"
apiPass="apipassword"
MacAdd=$( networksetup -getmacaddress en0 | awk '{ print $3 }' | sed 's/:/./g' )
ManAccount=$( curl -s -u $apiUser:$apiPass "$apiURL$MacAdd" | xpath /computer/general/remote_management/management_username[1] | sed 's/<management_username>//;s/</management_username>//' )
if [[ "$ManAccount" != "" ]]; then
echo "<result>$ManAccount</result>"
else
exit 0
fi
In case you're wondering why the if/then, exit stuff, our JSS is clustered with a limited access server in the DMZ so Macs can connect in outside the network. problem is, the API uses Tomcat which is disabled on the external server (Limited Access JSS) so we had some issues early on where if it couldn't read the information back during inventory while outside, it would blank out the value previously assigned. Since we had a policy that was attempting to correct the management account with a QuickAdd.pkg, it was causing those Macs to be re-enrolled. Not what we wanted and caused a few issues, like some policies re-running.
Truth is though, I'm not sure if the if/then, else exit is actually working as EA's operate a bit differently than regular scripts. Our account rep at JAMF thinks they must upload 'something' regardless of how you designed the script, and I have a feeling that is the case. We had disabled the above referenced policy anyway for other reasons.
Posted on 06-19-2013 02:10 PM
Awesome. Thanks again Mike.
I'll give it a whirl tomorrow.
We're in the throws of a change over & so far 150 out of 190 clients have the new account.
That's @ least 2 beers I'll hopefully buy you @ JNUC 2013!
Posted on 06-24-2013 04:02 AM
Worked well.. many thanks!
Posted on 03-04-2014 11:15 AM
anyone else getting an error with xpath?
not well-formed (invalid token) at line 1, column 0, byte 0:
[huge block of xml deleted]
^
at /System/Library/Perl/Extras/5.16/darwin-thread-multi-2level/XML/Parser.pm line 187
Posted on 04-23-2014 08:42 AM
Disregard.
The error was my own, the EA is working well.
Posted on 04-23-2014 09:05 AM
Just to throw in an additional feature, we are getting the account info in a similar way, but then comparing the result to the local directory, and then returning a "Missing" if it is not there.
if [[ $(dscl . -search /Users RecordName $JSSAdmin) ]]; then
echo "<result>OK - $JSSAdmin</result>"
else
echo "<result>MISSING - $JSSAdmin</result>"
fi
Posted on 12-17-2014 03:04 PM
Running this on Yosemite, I get:
no element found at line 1, column 0, byte 0:
^
at /System/Library/Perl/Extras/5.18/darwin-thread-multi-2level/XML/Parser.pm line 187.
Any thoughts, folks?
Posted on 12-17-2014 04:53 PM
Hi @smamdani][/url - Not sure if you're talking about my script or another one, but if you mean mine, try the following. New and improved.
#!/bin/sh
apiURL="https://your.casper.jss:8443/JSSResource/computers/macaddress"
apiUser="apiusername"
apiPass="apipassword"
MacAdd=$(networksetup -getmacaddress en0 | awk '{ print $3 }' | sed 's/:/./g')
ManAccount=$(curl -H "Accept: application/xml" -skfu $apiUser:$apiPass "${apiURL}/${MacAdd}/subset/general" | xmllint --format - 2>/dev/null | awk -F'>|<' '/management_username/{print $3}')
if [ ! -z "$ManAccount" ]; then
echo "<result>$ManAccount</result>"
else
echo "<result>N/A</result>"
fi
Posted on 12-29-2014 05:12 PM
any chance you could suggest the changes needed for this script to use xmllint? https://jamfnation.jamfsoftware.com/discussion.html?id=8667
Posted on 12-30-2014 09:31 AM
@ejboyd][/url][/url - using xmllint isn't strictly necessary. It just makes looking at and parsing the resulting xml a little easier since it formats it.
Anyway, here is a rework of the script posted on that thread using both xmllint and also forcing the API to return xml instead of JSON, which can happen under some circumstances now..
#!/bin/sh
apiURL="https://yourjss:8443/JSSResource/computers/macaddress/"
apiUser="username"
apiPass="password"
MacAdd=$( /usr/sbin/networksetup -getmacaddress en0 | /usr/bin/awk '{ print $3 }' | /usr/bin/sed 's/:/./g' )
siteName=$( /usr/bin/curl -H "Accept: application/xml" -skfu $apiUser:$apiPass "$apiURL${MacAdd}/subset/general" | xmllint --format - | xpath //site 2>&1 | awk -F'>|<' '/name/{print $3}' )
if [[ "$siteName" != "" ]]; then
echo "<result>$siteName</result>"
else
echo "<result>Not Available</result>"
fi
Posted on 01-27-2015 11:43 PM
This is great, thanks Mike.
FYI There was one typo I had to correct to get the EA for the management account to work (the new and improved version listed 3 posts above this post). There is a trailing slash in the apiURL variable, but also an additional slash when the apiURL variable is called when defining the ManAccount variable....you need to lose one or the other to get it to work.
.....
apiURL="https://yourjss:8443/JSSResource/computers/macaddress**/**"
.....
...."${apiURL}**/**${MacAdd}/subset/general".......
Posted on 01-28-2015 07:01 AM
@Josh.Smith - Thanks for the catch! You're absolutely right. One too many forward slashes. The EA we use for this is slightly different so this was a modification on what we use, hence the typo as it got translated.
Posted on 02-17-2015 08:18 AM
Hey @mm2270][/url , I upgraded to 9.64 this morning and suddenly my old EA to get the management account didn't work anymore. I looked at your updated version quick and it's returning a value of N/A for me on every computer, so maybe it needs to be updated again, or who knows. I'm not going to dig into that, because I modified your $sitename EA to get a working version.
For anyone interested, here it is. It's working for me, so hopefully it works for y'all too. All credit to @mm2270][/url for the original.
#!/bin/sh
apiURL="https://your.jss.address:8443/JSSResource/computers/macaddress/"
apiUser="YourAPIusername"
apiPass="YourAPIpassword"
MacAdd=$( /usr/sbin/networksetup -getmacaddress en0 | /usr/bin/awk '{ print $3 }' | /usr/bin/sed 's/:/./g' )
ManAccount=$( /usr/bin/curl -H "Accept: application/xml" -skfu $apiUser:$apiPass "$apiURL${MacAdd}/subset/general" | xmllint --format - | xpath //remote_management 2>&1 | awk -F'>|<' '/management_username/{print $3}' )
if [[ "$ManAccount" != "" ]]; then
echo "<result>$ManAccount</result>"
else
exit 0
fi
Posted on 02-17-2015 08:48 AM
@chlaird][/url - Thanks for the info! The problem it seems with most of my posts above is that I had an extra forward slash in the URL variable. For example, change the apiURL line to end with macaddress instead of macaddress/ and it should start working. @Josh.Smith][/url had pointed out the error above and I just never got around to changing any of the above posts to correct it.
Edit: Corrections now applied to several posts above.
Posted on 02-17-2015 09:04 AM
@mm2270 -- I see you corrected your posts, I thought I was going crazy! I was looking for what you said, and it wasn't there suddenly.
Anyway, you're correct-- the extra / in your 12/17/2014 post broke it for me. With your new edit, it now works.
If you're interested, your 12/30/14 post is now broken because it's missing a / , since the address ends with macaddress and you didn't include it in "$apiURL${MacAdd}/subset/general"
Posted on 02-17-2015 09:08 AM
Oops! Haha. You're right. I was looking close enough at that script when I edited it. I added the slash back in.
At some point I may edit them all to make them more consistent across the various versions.
Thanks again for the catches!
Posted on 02-24-2015 11:24 AM
What access is everyone providing to the API User for this particular lookup? JSS : Computers : Read Only?
Posted on 02-24-2015 11:35 AM
@spraguga - Yes, the API account should really only need access to read Computer objects and nothing else. Its just pulling the Computer record to get the Management account information from its record.
That said, we use our standard API account that can read all objects from the JSS for this, but its not necessary to have that level of access.
Posted on 07-30-2015 06:37 PM
Ok, finally got this working.
xmlpath and xmllint were choking on something returning from the server incorrectly. Our JSS is on Tomcat/Windows Server.
The fix was to edit:
C:Program FilesJSSTomcatincatalina.bat
and adding the line:
```
set JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding=UTF8
Posted on 08-20-2015 06:38 AM
@mm2270 Mike, do you know if something is changed since then so you can get the management account information from de EA? The api of our limited jss is disabled, and I would like to see that the management account information can be acquired.
Posted on 08-20-2015 07:04 AM
Hi @rvanhardeveld I'm not sure I understand what you mean by:
The api of our limited jss is disabled
If its disabled, there isn't really a way to get the Management Account via script. As far as I know its still not a built in criteria item in a computer record that can be displayed. Its part of the computer's record details in the xml, but that's it.
Or am I misunderstanding what you're meaning by that statement?
Posted on 08-20-2015 07:07 AM
No Mike, you understood it correctly:) Thank you for your answer, I was hoping there was a work-around for this:)
Posted on 08-20-2015 11:01 AM
Hi Everyone,
Just a friendly reminder, if you are going to deploy API scripts client side, you probably want to use a read only API account. I would just like everyone to take that into consdieration since they will contain a password. Alternatively you can check out Bryson's GitHub example of passing encrypted strings in positional parameters in a script (which you can't do in an EA unfortunately but you can in a policy) at this link:
Another option over XML is JSON when doing GET request, and it is sometimes a lot easier to parse. There is a FOSS binary called jq
which you can download off their GitHub site
A quick example to get the management account in a one liner, you can use jq
like so:
bash-3.2$ serial=$(system_profiler SPHardwareDataType | awk '/Serial Number/ { print $4}')
bash-3.2$ curl -sk -H "Accept: application/json" -u tlarkin https://casper9gm.local:8443/JSSResource/computers/serialnumber/${serial} | jq '.computer.general.remote_management.management_username'
Enter host password for user 'tlarkin':
"_sshdaemon"
Of course Python has built in modules that can parse XML/JSON, but there are some decent ones for bash. XMLstartlet and jq are two you should look up. One pitfall of jq though is there is no edit in place with the binary, you have to write to a file. Since the JSS doesn't support PUT/POST in JSON anyway that should not be a huge deal currently. XMLStartlet is another FOSS project that uses xpath
and can do in place editing when doing API work. This should reduce the amount of awk
and sed
pipes, although in my experience nothing does regex that well in bash as sed
does.
Hope this was somewhat helpful to you all.
Thanks,
Tom
Posted on 08-20-2015 11:27 AM
Thanks for the information on jq @tlarkin.
FWIW, I still prefer working with xml myself and my API scripts no longer use all that xpath, awk and sed stuff up above (some of it, but less). For example, getting the management account now is:
#!/bin/sh
serial=$(ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformSerialNumber/{print $4}')
management_account=$(curl -H "Accept: application/xml" -sfku apiuser:apipass https://jss.company.com:8443/JSSResource/computers/serialnumber/${serial} -X GET | xmllint --format - | awk -F'>|<' '/<management_username>/{print $3}')
So basically, pass the xml result thru xmllint to format it and use awk field separator and regex matching together to pull the field between the tags. Just two pipes, so not terrible. Seems to work well for me. I will take a look at the extra tools you mentioned though. Can't have too many tools in your toolbox.
Posted on 08-20-2015 11:47 AM
That is the beauty of the plethora of tools available, and the methods you use. You have options. I prefer xpath
when working with XML in bash. Like this example:
$ curl -sk -u api:api https://casper9gm.local:8443/JSSResource/computers/id/10 | xpath /computer/general/remote_management/management_username
Found 1 nodes:
-- NODE --
<management_username>_sshdaemon</management_username>
from there I just strip out the xml tags with sed
and regex. However, that is not the only way to accomplish the same goal, so whatever methods you prefer is really up to you. I like xpath
and the -d
switch with curl
so I can just GET/PUT/POST whatever small piece of XML I am working, but that is literally just my personal preference. It is by no means the only way to do this.
I personally enjoy seeing everyone's solutions on here because it always gives me new ideas. :-)
Cheers,
Tom
Posted on 12-23-2015 05:51 PM
Probably worth submitting a feature request to simply expose this in the GUI without an EA. Unfortunately we have an ITSec policy prohibiting us from storing passwords in scripts (yes, I know, I didn't write it). We use Recon to "catch" systems that we've missed, but that enrolls with an existing admin account, while we created a new one to use with Casper. It would be nice to create a policy to re-enroll with the new account, scoped to systems using the old one.