Creating computer records in the JSS before device enrollment.

seanjsgallagher
Contributor

I am looking for a way to create computer records in the JSS before the computers are enrolled. I would like to be able to set it to use the serial number for the computer name. I will have a spreadsheet with the serial numbers once they are ordered. We do use the DEP but discussions I have been reading indicate there is no way to leverage that for this.. It was suggested to me that I could use the API, but I have zero experience using it. Has anyone already done this, or done something like it that they could share? I'm willing to learn I am just on a very tight time table. Any help or suggestions would be appreciated.

14 REPLIES 14

Phantom5
Contributor II

You could try macadmins.slack.com JSS API channel. lots of ideas on how to use the API to achieve what you are looking for.

brytox
New Contributor III

I was going to do something similar a while back, the problem is the jss uses udid as the identifier for a computer, not serial, so you would end up with a duplicate record once you have enrolled it.

chelm
New Contributor III

@seanjsgallagher Were you able to find a solution for this? I am having similar issues.

drhoten
Contributor II
Contributor II

Hello @seanjsgallagher, have you taken a look at the Inventory Preload in 10.8 to see if this workflow is what you are looking for? While 10.8 is only for mobile devices, we are working on adding macOS for an upcoming release and would be curious to learn if that would meet your needs.

marklamont
Contributor III

@drhoten It would be useful for many but as @brytox says if jamf is using UUID as the defining data field you can't get that without booting up and enrolling.

drhoten
Contributor II
Contributor II

The Inventory Preload is different than creating a computer record in Jamf Pro before it is is enrolled.

When you upload a CSV file or update the Inventory Preload data using the API, the data is stored in a different table and does not create a device record.

Once the device record is created after enrollment and the inventory report is sent to Jamf Pro, it does a lookup in this table for a matching serial number (and not the UUID). From there, it then updates the user and/or device information for that device based on what has been uploaded.

Additionally with each subsequent inventory report it will check to see what data is different, and overwrite the device information with what is in the Inventory Preload if it is different.

I hope then helps highlight the differences between the two approaches.

ChrisL
New Contributor III

Here's a Feature Req. that addresses this from a different angle: use-serial-numbers-to-identify-macs-instead-of-udid-to-handle-mainboard-replacements

This issue is starting to bite us more and more. When we deploy computers, we need to pre-set various values in a jamf computer record before the machine is enrolled - even more so as we move to DEP-based user-self-enrollment. Our current system is almost painfully complicated because serialnumbers are not used to match existing records with enrolling devices, only udids.

Currently our admins use a homebuilt webapp to create a 'stub' jamf record with the known SN and the desired values. Then when the machine finally enrolls (via DEP or otherwise) there will be two records with that SN. A ComputerAdded webhook is triggered which uses the API to match the newly created 'real' record, with the pre-created 'stub' record by SN. It copies the values from the stub as needed, then marks the stub record for deletion. This has to happen very early in the deployment/configuration process, or things can go south in strange ways.

The whole thing is more complex and fragile than we'd like. If the JSS would just recognize the serialnumber as well as the UDID, our whole adopt-values-from-stub-record process can just go away. That would be wonderful.

drhoten
Contributor II
Contributor II

Hello @ChrisL, thanks for the information.

For your workflow, what specific fields are you setting on the computer record? We've added Inventory Preload for Computers in 10.10.0 and it would be great to compare your list to new functionality to learn whether that meets your needs and would allow you to move away from your current solution.

ChrisL
New Contributor III

Hi @drhoten I just saw your question.

I think the fields available in the CSV are sufficient - most of those we need are Ext Attribs.

The fields available aren't the problem; as it is documented now, the Inv. Preload system enforces the values from the CSV all the time - at every recon. To quote from the docs:

Important: When using Inventory Preload, any manual edits or mass action updates to computer and mobile device inventory details within Jamf Pro will be overwritten by the Inventory Preload data when inventory collection runs.

