Add newly enrolled macs to a static group via script ?

tcandela
Valued Contributor II

I have a configuration (standard with smart) , I would like to have the computers that run this Smart config to also be put into a static group automatically. Is there a way or a script that can do this automatically ?

to avoid having me to manually go into the JSS after each computer has been enrolled and add them to this static group.

1 ACCEPTED SOLUTION

tcandela
Valued Contributor II

I made a smart group based on the criteria of 'serial numbers', i just added all 8 iMacs serial numbers manually to create this group.
I am imaging my test computer with a configuration, I want to see how soon in the process the enrollment happens, thus the test computer should go into the smart group immediately after.

I have a policy that is a custom event policy that gets called 'after reboot' in the imaging process (jamf policy -event installprinter). This policy is scoped to this 'smart group'.

View solution in original post

17 REPLIES 17

mm2270
Legendary Contributor III

Just curious, but why a Static Group? Any particular reason it must be Static?
I ask because you could simply drop some kind of identifier file/folder onto these Macs as part of your Casper Imaging configuration, then have an Extension Attribute pick up the existence of that file/folder and place any machines with it into a Smart Group instead. Wouldn't that be better?

If not, then yes its possible to add Macs into a Static group using the JSS API.

kitzy
Contributor III

Hi @tcandela,

As @mm2270 said, you could add Macs into a static group using the JSS API, but I also agree that simply adding an identifier that an extension attribute looks for and place those machines into a smart group would be easier. I like to call these "dummy receipts."

Here is a post I wrote up a while ago on dummy receipts: http://www.kitzy.org/blog/2013/9/26/the-art-of-the-dummy-receipt

Hope that helps!

tcandela
Valued Contributor II

@mm2270 The computer count for this lab will stay at 8, so i don't see it necessary to create a smart group, there all configured the same....

how do i go about adding the Mac into the static group using the JSS API ?

tcandela
Valued Contributor II

@kitzy I understand your post.

how do i go about adding the Mac into the static group using the JSS API ?

Chris_Hafner
Valued Contributor II

Sounds like you are working through your needs. However, I find that it's easy to use departments to define labs and they can be easily imaged and provisioned using either pre-stage imaging and again by utilizing auto-run data if they need a re-image. For other groups I use their naming conventions.

Since you're interested in API access, are you trying to set these using another database or inventory system?

There are many ways to skin this cat but in short, yes.

tcandela
Valued Contributor II

I just Am looking for the simplest way possible to get these eight computers added to a static group immediately after enrollment. An 'at reboot' script to run after imaging?

Chris_Hafner
Valued Contributor II

Sure thing... but there are some variables here that you know and we don't, like why and what you want your static group for. No judging or anything.

