Tiny Deathstars of Foulness

The next release of iOS (10.3), macOS (10.12.4), and tvOS (10.2) bring us a host of new management features. These include DEP configuration, remote wipe, single app mode, conference room mode, and remote reboot for Apple TVs. The next evolution of iOS brings us sounds in lost mode, the ability to prevent users from connecting to unmanaged wireless networks (just make sure to push that policy after sending down the actual managed wireless networks – or eek), the option to remotely shut down and reboot devices,

The Mac options includes some of the above but also restricting the feature to unlock macOS devices with Touch ID, restrict documents and desktop syncing with Apple’s iCloud service. Shared iPad environments also get new passcode policies.

Jamf Pro 9.98 has also comes with Symantec PKI integration and lots, and lots, and lots of resolutions to product issues. For more, see For a full run-down of profile options and MDM commands:’s_New_in_This_Release.html.

Keeping with Apple’s evolving standards, Managed Preferences and Provisioning Profiles are being deprecated: (which isn’t to say you can’t still deploy these kinds of things using your own scripts, etc).

Finally, if you have a problem in your environment and want to see if it’s been fixed, for a list of defects and product improvements – see

March 23rd, 2017

Posted In: JAMF, Mac OS X, Mac OS X Server

Tags: , , , ,

Leave a Comment


Some tasks are like the Labrynth. You walk around a corner, mark a block in chalk so you can go back, and then a goblin switches your arrow to a different direction. Or you go through a door and fall down an oubliette. But hey, if you write a few more scripts, you can always bring sanity to those you already have but don’t know exist, right?

March 22nd, 2017

Posted In: Uncategorized

Leave a Comment

You search for items in macOS using compound conditions in a number of ways. One way is with awk. Here, we’re going to grab the output of a simple ls command. That gets piped into an awk statement. Then we’re going to look at the expression to evaluate. Basically, we’re going to say anything that contains com. as well as apple and .plist. Because it’s ls, we’re looking for names of files that match those patterns. Each pattern is listed in brackets. And then there’s the {print} to lay out the action of printing to the files that match the pattern to the screen:

ls |awk '/[com.][apple][.plist]/ {print}'

Note: I know you’re not supposed to use ls in scripts. Don’t care. If it were dates and such, I’d of used stat…

March 14th, 2017

Posted In: Mac OS X, Mac OS X Server

Tags: , , , ,

One Comment

If you happen to be tweaking the macOS subsystems for logging, I’ve put them into a little python class. If you need it, find it at this gist:

Could use an array of all the levels, TTLs, and options. But I’ll get to that when I get some time. If this is all you need, though:

class Logging(object):

__name__ = ''
plist = '/System/Library/Preferences/Logging/Subsystems/'

def __init__(__name__, plist, *args, **kwargs):
super(getLogger/, self).__init__()'Input parameters:\n'
'accessibility: "{}"\n'
'StandaloneHIDFudPlugins: "{}"\n'
'duetactivityscheduler: "{}"\n'
'passkit: "{}"\n'
'AppKit: "{}"\n'
'SystemConfiguration: "{}"\n'
'eapol: "{}"\n'
'persona: "{}"\n'
'AppleIR: "{}"\n'
'TCC: "{}"\n'
'icloudpreferences: "{}"\n'
' "{}"\n'
'AssetCache: "{}"\n'
'TimeMachine: "{}"\n'
'internetAccounts: "{}"\n'
'photoanalysisd.graph: "{}"\n'
'AssetCacheServices: "{}"\n'
'Transport: "{}"\n'
'libsqlite3: "{}"\n'
'photoanalysisd.job: "{}"\n'
'BezelServices: "{}"\n'
'accounts: "{}"\n'
'locationd.Core: "{}"\n'
'photoanalysisd: "{}"\n'
'DesktopServices: "{}"\n'
'amp.MediaServices: "{}"\n'
'locationd.Legacy: "{}"\n'
'pluginkit: "{}"\n'
'ExchangeWebServices: "{}"\n'
'authkit: "{}"\n'
'locationd.Motion: "{}"\n'
'sandbox.reporting: "{}"\n'
'FaceTime: "{}"\n'
'avfaudio: "{}"\n'
'locationd.Position: "{}"\n'
'sbd: "{}"\n'
'Finder: "{}"\n'
'awd.awdd: "{}"\n'
'locationd.Utility: "{}"\n'
'securityd: "{}"\n'
'HTTPServer: "{}"\n'
'awd.framework: "{}"\n'
'mDNSResponder: "{}"\n'
'sharing: "{}"\n'
'IDS: "{}"\n'
'bluetooth: "{}"\n'
'mac.install: "{}"\n'
'siri: "{}"\n'
'IPConfiguration: "{}"\n'
'calendar: "{}"\n'
'mail: "{}"\n'
'social: "{}"\n'
'ManagedClient: "{}"\n'
'captive: "{}"\n'
'mediaremote: "{}"\n'
'socialpushagent: "{}"\n'
'Messages: "{}"\n'
'catalyst: "{}"\n'
'multipeerconnectivity: "{}"\n'
'symptomsd: "{}"\n'
'MessagesEvents: "{}"\n'
'cdp: "{}"\n'
'network: "{}"\n'
'syncdefaults: "{}"\n'
'NetworkSharing: "{}"\n'
'clouddocs: "{}"\n'
'networkextension: "{}"\n'
'useractivity: "{}"\n'
'ProtectedCloudStorage: "{}"\n'
'coreanimation: "{}"\n'
'networkserviceproxy: "{}"\n'
'Registration: "{}"\n'
'coreaudio: "{}"\n'
'nlcd: "{}"\n'
'SkyLight: "{}"\n'
'coredata: "{}"\n'
'notes: "{}"\n'

