A Simple Python Script for Naming Macs

I recently have been working at my new job to learn as many ways as possible to automate our current setup.

One thing that I took a day or so to work on was finding a way to automate our naming conventions.

The following script is still in development, hasn't been tested on any machines other than verifying that the output worked as intended. It is intended to be run by JAMF, so it will run as root.

import subprocess
import sys
import os
from SystemConfiguration import SCDynamicStoreCopyConsoleUser

# dictionary matching our model naming schemes for Macs to their model identifiers

model_id_dict = {'15MBP': ['MacBookPro15,1', 'MacBookPro14,3', 'MacBookPro13,3',
                          'MacBookPro11,4', 'MacBookPro11,5', 'MacBookPro11,2', 
                          'MacBookPro11,3', 'MacBookPro10,1', 'MacBookPro9,1'],
                '13MBP': ['MacBookPro15,2', 'MacBookPro14,2', 'MacBookPro14,1',
                          'MacBookPro13,2', 'MacBookPro13,1', 'MacBookPro12,1',
                          'MacBookPro11,1', 'MacBookPro10,2', 'MacBookPro9,2'],
                '27iMac': ['iMac18,3', 'iMac15,1', 'iMac17,1', 'iMac15,1', 
                           'iMac14,2', 'iMac13,2', 'iMac12,2', 'iMac11,3'],
                '21iMac': ['iMac18,1', 'iMac18,2', 'iMac16,1', 'iMac16,2',
                           'iMac14,4', 'iMac14,1', 'iMac13,1', 'iMac12,1',
                           'iMac11,2']}

# variable for to store results of model id bash command
fetch_model_id = subprocess.check_output(['sysctl','hw.model'])
search_model_id = fetch_model_id.strip('hw.model:').strip('\n').strip()
model_name = ''

# reverse dictionary lookup to set model name based on model id
for name, model_id in model_id_dict.items():
    if search_model_id in model_id:
        model_name = name
        break
    else:
        model_name = 'Mini'

def get_console_user():
    '''Uses Apple's SystemConfiguration framework to get the current
    console user'''
    cfuser = SCDynamicStoreCopyConsoleUser(None, None, None)
    return cfuser[0]


console_user = get_console_user()
user_real_name = subprocess.check_output(['id','-F', console_user])
computer_name = ''.join(user_real_name.split()) + '-' + model_name


def set_computer_name(cname):
    '''function to set hostname, localhost, and computer name
    to the same value and flush the cache'''
    commands = ['HostName', 'LocalHostName', 'ComputerName']
    for name_type in commands:
        subprocess.call(['scutil', '--set', name_type, cname])
    subprocess.call(['dscacheutil', '-flushcache'])


if user_real_name == 'Local Administrator':
    sys.exit(0)
else:
    set_computer_name(computer_name)

check_computer_name = subprocess.check_output(['scutil', '--get', 'ComputerName'])
if check_computer_name == computer_name:
    sys.exit(0)

Our naming scheme prior to this script has been a manual affair: modify the Mac's name on JAMF Pro to fit the format of {Firstname}{Lastname}-{Model} This is not something that's easily automated since the abbreviated model names weren't something used by Apple.

What I had to do was go to Apple's website and manually transcribe the model identifiers into a dictionary in Python. I used subprocess.check_output() to generate a string and save it to a variable to compare to the dictionary and perform a reverse lookup.

After that lookup it assigns the key as the model_name variable. Then it's cleaned up by stripping out the "hw.model: " string from the output.

To lookup the user who this will be named after, I originally just had it run id -F to find the Full Name attribute of the user, but without realizing that would look up the user running the script.

To resolve that issue, it is possible to run the command with an argument of the username.

id -F [username]

I was referred by another Mac Admin to a function on the Munki GitHub repository that uses Apple's SystemConfiguration framework to get the current console user.

I adapted it into my code, moving the dependencies up to the import lines and renaming the function to follow my naming conventions. The function is used to save the username to a variable. Then it's used by the subprocess.check_output() method to run id -F [username], which then saves a string with the Full Name attribute.

The final name is created by cleaning up the output and appending the hyphen and model name to it:

computer_name = ''.join(user_real_name.split()) + '-' + model_name

I then check to make sure that the logged in user isn't our “Local Administrator” account to prevent improper naming and exit the script. If the logged in user is the end user, it then sets the computer's HostName, LocalHostName, and ComputerName to match the output and flushes the caches.

I'll go through a full test of this soon, but for right now, this was really an exercise in if I could do this with Python and to set the framework for the future.

I hope you enjoyed this little explanation. Follow the development of this script on GitHub if you're interested and feel free to comment if you have ideas on how to improve it.

Cheers!

❤️ -Vince