Jamf Pro EA: Member of AD Group

jamfProThis is an extension attribute script to determine if the user assigned to the computer is a member of a given AD group or groups.

In the example below, the script will return a “Yes” result if the user to which the computer is assigned in Jamf Pro is a member of the groups “ADGroupX” or “ADGroupY”.

The script will…

  • Get the computer’s serial number
  • Pull the computer record via the Jamf Pro API
  • Harvest the contents of the “username” field
  • Get the domain via dscl (computer must be bound to AD)
  • Determine if “username” is a member of “ADGroupX” or “ADGroupY”

This script can certainly be cleaned up a bit but does the job effectively.

#!/bin/sh

# Is the user assigned to this computer a member of a given AD group or groups.
# In this example, the target groups are "ADGroupX" and "ADGroupY"

serialNumber=$(ioreg -l | awk -F'"' '/IOPlatformSerialNumber/ { print $4;}')
response=$(curl -v -k -u apiComputerReadUsername:apiComputerReadPassword -H "Accept: application/xml" -H "Content-Type: application/xml" https://JamfProUrl/JSSResource/computers/serialnumber/$serialNumber)

assignedUser=$(echo $response | xpath '/computer/location/username/text()' 2>/dev/null)

domain=$(dscl /Active\ Directory/ -read . | grep SubNodes | sed 's|SubNodes: ||g')

membership=$(dscl /Active\ Directory/"$domain"/All\ Domains read /Users/$assignedUser dsAttrTypeNative:memberOf | egrep 'ADGroupX|ADGroupY')

if [[ "$membership" == "" ]]; then
 echo "<result>No</result>"
 else
 echo "<result>Yes</result>"
 fi

exit 0

The script can also be found on GitHub below.

https://github.com/themacadmin/extensionAttributes/blob/master/EAMemberOfADGroup

Resetting AirPlay

AirplayIconI have been having occasions lately where I’ll lose audio whilst using AirPlay mirroring from my Mac running OS X version 10.8.4 to my Apple TV running the latest Apple TV Software, version 5.3.  When this issue occurs, audio from iTunes, Hulu, Netflix, etc. on the Apple TV plays audio normally, as does AirPlay content from an iOS device.  It seems to be only OS X devices that are affected.  Searches of Apple support forums and other places Mac nerds share information showed that this is not an issue peculiar to my equipment.

I have reported the issue to Apple, as I’m sure others have, and will continue to investigate on my own to see if I can uncover a specific cause and more finely tuned fix.  In the meantime, forcing Core Audio on the Mac to restart seems to solve the problem, at least temporarily.  Use the following command to stop Core Audio, which will then automatically restart.

sudo killall coreaudiod

I’ve also bundled this into an Automator application, if that makes things a bit easier for some.  It will prompt for administrative credentials when launched.

Download Restart coreaudiod

Note: Restart coreaudiod is provided “as is” without warranty of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability, or fitness for a particular purpose.

 

Cleaner Security Scripting

terminalIn previous articles, we have discussed making changes to the /etc/authorization file, also known as the authorization policy database or authorization database, using text editors.  Apple has a tool in Mac OS X that is specifically designed for that purpose.  /usr/bin/security, in addition to a multitude of other uses, security has a command called authorizationdb that allows for edits to the authorization database.

The authorizationdb command has three options, read, write and delete.  These function in much the same way as the defaults command is used to edit preference files.  Let’s use the previous article on setting DVD region codes as an example.  In that article, we discussed how to enable any user to set the initial DVD region code, but still require an administrative user to change the code once set.

To read the current authorization rule, we’ll use this command…

/usr/bin/security authorizationdb read system.device.dvd.setregion.initial

…which gives us the following output…

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
     <key>class</key>
     <string>user</string>
     <key>comment</key>
     <string>Used by the DVD player to set the region code the first time. Note that changing the region code after it has been set requires a different right (system.device.dvd.setregion.change).</string>
     <key>default-button</key>
     <dict>
          <key>en</key>
          <string>Set</string>
     </dict>
     <key>default-prompt</key>
     <dict>
          <key>en</key>
          <string>__APPNAME__ is trying to set the DVD region code for the first time.</string>
     </dict>
     <key>group</key>
     <string>admin</string>
     <key>shared</key>
     <true/>
</dict>
</plist>

Notes: Non-English strings in the default-button and default-prompt dictionaries have been removed for brevity.

The boldface “class” key and its value (emphasis mine) are the operative values that we are working with.  Using the write option for the authorizationdb command, we can make the same change described in the previous article, allowing any user to set the initial DVD region code, with a one-line script.

/usr/bin/security authorizationdb write system.device.dvd.setregion.initial allow

After running this command, if we read the contents of the system.device.dvd.setregion.initial key again using /usr/bin/security authorizationdb read system.device.dvd.setregion.initial, we now receive the following output…

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
     <key>rule</key>
     <string>allow</string>
</dict>
</plist>

Not only does /usr/bin/security simplify editing the authorization database, it also results in a cleaner entry.

I hope this is useful.

Mounting the EFI Boot Partition on Mac OS X

terminalHere’s the answer to another reader request…

According to WIkipedia, “On Apple–Intel architecture Macintosh computers, the EFI partition is initially blank and not used for booting. However, the EFI partition is used as a staging area for firmware updates.”  When people look to create non-standard boot environments or attempt to build a hackintosh, the first step is often mounting and modifying the EFI boot partition.  Before you read any further, take note: altering your EFI boot partition is not supported by Apple and The Mac Admin takes no responsibility if you render your computer(s) unbootable by mounting and modifying this partition.

To mount an EFI boot partition, follow these steps:

1. Discover the volume identifier for your EFI boot partition.

Run this command:

diskutil list

The output should look something like this:

/dev/disk0
 #: TYPE                     NAME          SIZE       IDENTIFIER
 0: GUID_partition_scheme                  *251.0 GB  disk0
 1: EFI                                    209.7 MB   disk0s1
 2: Apple_HFS                Macintosh HD  250.1 GB   disk0s2
 3: Apple_Boot               Recovery HD   650.0 MB   disk0s3

 

In this case, the volume identifier of the EFI partition is disk0s1

2. Create a mount point.

A mount point is a directory where a non-booted volume is mounted.  On Mac OS X, mount points are typically created in /Volumes.  We can create a directory called efi within /Volumes by running the following command:

mkdir /Volumes/efi

 

3. Mount the EFI partition at the efi mount point.

Run the command:

sudo mount -t msdos /dev/disk0s1 /Volumes/efi

 

That’s it.  Your EFI volume will be mounted.  Modify it at your own risk.

Setting A Default Paper Size

printerThis post is in response to a reader request.

In Mac OS X, the default paper size is a setting that determines the size of paper that applications will try to print to unless the user chooses otherwise. For most systems and applications this defaults to US Letter.  In order to provide a positive user experience, especially for end users outside of the United States, it may be desirable to set a different default paper size.

The file that contains this preference is:
~/Library/Preferences/com.apple.print.PrintingPrefs.plist

This makes the preference domain: com.apple.print.PrintingPrefs

The Key that governs the preference is called : DefaultPaperID

DefaultPaperID contains a string value that corresponds to a paper size. See the chart below:

Paper Size String
US Legal na-legal
US Letter na-letter
A4 iso-a4
A5 iso-a5
JIS B5 jis-b5
B5 iso-b5
Envelope #10 na-number-10-envelope
Envelope DL iso-designated-long-envelope
Tabloid tabloid
A3 iso-a3
Tabloid Oversize arch-b
ROC 16K roc16k
Envelope Choukei 3 cho-3-envelope
Super B/A3 arch-b-extra

To set this preference with a script use the command below, replacing with the correct string for the intended paper size.

For a single user, run as the user:
defaults write ~/Library/Preferences/com.apple.print.PrintingPrefs DefaultPaperID

For all users, run as root:
defaults write /Library/Preferences/com.apple.print.PrintingPrefs DefaultPaperID

This process has been tested on Mac OS X v10.6 (Snow Leopard), v10.7 (Lion) and v10.8 (Mountain Lion).

I hope you find this useful.

Scripting: Using cut to Capture Information

terminalIn the previous article we discussed using grep and awk to harvest information.  The final example in that article may have left us wanting.  In this article, we’ll discuss some additional options that the cut command can give us.

As we discussed, the following command:

diskutil info / | grep "Volume Name:" | awk '{print $3}'

would output the name of our boot volume, assuming there were no spaces in it.  However, if our target Mac had a factory standard boot volume called “Macintosh HD”, we’d need to change our command to:

diskutil info / | grep "Volume Name:" | awk '{print $3,$4}'

If there were more than one space in our volume names, well, it all becomes a bit much to manage. Unfortunately, awk doesn’t provide a method to display word X and all following words, so we will look to another command called cut.

According to its man page, cut is designed to “cut out selected portions of each line of a file”.  Cut can work with “words”, like awk, or it can work with characters.  We’ll look at working with words first.  Unless specified otherwise, cut assumes that words are delimited (separated) by tab characters.  If the delimiter is something other than a tab, the delimiter must be defined using the “-d” option.  After defining the delimiter, we must tell cut which words we would like to output.  We do this using the -f option, followed by a number indicating the word’s position.  Unlike awk, we do not need a “$” or other character to indicate our word selection, just the number.  Also unlike awk, we can specify a range, including “X-” which tells cut to return the word at position X and everything after it, which we will do below.

diskutil info / | grep "Volume Name:" | cut -d ' ' -f 19-

The “-d” option has indicated that our delimiter is a space.  The “-f” option has asked for words 19 through the end of the line.  This may seem a bit confusing because if you look at the output of the first two commands, it would seem that we would be interested in word number 3 and onward.  It would appear that diskutil’s output contains both spaces and tabs, and a bit of trial and error helped to arrive at the number 19.  This command will return our boot volume’s name regardless of the number of spaces in the name.

The other option when working with cut is to simply count characters.  This precludes a need to define a delimiter.  By counting characters, we can find the same information with the following command:

diskutil info / | grep “Volume Name:” | cut -c 30-

This line will return character number 30 and all characters that follow it.  Like the example using the -d and -f options, this will return our boot volume’s name regardless of the number of spaces in the name.

We see that cut can provide us with some capabilities that awk doesn’t.  Hopefully this examination will help you to capture data in your own scripts.

The commands in this article have been tested on Mac OS X versions 10.5.8 and 10.6.7 (build 10J869).  Thanks go to Lisa at lisacherie.com for assistance in testing the commands used in this article.

Scripting: Getting Volume Details Using grep and awk

terminalAs sysadmins, we often need to write scripts that will interact with hard disks or other volumes on a client computer.  These scripts usually need some information about the volume(s) being worked with, such as a device identifer, UUID, etc..

I often see my fellow sysadmins making assumptions such as a Mac’s boot volume will be known by the device identifier “disk0s2”.  While this is often the case, it is by no means guaranteed.  For my money, often being correct isn’t acceptable, especially when always being correct can be achieved with a relatively short command. In this vein, I will outline some commands to harvest various volume information below.

Device Identifier

Some disk management commands require a device identifier.  The device identifier is in the format diskXsY.  diskX refers to a physical device.  sY refers to a volume or “slice” of diskX.

diskutil info / | grep "Device Identifier" | awk '{print $3}'

Volume UUID

The Volume UUID, or Universally Unique IDentifier, is a unique ID code generated for every volume.  The UUID is required for some disk operations.  Volume UUIDs are persistent regardless of your currently booted system.

diskutil info / | grep "Volume UUID" | awk '{print $3}'

Volume Name

Sometimes we’ll need to know the name, also referred to as the “label”, of a volume.  This is the name we see displayed in Finder.

diskutil info / | grep "Volume Name:" | awk '{print $3}'

Breaking It Down

You may have noticed a pattern in the commands above.    All of the sample commands begin with “diskutil info.”  Simply executing “diskutil info” followed by a volume, will output a list of information about that volume.  In the example commands above, we use “/”, which refers to the current boot volume.  By replacing “/” with “/Volumes/<otherVolumeName>” we can retrieve information from other volumes mounted on the Mac.  The pipe or “|” character passes the output from this command to the next one.

The next command is “grep”, followed by a quoted term.  Grep is a very powerful UNIX tool, but here, we’re using one of its most basic functions.  Grep will look within the text that it receives as input, in this case the output of “diskutil info /”, for the search term we’ve provided.  If the term is found, grep returns the entire line (s) on which our search term appears.  The grep output is then piped to the next command.

awk is another powerful tool;  books with page counts in the hundreds have been written about it.  Like grep, we are using one of awk’s more simple functions here.”awk ‘{print $X}'” takes the input it is given, the output of the grep statements in these examples, and returns the “word” at position X.  I’ve put “word” in quotes because awk doesn’t define word the same way as the English language does.  To awk, a word is a string.  Words are separated by spaces.  If we run our last example command (diskutil info / | grep “Volume Name:”) on a system booted to a volume called “BootDrive”, the output from the first two parts of the command  is ”   Volume Name:      BootDrive”.  In this case, “Volume” is word 1, “Name:” is word 2, and finally “BootDrive” is word 3.  This is why we ask awk to return word 3.

Note that if your volume name has a space in it, such as the factory default “Macintosh HD”, the command listed above would only return the first word of your volume name, for example, “Macintosh”.  To get awk to return multiple words, multiple words can be referenced inside the brackets, separated by commas.  For example “awk ‘{print $3,$4}'” would return the words at positions 3 and 4, with a space between.  We could repeat this for as many words as you need.  such as “awk ‘{print $X,$Y,$Z…..<and so on>}'”.  It is not necessary to choose consecutive words either.  “awk ‘{print $1,$5}'” would work just as well.  Referencing empty word positions will not generate any output, meaning that if we executed “diskutil info / | grep “Device / Media Name” | awk ‘{print $3,4}'” on a system with a boot volume called “BootDrive”, our output would be simply “BootDrive”.

Well, I hope some of you have found this exploration useful.  Future articles will build on what we’ve discussed here.