except Exception as e:

March 13th, 2017

Posted In: Mac OS X

Tags: , , , , , , , ,

Leave a Comment

My latest Huffington Post article is available at and starts off as follows:

Whether establishing a business agreement with a client, buying a car, or purchasing services at work, negotiating contracts is an inevitable part of life. Most negotiation advice dispensed online or in books falls far short of the mark, and some of it can actually backfire. Pretending that you have another, better potential deal in the wings or being too aggressive, for example, both shut down the possibility of forming a real connection with the other party—thereby making them less willing to cut you a good deal. In other words, a lot of the traditional tools out there are just inauthentic.

A few strategies help set the record straight when it comes to contract negotiation, allowing you to get the best deal possible:

To read more, see

March 10th, 2017

Posted In: Articles and Books, Business

Tags: , ,

Leave a Comment

March 8th, 2017

Posted In: Mac OS X Server, Mac Security, MacAdmins Podcast

Leave a Comment

My latest @inc piece is up, at It starts like this:

Telecommuting is on the rise. According to a 2015 Gallup poll, 37 percent of U.S. workers say they have telecommuted at one point or another– four times greater than in 1995.

But working remotely can be a challenge. Not only can telecommuters feel disconnected from the organization, the organization can also feel disconnected from them.

If you’re into it, read the rest of the article here. Telecommute and have other tips, comment below? 🙂

March 7th, 2017

Posted In: Articles and Books, Business

Tags: , ,

Leave a Comment

One of my favorite things about grabbing things with scripts is just how many ways (and sometimes how needfully or needlessly convoluted you can make them) to grab the same pieces of information. For example, something as simple as what hosts you use to resolve names on a Mac. There are a number of ways to grab what DNS server a device is using in macOS. So when you’re running a script you might choose to grab DNS information one way or another, according to what you’re after. Some of this might seem more complicated than it should be. And that’s correct…


The /etc/resolv.conf file is updated automatically to look at what servers are used to resolve names used for DNS. The easiest way to see theses to simply cat it and grep for nameserver:

cat /etc/resolv.conf | grep nameserver


The next way we’ll grab DNS information is using scutil. Here, we use the –dns option, which outputs a lot of DNS stuffs, including all the built-in resolvers:

scutil --dns

To just grab the name servers:

scutil --dns | grep nameserver

We can also simplify the output to just the servers with awk:

scutil --dns | grep nameserver | awk '{print$3}'


The second way is using networksetup. This command has an option to get a DNS server in (shocker) -getdnsservers. However, you have to list the interface for each. So below we’ll dump all interfaces into an array using -listallhardwareports and then read them in using a for loop and querying the name servers.

interfaces=( "$(networksetup -listallhardwareports | grep Hardware | cut -c 16-900)" )
for i in "${interfaces[@]}"
networksetup -getdnsservers $i