One option that I alluded to may or may not work depending on your particular organization: You can create a 'department' within the JSS for this lab (unless you're already using it for something else). Setup a pre-stage in the JSS to automatically image and provision these 8 iMacs into that department and then create a static group (or smart for that matter... or even nothing as you can use 'department' as a variable in both) who's 'Criteria' is:

"Department" IS whateveryounamedyourlab

That's just one way to do it. If the units are already in the JSS you can set their AutoRun data to the same department as well and for the same purpose even without needing to re-image. Though the department setting would be maintained after any number of re-images. I tend to use a set of naming conventions for certain lookups and smart groups as well. I tend to favor smart groups over static groups as I have policies that are applied automatically based on them. That said, I do use static groups for certain types of manual notifications.

Is any of this helping?

tcandela
Valued Contributor II

I'm a site admin, I never have done pre staging yet so I have to learn about it (no big deal).

What is this 'auto run data' ?

I see the check box in casper imaging and never have checked it because I don't know what it does or where the logs/data is kept.

What is your definition of 'static group'?
This static group I am wanting to put the lab computers is not going to change. The amount of computers, apps installed on them will be the same on all 8

mm2270
Legendary Contributor III

Hey @tcandela
So it turns out this wasn't as easy to do as I originally thought. Maybe there is some easier way to accomplish this via the JSS API that I'm just blind to, but in the various tests I ran, it seems the API will overwrite a group's membership when trying to add in a Mac using a PUT command, at least with all the testing I did. IOW, any existing machines get removed and you end up with just the one Mac you just added to it, which is obviously not a workable scenario. It seems it actually requires the complete group information to be appended to and then re-uploaded to the JSS, which is very strange. I didn't know it worked this way since other items in the JSS, like computer objects don't operate this way with API PUT commands.

That said, I did come up with a workaround as I described above. Here is the script. its a bit clunky in nature due to how its pulling down the whole group, stripping out some of the closing xml tags from the local file, then populating some extra data (appending) to the end of the xml file, and finally, adding the closing xml tags to make it a valid xml. Then it uploads it to the JSS. This retains the existing membership and adds the Mac the script is running on into the group. Obviously the Mac has to be enrolled in your JSS before any of this would work.

I set it up to use Parameters 4 - 6 to pass the API username, API password and the group name, respectively, to the script. If any of them are blank, it exits with an error. Your API account will need write access to objects, specifically to Computer Groups. Not sure if anything else is required other than that though.

Give this a try, but I encourage you to only try it on a test/junk group first, and not anything that you'd be upset about it if it was overwritten, until you're sure it will work for you.

#!/bin/sh

## Script name: Add local computer to JSS Static Group
## Author:      Mike Morales, May 2015

## The script uses Parameters 4, 5 and 6 to pass the API write username, password and group names, respectively to the script

## Get the JSS URL from the Mac's jamf plist file
jssURL=$(defaults read /Library/Preferences/com.jamfsoftware.jamf.plist jss_url)

## Define API username and password information & JSS Group name from passed parameters
if [ ! -z "$4" ]; then
    apiUser="$4"
else
    echo "No value passed to $4 for api username. Exiting..."
    exit 1
fi

if [ ! -z "$5" ]; then
    apiPass="$5"
else
    echo "No value passed to $5 for api password. Exiting..."
    exit 1
fi

if [ ! -z "$6" ]; then
    jssGroup="$(perl -MURI::Escape -e 'print uri_escape($ARGV[0]);' "$6")"
else
    echo "No value passed to $6 for the JSS Group. Exiting..."
    exit 1
fi

## Get the JSS Group's data, remove closing section
curl -H "Accept: application/xml" -sfku "${apiUser}:${apiPass}" "${jssURL}JSSResource/computergroups/name/${jssGroup}"| xmllint --format - | awk '/<computer_group>/,/</computers>/{print}' | sed 's/</computers>//' | sed '/^$/d' > "/private/tmp/tmpgroupfile.xml"

if [ -e "/private/tmp/tmpgroupfile.xml" ]; then
    ## Get computer's data
    macName=$(scutil --get ComputerName)
    MACAdd1=$(networksetup -getmacaddress en0 | awk '{print $3}')
    MACAdd2=$(networksetup -getmacaddress en1 | awk '{print $3}')
    SerialNo=$(ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformSerialNumber/{print $4}')

    ## Get the Mac's JSS ID using the API
    jssID=$(curl -H "Accept: application/xml" -sfku "${apiUser}:${apiPass}" "${jssURL}JSSResource/computers/macaddress/${MACAdd1}/subset/General" | xmllint --format - | awk -F'>|<' '/<id>/{print $3; exit}')

    echo "JSS ID found for $macName was: $jssID"

    if [[ "$jssID" ]] && [[ "$macName" ]] && [[ "$MACAdd1" ]] && [[ "$MACAdd2" ]] && [[ "$SerialNo" ]]; then
        ## echo the xml section for the computer into the temp xml file
        echo '<computer>
        <id>'$jssID'</id>
        <name>'$macName'</name>
        <mac_address>'$MACAdd1'</mac_address>
        <alt_mac_address>'$MACAdd2'</alt_mac_address>
        <serial_number>'$SerialNo'</serial_number>
        </computer>' >> "/private/tmp/tmpgroupfile.xml"

        ## Now finish the xml file
        echo '</computers>
        </computer_group>' >> "/private/tmp/tmpgroupfile.xml"
    else
        echo "Some data values are missing. Can't continue"
        exit 1
    fi
else
    echo "The temp xml file could not be found. It may not have been created successfully"
    exit 1
fi

## If we got this far, check the format of the xml file.
## If it passes the xmllint test, try uploading the xml file to the JSS
if [[ $(xmllint --format "/private/tmp/tmpgroupfile.xml" 2>&1 >/dev/null; echo $?) == 0 ]]; then
    echo "XML creation successful. Attempting upload to JSS"

    curl -sfku "${apiUser}:${apiPass}" "${jssURL}JSSResource/computergroups/name/${jssGroup}" -X PUT -T "/private/tmp/tmpgroupfile.xml"

    ## Check to see if we got a 0 exit status from the PUT command  
    if [ $? == 0 ]; then
        echo "Computer "$macName" was added to group "$6""
        ## Clean up the xml file
        rm -f "/private/tmp/tmpgroupfile.xml"
        exit 0
    else
        echo "Add to group failed"
        ## Clean up the xml file
        rm -f "/private/tmp/tmpgroupfile.xml"
        exit 1
    fi
else
    echo "XML creation failed"
    exit 1
fi

Edit: Just wanted to also mention that, I still feel dropping a dummy receipt on these Macs and just placing them into a Smart Group is the better way to address your need. Its simpler and far less prone to breakage than what I posted above. Just because it would be a "Smart Computer Group" doesn't mean its membership would actually change. If your criteria for the group is to only gather Macs that have that hidden identifier or package receipt or whatnot on them, only those 8 Macs will be in that group, ever.
Finally, I have not tested how this fairs when its run on a Mac that's already in the group you're trying to add it to. Hopefully it just handles it gracefully and doesn't hiccup, but I don't know. Something to test, since, if you ever re-image one of those Macs with the same Casper Admin config, it would conceivably run the script again on it after imaging.

Edit2: OK, answered my own question. If the Mac is already in the group and the script runs again, nothing bad happens. It uploads the XML, but the group membership remains the same as it was, so no wonkiness as far as I can see with that.
If anyone knows of some way to accomplish adding to an existing Static Computer Group via the API that doesn't involve the rigmarole I came up, I'd be interested in seeing how. Not that it matters much to me, but I'd just be interested to see the proper way to do it.

stevewood
Honored Contributor II
Honored Contributor II

@tcandela "AutoRun Data" is a way to store the imaging settings for a computer (or computers) with the computer records so that you do not have to re-enter that data at imaging time.

For example, if you have an Casper Imaging configuration that you use for your labs you could store that as AutoRun data for each of your lab computers. Then whenever Casper Imaging is run on those computers they will image with that AutoRun data.

A good real use case for this is in the lab environment where you may want to re-image your lab computers on a regular schedule, perhaps every weekend. If you have AutoRun data stored for each computer in the lab, you can create a policy that reboots the lab computers and points their startup disk to a NetBoot set. When the computers boot off of that NetBoot set and Casper Imaging starts, the machines will get re-imaged with their AutoRun data.

For more info on Autorun Imaging start at page 384 in the Admin guide (version 9.7 guide is what I'm using).

stevewood
Honored Contributor II
Honored Contributor II

@tcandela as an addendum, PreStage Imaging is for machines that are not in the JSS at all, where AutoRun Data is for machines that are in the JSS and you want to automatically image them when Casper Imaging is run.

Chris_Hafner
Valued Contributor II

Yep. The best part is that you can store that pre-stage info as auto run data for future imaging. That info will be provided as @stevewood mentions, for future imaging needs. There's some additional benefit as well. For example, any policy run on a given unit (either automatically or selectively installed via self-service) can be installed during any future imaging. Say you have the adobe creative suite available to a given user or machine, that NOT part of the normal imaging configuration. The creative suite can be automatically added to any future imaging of that unit without intervention by you, the administrator. That way, users don't need to re-download an optional installer after.

Chris_Hafner
Valued Contributor II

P.S. @mm2270 You are one crazy sharp tech my friend!

alexjdale
Valued Contributor III

One useful extension attribute I've found is "imaging date" which lets me scope to new systems (or systems in any date range) very easily. My setup script simply writes the current date in YYYYMMDD format and I read that into an extension attribute as an integer. I can then create a smart group with "greater than" criteria after a certain date so only new systems are included.

tcandela
Valued Contributor II

I made a smart group based on the criteria of 'serial numbers', i just added all 8 iMacs serial numbers manually to create this group.
I am imaging my test computer with a configuration, I want to see how soon in the process the enrollment happens, thus the test computer should go into the smart group immediately after.

I have a policy that is a custom event policy that gets called 'after reboot' in the imaging process (jamf policy -event installprinter). This policy is scoped to this 'smart group'.

tcandela
Valued Contributor II

Looks like the 'at reboot' scripts run BEFORE the computer gets enrolled (/var/log), thus the custom-event.sh called the custom event but did not add the printer, nor did the Turnoffwifi.sh 'at reboot' make the change.

The test computer did get added to the smart group, so I'll just have the printer and disableairport.sh policies trigger after enrollment , using this computer lab smart group as scope.

The turnoffwifi.sh is taken from JAMF nation scripts

kitzy
Contributor III

Hi @tcandela,

I've run into this issue myself, where enrollment doesn't complete right away after imaging. I got around it by adding some logic into my scripts that check for enrollment, and attempt to force enrollment until successful.

#!/bin/bash
# Check to make sure the machine has enrolled before continuing
/bin/echo "Checking enrollment..."
until [ ! -f "/Library/Application Support/JAMF/FirstRun/Enroll/enroll.sh" ]
    do
        /bin/echo "Machine is not enrolled. Trying enrollment."

        # Attempt enrollment
        /Library/Application Support/JAMF/FirstRun/Enroll/enroll.sh

        # Test if enrollment completed, sleep and try again if not
        if [ ! -f "/Library/Application Support/JAMF/FirstRun/Enroll/enroll.sh" ]
            then
                break
            else 
                sleep 30
        fi
    done
/bin/echo "Enrollment complete"
exit 0

Gist here.

You can see a breakdown of how I'm using that here.

Hope that helps!