Posted on 06-04-2020 12:03 PM
I had a use case that it would have been extremely nice to be able to use an advanced search or smart group to be able to gather data about computers in specific sites. However sites aren't meant to be scope-able per Jamf, and that really made my life difficult. Specifically I was looking for unmanaged computers in the "none" or "Full Jamf Pro" site, and there is no way to make a search for this.
I did some searching and saw several posts of folks who wanted Jamf to make sites a useable criteria, but saw that Jamf specifically said it was not planned (https://www.jamf.com/jamf-nation/feature-requests/1365/smart-computer-groups-based-on-site).
I was able to create a workaround for this and thought I'd share. I first made a custom extension attribute named "Site" with a string data type and a text field for the input type.
Then I was able to make a script utilizing the API to read the current site of a computer and write that data to a XML file that gets uploaded to Jamf and sets the custom EA I created. Once this runs and is finished you will then be able to scope and search based on that custom EA. The script loops through all computers there's a device ID for, and is run locally without the need to be run on each individual computer.
Hopefully others find this useful. Below is my script:
#!/bin/sh
jssURL="https://xxxxxx.jamfcloud.com/JSSResource"
username="apiusername"
password="apipassword"
IDS=$(/usr/bin/curl -H "Accept: text/xml" --user "$username":"$password" ${jssURL}/computers | xmllint --format - | awk -F'>|<' '/<id>/{print $3}')
ea_name="Site"
for X in $IDS; do
ea_value=$(curl -H "Accept: text/xml" -skfu $username:$password ${jssURL}/computers/id/${X} -X GET | xmllint --xpath 'computer/general/site/name/text()' -)
# Create xml
cat << EOF > /private/tmp/ea.xml
<computer>
<extension_attributes>
<extension_attribute>
<name>$ea_name</name>
<value>$ea_value</value>
</extension_attribute>
</extension_attributes>
</computer>
EOF
# Upload the xml file
curl -sfku "${username}":"${password}" "${jssURL}/computers/id/${X}" -T /private/tmp/ea.xml -X PUT
done
exit 0
Posted on 06-04-2020 01:29 PM
We solved this a different way by storing the site value locally in a plist file that gets read in by an EA. We use a policy that runs once a week to grab the site info for the computer and store it in that plist. The policy ends with an inventory update, which pushes the site information up to the server. The advantage of this is two-fold. First, the site info is stored on the device so a tech can easily determine a machine is in the correct site without needing access to Jamf, and second, the site EA is continually updated in case a machine is moved to a different site and doesn't require us to remember to update the EA value manually.
All in all, you came up with a nice way to workaround Jamf's limitations.
Posted on 06-04-2020 02:01 PM
@stevewood Yeah, that's also a good idea. In my environment I'm in the process of migrating computer records from multiple different Jamf servers into a central one, and if it's just a record and the computer hasn't itself migrated over, then the record is "unmanaged", and still checking into the old Jamf server. I'm doing this in preparation for the computer migration so the computer will retain it's user/location/dept/building info. So for my specific purpose I don't think I had a lot of other options. I can also make some kind of scheduled task to automate running the script weekly or what not.
Posted on 06-04-2020 02:32 PM
We're in the same boat. Migrating ~16,000 devices over to a different server. We have quite a bit of data in the "old" Jamf server that we'll need to migrate over to the new. We will most likely store in our list so we can ingest into the new server easily.
Posted on 03-01-2021 06:35 AM
@dennisnardi Did you create a single EA plist and you dump all your EAs into the single file or do you create one for each EA? (nothing like bringing up a 6 month old thread, right? :) )
Posted on 08-11-2021 03:18 PM
And nothing like replying to a post 5 months late! I didn't have the skills to do a single plist, so my script created one for each computer. So it takes a second or two per computer to go through the process if I run the script locally. Generally what I do now is set the script to run on each computer on enrollment/check in, so the EA gets set automatically and I don't need to run a script on a local computer that touches 4000+ Mac's now.
Posted on 08-11-2021 03:08 PM
@dennisnardi Thanks this is great. I was able to create a EA based on this script.
#!/bin/sh
# This will pull the site name
jssURL="https://you.jamfcloud.com/JSSResource"
username="your"
password="your"
udid=$(/usr/sbin/system_profiler SPHardwareDataType | /usr/bin/awk '/Hardware UUID:/ { print $3 }')
siteName=$(curl -H "Accept: text/xml" -skfu $username:$password ${jssURL}/computers/udid/${udid} -X GET | xmllint --xpath 'computer/general/site/name/text()' -)
if [[ $siteName ]]; then
echo "<result>${siteName}</result>"
else
echo "<result>Not Available</result>"
fi
Posted on 03-27-2023 03:45 AM
Hi Kyle,
Thanks for the script based on this topic, I tried creating an attribute and somehow it's blank for me. Is there any OS restriction for the above script?
Thanks
Posted on 03-30-2023 06:45 AM
I don't think so just make sure that you allow for legacy API in Jamf Pro and that the username and password are correct for the script. Also make sure that a recent inventory has ran.
Posted on 03-30-2023 07:35 AM
Make sure your URL variable contains /JSSResource like Kyle's script has. I missed that in testing just now and the info was coming black blank.
Posted on 03-30-2023 07:39 AM
#!/bin/sh
jssURL=https://***********.com/JSSResource
username=test.api
password=********
IDS=$(/usr/bin/curl -H "Accept: text/xml" --user "$username":"$password" ${jssURL}/computers | xmllint --format - | awk -F'>|<' '/<id>/{print $3}')
ea_name="Site"
for X in $IDS; do
ea_value=$(curl -H "Accept: text/xml" -skfu $username:$password ${jssURL}/computers/id/${X} -X GET | xmllint --xpath 'computer/general/site/name/text()' -)
# Create xml
cat << EOF > /private/tmp/ea.xml
<computer>
<extension_attributes>
<extension_attribute>
<name>$ea_name</name>
<value>$ea_value</value>
</extension_attribute>
</extension_attributes>
</computer>
EOF
# Upload the xml file
curl -sfku "${username}":"${password}" "${jssURL}/computers/id/${X}" -T /private/tmp/ea.xml -X PUT
done
exit 0
Posted on 03-30-2023 07:41 AM
This is what I have updated and please correct me if I need to modify it.
Posted on 03-30-2023 07:55 AM
So what you have posted would be a script that would run off from a policy and not as part of an EA. Instead what Kyle posted can be placed into an Extension Attribute and run that way. That would be more secure since the credentials would not get stored on the device, whereas if running a script from a policy the credentials could be visible in the jamf.log file.
Try creating a new Extension Attribute, set the Data Type to String and the Input Type to script and then paste in Kyle's script:
#!/bin/sh
# This will pull the site name
jssURL="https://you.jamfcloud.com/JSSResource"
username="your"
password="your"
udid=$(/usr/sbin/system_profiler SPHardwareDataType | /usr/bin/awk '/Hardware UUID:/ { print $3 }')
siteName=$(curl -H "Accept: text/xml" -skfu $username:$password ${jssURL}/computers/udid/${udid} -X GET | xmllint --xpath 'computer/general/site/name/text()' -)
if [[ $siteName ]]; then
echo "<result>${siteName}</result>"
else
echo "<result>Not Available</result>"
fi
The next time a computer updates inventory, the site value will be placed in the EA.
Posted on 03-30-2023 08:32 AM
Worked like a charm, Thanks Stevewood & Kyle.
Posted on 04-17-2023 12:14 PM
It should be mentioned that including API account credential in scripts and/or EA is considered very bad practice and really shouldn't be utilized, much less should it be recommended (at least, without a disclaimer).
If you need to do something like this, run it in a script off device. There is absolutely no need to run this on a device. Not to mention, these methods only support Macs, so if you have Mobile Devices as well, this doesn't support them.
I've been using my solution since 2018 and it essentially does the same thing, but again, off devices.
Here's my script: jamf_assignSiteEA.ps1; it sets the Site value on every device using the API. Some notes:
This is a PowerShell script as I run it on a Windows box that runs other automated tasks that my team has setup
It runs nightly and dumps to a log file for review
It checks if the current Site is the same as the Site EA; if it is, it does nothing, if it isn't, it updates the Site EA
Duplicate records will cause an issue here -- the API cannot handle this
Every time the API is used to change a device record, Jamf Pro acts like that is a "Inventory Update" even though it isn't -- this is a known issue with Jamf Pro that Jamf has yet to fix even though there are numerous Feature Requests asking for it
Posted on 04-22-2024 07:21 AM
In the year 2024, this is still useful I just added this as an extension attribute. thanks!
Posted on 04-22-2024 01:07 PM
And even with it still being useful..... Jamf rejects any Feature Requests to add this simple criteria into the product........