The one tricky thing in this one is I initially forgot to quote the interfaces as they went into the array, which meant each word of the interface was an item in the array and therefore the -getdnsservers option failed. Once I quoted, it was all happy. The other thing I can point out is I used cut instead of sed because it was easier to quote; however, it seems unlikely the name can be more than 890 characters, so I think it’s fine…


You can also use dig. Here, you’ll query for a name without using an @ option, but omit everything but the line with the server that responded:

dig | grep SERVER:

The output is kinda’ fug:


For simpler output, we’ll use sed to constrain the output to just what’s between the parenthesis:

dig | grep SERVER: | sed 's/^.*(//;s/)$//'


nslookup is a tool similar to dig, used for querying names. We’ll basically do the same thing as above, just using awk as it’s just a standard position in a line:

nslookup | grep Server: | awk '{print$2}'


Then there’s system_profiler, the command line interface for System Profiler. Here, we can query the SPNetworkDataType. This is going to produce a lot of output, so we can limit it to just the DNS servers using grep to constrain to just the lines we want and awk for just the columns in those lines, as follows:

system_profiler SPNetworkDataType | grep "Domain Name Servers:" | awk '{print$4}'


@knapjack added to use hosts. I had to use verbose mode to pull the local name server as follows:

host -v -t ns | grep Received | awk '{print $5}'


Thanks to the lovely Allister (@sacrilicious), we also have ipconfig to add to the list:

/usr/sbin/ipconfig getpacket en0 2> /dev/null | grep name_ | cut -d' ' -f3-

There are tons of ways to find things in macOS. Do you have a way to find a DNS server that I didn’t think of here?

March 6th, 2017

Posted In: bash, Mac OS X, Mac OS X Server, Mac Security, Ubuntu

Tags: , , , , , , ,


March 1st, 2017

Posted In: Uncategorized

According to @johnkitzmiller, you can’t spell function without fun. So let’s have some fun! What’s a function? Think of it as a script inside a script. Define functions at the beginning of the script instead of making repeated calls to the same task within a script. The other nice thing about functions is that the act of compartmentalization makes them simple to insert into a number of different scripts. For example, if you do a lot of curl commands to pull down something in a lot of different scripts, having the grabbing of the data as a function, then the parsing of it into an array as a function and ultimately the writing of it or dealing with an stderr as another might make it simpler to then port it into the next script and the next.

Functions are simple to define. Just use (yes, you guessed it) the function command. So let’s look at the most basic function. Here, we’ll wrap a simple echo line inside curly brackets. So the syntax is function followed by the name of the function, followed by a curly bracket to introduce it. Then, I like to put a curly bracket on a line at the end of the function. Then I have a line where I just call the function. Note, there’s no special indicator, like a $ in front of the name of it or anything like that (unless you maybe variabalized it):

function hellokitzy {
echo "Hello Kitzy"

OK, so when you call it, it says hellokitzy. Obviously it could have nested if/thens, whiles, cases, etc. Now, let’s have two functions. In this example, we’ll basically just split the single echo statement into two; then call them in separate lines:

function hello {
echo "Hello"
function kitzy {
echo "Kitzy"

As with shell scripts, you can also push a positional parameter into the function. Here, we pass a positional parameter into the script and it echos a hello to that parameter. You know, making our scripts a bit more personal and all… Then we call the function twice. In the first instance, we just pass the same parameter, but in the second, we actually replace it. We do this to show that the function overwrites the $1 inside that function, but if we did another call to the function we’d just get the original $1 as it doesn’t persist outside of the function:

function term {
function hello {
echo "Hello" $1
hello $1
hello all
echo "bye"

When run with a parameter of Kitzy, the above would simply output:

Hello Kitzy
Hello all

That’s just for positional parameters that you’re feeding into a script though. If you have a variable (let’s call it a) and you update it in a function, then it will be the updated variable after the function. So in the following example, a echos out as two in the end:

function quit {
echo $a

Overall, functions are easy to use and make your code more modular. The only things that get a little complicated is that unless you know functions, you aren’t sure what’s going on in the beginning and when you are editing variables throughout the script you wanna’ make sure you know what changed things and when.

OK, now you – have fun with functions, and feel free to use the comments to post some you wrote!

February 28th, 2017

Posted In: Mac OS X, Mac OS X Server, Mac Security, Unix

Tags: , , , ,

Next Page »