We need a way to pre-set these values once - just before the machine is deployed, and after that, the record is managed normally, and the values can be changed as desired. Using Inv. Preload, any time after enrollment that we wanted to change one of the pre-set values, we'd have to edit the CSV and re-upload it, rather than just changing the value directly in the computer's record. We would also have to make sure all admins who might make such changes know NOT to do so in the record, but using a custom tool that manipulates the Inv. Preload data via the API.

Even if Inv. Preload records could be told 'apply this only at enrollment' thats still more complex to automate and maintain than simply creating a new computer record with the correct SN and desired values, and waiting for it to enroll.

If the JSS would recognize the serialnumber of an existing record at enrollment, our current tools that pre-create the record would just work. There'd be no need for a webhook to adopt values from the pre-created record into the real record, nor the added complexity/fragility of maintaining the Inv. Preload.

Thanks,
-Chris

PS: As mentioned in the feature request I linked above, recognizing the SN would also help in situations where a logic board has been replaced, which usually means a new UDID but the SN is retained (if the hardware tech didn't forget to set it, which happens, but is hopefully rare)

kerouak
Valued Contributor

..

kerouak
Valued Contributor

I use this python script..

Save CSV to webserver (somewhere)

Then run the script

#!/usr/bin/python
'''
Rename computer from remote CSV using Jamf binary

Pass in the URL to your remote CSV file using script parameter 4

The remote CSV could live on a web server you control, OR be a Google Sheet
specified in the following format:

https://docs.google.com/spreadsheets/u/0/d/<document ID>/export?format=csv&id=<document ID>&gid=0
'''


import os
import sys
import urllib2
import subprocess


CSV_PATH = '/var/tmp/computernames.csv'


def download_csv(url):
    '''Downloads a remote CSV file to CSV_PATH'''
    try:
        # open the url
        csv = urllib2.urlopen(url)
        # ensure the local path exists
        directory = os.path.dirname(CSV_PATH)
        if not os.path.exists(directory):
            os.makedirs(directory)
        # write the csv data to the local file
        with open(CSV_PATH, 'w+') as local_file:
            local_file.write(csv.read())
        # return path to local csv file to pass along
        return CSV_PATH
    except (urllib2.HTTPError, urllib2.URLError):
        print 'ERROR: Unable to open URL', url
        return False
    except (IOError, OSError):
        print 'ERROR: Unable to write file at', CSV_PATH
        return False


def rename_computer(path):
    '''Renames a computer using the Jamf binary and local CSV at <path>'''
    cmd = ['/usr/local/bin/jamf', 'setComputerName', '-fromFile', path]
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    out, _ = proc.communicate()
    if proc.returncode == 0:
        # on success the jamf binary reports 'Set Computer Name to XXX'
        # so we split the phrase and return the last element
        return out.split(' ')[-1]
    else:
        return False


def main():
    '''Main'''
    try:
        csv_url = sys.argv[4]
    except ValueError:
        print 'ERROR: You must provide the URL of a remote CSV file.'
        sys.exit(1)
    computernames = download_csv(csv_url)
    if computernames:
        rename = rename_computer(computernames)
        if rename:
            print 'SUCCESS: Set computer name to', rename
        else:
            print ('ERROR: Unable to set computer name. Is this device in the '
                   'remote CSV file?')
            sys.exit(1)
    else:
        print 'ERROR: Unable to set computer name without local CSV file.'
        sys.exit(1)


if __name__ == '__main__':
    main()

drhoten
Contributor II
Contributor II

Thanks for the clarification on your use-case @ChrisL, I appreciate it.

srogowski
New Contributor II

Does anyone have the script @kerouak posted working in Mojave? We get an error that basically says it can't read the csv file. Not sure what we're doing wrong.

cwaldrip
Valued Contributor

It'd be great if inventory preload would populate the machine names... has that been brought up before? ;-)