Succinct version of `if..elif`

Instead of writing out a large block for an if / elif such as…

if [[ $foo == $bar ]]; then
    echo "yes"
else
    echo "no
fi

a much shorter version can be used instead:

[[ $foo == $bar ]] && echo "yes" || echo "no"

A simple [[ condition ]] && positive result || negative result

VMWare and DEP

Requirements:
VFUSE: https://github.com/chilcote/vfuse/releases
AutoDMG: https://github.com/MagerValp/AutoDMG/releases
VMWare Fusion
Bootable DMG of macOS
Serial number and model identifier of a machine that will DEP

Build a bootable DMG using AutoDMG
Use the following vfuse commands to create the .vmwarevm

sudo /usr/local/vfuse/bin/vfuse -i [path/to/DMG] -n "[name of VM Machine]" -s [DEP Serial] --hw-model [model identifier]

sudo /usr/local/vfuse/bin/vfuse -i /Users/monodata/Documents/_IMAGES/10.13/macOS-10.13.6-17G65.apfs.dmg -n "macOS-10.13.6-DEP" -s C0202XHG0D6T --hw-model MacBookPro14,3

 

MDM & MBP :: Touch ID Not Unlocking Device

Had an issue recently with some users that couldnt unlock their JAMF MDM managed MBP using Touch ID.

After a bit of poking around, I found that I had to:

  1. exclude their machine from the MDM profile
  2. Run the `bioutil` commands [see below]
  3. Re-apply the MDM
  4. Re-add their fingerprints.
bioutil -s -w -u 1

 

The man page for `bioutil` says:

Usage:
bioutil {-r | -w [-f { 0 | 1 }] [-u { 0 | 1 }] [-a { 0 | 1 }]} | [-c] | [-p] | [-d <uid>] [-s]

Options:
    -r, --read                      Read current Touch ID settings
    -w, --write                     Write new Touch ID settings
    -s, --system                    Flag to read/write systemwide Touch ID settings or perform systemwide operations
    -f, --function                  Enable (1) or disable (0) Touch ID functionality in general (system settings only)
    -u, --unlock $value             Enable (1) or disable (0) Touch ID for unlock
    -a, --applepay $value           Enable (1) or disable (0) Touch ID for ApplePay (user settings only)
    -c, --count                     Print number of enrolled fingerprints of the current user or of all users (-s, administrator only)
    -p, --purge                     Delete all enrolled fingerprints of the current user or of all users (-s, administrator only)
    -d, --delete $uid               Delete all enrolled fingerprints of the given user (administrator only)

 

BASH :: Always make sure to validate your inputs!

Got caught out not checking if a variable had been passed to a script that then used it to delete an .app.

Added in lines 8 – 11 to validate the input. Thankfully, only 3 machines affected!

#!/bin/bash

#  Get folder path when run through Casper (Comment out as applicable)
#  Enter the full path to the folder in the 'Parameter 4 Field' in Casper
# then check its not empty or it will delete everyhting from someones machine!
app=$4

if [[ $app == "" ]]; then
    echo "App field is empty. Stopping before everything is deleted!" >> /var/log/jamf.log
    exit 1
fi

FolderPath="/Applications/${app}"


# Check path exists then delete
if [[ -e "$FolderPath" ]]; then
  # delete
  /bin/rm -Rf "$FolderPath"
  if [[ ! -e "$Folderpath" ]]; then
    echo "${app} has been deleted." >> /var/log/jamf.log
  else
    echo "Removing ${app} failed." >> /var/log/jamf.log
  fi
fi

exit $?

Bash :: Check PKG Receipt Exists

While scripting a configuration manifest for DEPNotify, it would skip to the next policy before the last had completed, and so would skip to the end and close the splash screen before the build was finished.

This defeats the purpose of having a screen stopping any interaction until the machine had completed so after a little interaction on the #DEPNotify slack channel on Macadmins, it was suggested to write a bom file as the last action of a policy but this would require every policy to have additional work to add this.

JAMF already writes an empty PKG or DMG to `/Library/Application Support/JAMF/Receipts/` upon completion so why not use this?

Below is the function I wrote:

#!/bin/bash

# Check to see if package receipt exists. Time range is 1 mins
# if it does, it returns the full package name. If not, it waits until
fileExists() {
  # Package name passed with FUNC
  package=$1
  
  # Path to JAMF pkg receipts
  receiptPath="/Library/Application Support/JAMF/Receipts"
  
  # Time range for find: currently 30 mins
  range="$(date -v -30M)"
  
  # Find pkg receipts that match $1 less than 30 mins old
  results="$(find "${receiptPath}" -newermt "$range" | grep -i $package)"
  
  # Strip the path
  results="$(basename "$results")"

  # Loop until result exists; echo pkg name when it does
  while :; do
    [[ $results != "" ]] && echo $results && break
    sleep 1
  done
}

Python: Build Application List

My first major Python script!

I created a script that took the list of applications from a standard build then compares to a CSV file from a users current machine, subtracts them and what’s left is the additional apps to add at build time.

It uses `csv.Sniffer` to work out what the delimiter is so it can detect if its ‘,’ or ‘;’ or tabs, etc. [Line 13 is where the heavy lifting is]

Here’s the script:

#!/usr/local/bin/python3

# Imports
import csv, os, pathlib, glob
from pprint import pprint


def read_csv_delimit(csv_file):
    # Initialise list
    file_csv = []
    # Open csv & check delimiter
    with open(csv_file, newline='', encoding = "ISO-8859-1") as csvfile:
        dialect = csv.Sniffer().sniff(csvfile.read(1096))
        csvfile.seek(0)
        reader = csv.reader(csvfile, dialect)
        for item in reader:
            file_csv.append(item[0])
        #del file_csv[0]
        return file_csv

def write_csv(file_dir, csv_file, new_machine_list):
    # Open file then write the lines
    if os.path.exists(file_dir + "/" + csv_file):
        append_write = 'a'
    else:
        append_write = 'w'

    file_name = csv_file
    
    with open(file_dir + "/" + csv_file, "w") as csv_file:
        writer = csv.writer(csv_file, delimiter=',')
        writer.writerow([file_name])
        for line in new_machine_list:
            writer.writerow([line]) 

def split_path(full_path):
    #path = path.rstrip(os.sep)
    head, tail = os.path.split(full_path)
    return (head, tail)

def enumMachines(machine_dir):
    machines = []
    for filename in glob.glob(machine_dir + "/*.csv"):
        machines.append(filename)
    return machines

def main():
    # Get the paths to the csv files
    app_csv = input("drop the app list csv here: ")
    machine_dir = input("drop the machines csv folder here: ")

    # Gets list of machines with extension of .csv
    machines = enumMachines(machine_dir)

    # get csv data
    app_list = read_csv_delimit(app_csv)

    for machine in machines:

        # import machine csv data
        machine_list = read_csv_delimit(machine)
        # delete the first row
        del machine_list[0]

        # list comprehension
        new_machine_list = [app for app in machine_list if app not in app_list]

        # get the machine csv name
        new_machine_dir, new_machine_csv = split_path(machine)

        # new folder to write to
        new_machine_dir = machine_dir + "/" + "edited"

        # create the new folder if it doesnt exist
        pathlib.Path(new_machine_dir).mkdir(parents=True, exist_ok=True)

        # Write the machine name first
        #write_csv(new_machine_dir, new_machine_csv, new_machine_csv)

        # write to the new csv
        write_csv(new_machine_dir, new_machine_csv, new_machine_list)



if __name__ == '__main__': main()

init()

Just a first page to launch the site really!

I’m going to post ramblings about learning to code and links to scripts.