Tiny Deathstars of Foulness

Given the increased reliance on XML in scripts and exchanging data, a number of different solutions leverage XML traversal options to get all the things done. We frequently use path to bring a file into a script or program, or accept input from STDIN. The most basic task that we then perform is simply selecting an item from that file or STDIN and then variabalizing it. One common tool that we use here is Path. XPath calls these objects nodes, and uses path expressions to select these nodes. A path expression is the path along the xml input that is followed to find a piece of data.

There are some pretty standard wildcards the can be used with xpath, where node() watches any node, * matches any element node, @* matches any attribute node, helping to constrain output.

Supported expressions include:

  • node: This is a text input that identifies the name of a node to start a relative search from – for example site would select all nodes in a structure with the name site
  • . Identifies the current node (kinda’ like pwd in a shell)
  • .. Starts at the parent of the current node – for example,
  • / Starts traversal from the root node – for example, /computer would select any nodes that falls underneath
  • /computer meaning that these are absolute paths
  • // Identifies the nodes in an XML structure that match a selection wherever they may be – for example
  • //computer would select all nodes that contain //computer and search for other expressions below those that you may identify such as: ‘xpath //computer/general/mac_address’
  • //* Selects everything
  • //computer/* Selects all the child element nodes of everything that starts with computer
  • @ Select an attribute in an XML structure – for example ‘xpath //computer/general/@’
  • [1] This predicate selects the first item (or whatever number is identified, so xpath
  • //computer[3]/general/mac_address would return with the mac address of the third computer
  • [@PATTERN] Constrains found sets, so ‘xpath //computer/general/[@mac_address]’ identifies all computers with an actual mac_address attribute
  • //[@PATTERN=VALUE] Constrains a found set to all items where the attribute contains the value, so ‘xpath //computer/general/[@mac_address=00]’ identifies all computers with an actual mac_address attribute that has the value of 00
  • //[@*] Selects only items with something in an attribute (non-null), so ‘xpath //computer/general/[@mac_address=@*] (btw, rather than use an =, you can use > or <)
  • | creates compound matches. So ‘xpath //computer/general/mac_address | //computer/general/name’ would grab the mac_address and name of every computer
  • [last()] Identifies the last item, so ‘xpath //computer[last()]/general/mac_address’ would return the last computer’s mac address
  • [last()-2] placing a negative number after the parenthesis identifies descending orders from the end of a found set – for example, //computer[last()-2] Selects the second to last computer

Overall, as you can see xpath really makes traversing XML structures simple. Other tools and languages have their own ways, but most are similar in syntax.

November 15th, 2016

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

Tags: , , , , ,

I thought there might be an easier way to do this. So there’s this binary called serverrails that I assumed would install rails – no wait, actually it’s a ruby script that tells me to ‘gem install rails’ – which fails:

cat `which serverrails`
# Stub rails command to load rails from Gems or print an error if not installed.
require 'rubygems'

version = ">= 0"
if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
version = $1

gem 'railties', version or raise
rescue Exception
puts 'Rails is not currently installed on this system. To get the latest version, simply type:'
puts ' $ sudo gem install rails'
puts 'You can then rerun your "rails" command.'
exit 0

load Gem.bin_path('railties', 'rails', version)

Given that doesn’t work, we can just do this the old fashioned way… First let’s update rails to 2.2 or 2.2.4 using rvm, so grab the latest rvm and install it into /usr/local/rvm:

sudo curl -sSL | bash -s stable --ruby

Then fire it up:

sudo source /etc/profile.d/

Then install the latest ruby:

sudo rvm install 2.2

Set it as default:

sudo rvm use 2.2 –default

Then run your gem install:

gem install rails


November 14th, 2016

Posted In: Mac OS X, Mac OS X Server

Tags: , , , , , ,

Servers can have problems. When they have problems, you need to grab logs and stuff. Ever wonder what Apple developers think is important, when it comes to logs and stuff? Try serverdiagnose!


Then hit the Enter (return) key. Then it collects some logs into a tgz. Why a tgz? No clue. But it ends up in /tmp. Notice the name as ServerLogs- followed by the hostname, then a date stamp (yearmonthday) and an underscore followed by a timestamp. Inside the tgz is /Library/Logs, /Library/Server, /tmp/dsdiagnose (a dump of OD debug logs), serverlogs_S3vKsy (configuration statuses), a couple of things from /var/db (the most important of which is PreviousSystemLogs), and /var/log.

November 9th, 2016

Posted In: Mac OS X Server

Tags: , , , , ,

Recently, I got a strange message when trying to run a command:

You have exceeded the maximum number of shell sessions.

I’d seen a series of commands but never really needed to use them, so I ran:


And viola, life was good. My command run. Of course, the next time I went to close the terminal correctly using the exit command. Upon doing so, I noticed:

Saving session…
…copying shared history…
…saving history…truncating history files…

[Process completed]


So, I opened a new shell and ran:


And go the same result. Same with:



November 8th, 2016

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

Tags: , , , ,

Server comes with a command called RoomsAdminTool located at /Applications/ This tool can list available rooms using a -l flag:

RoomsAdminTool -l

You can also create new rooms, using the following format, where krypted is the name of the room, the persistent option means the room is, er, persistent. The description option indicates a description used for the room.

RoomsAdminTool -n krypted -c persistent yes description "This room is for friends of krypted only”

To then delete the room, use the -d option:

RoomsAdminTool -n krypted -d

Add the -v to do it all verbosely. There are lots of other options as well, as follows (from the man page):

Valid Configuration Keys and Values:

descriptionstringA short description for the room
passwordstringDefine a password for room entry. An empty string implies no password required.
membersOnlyyes | noOnly room members are allowed to enter the room.
subjectLockedyes | noAre non-moderators and non-admins prevented from setting the room subject
logFormatDisabled | Text | XHTMLDisable room logging, or enable it using Text or XHTML.
maxUsersinteger; 0 for unlimitedSet the maximum allowed occupants for the room.
moderatedyes | no Make the room "moderated".
nonAnonymousyes | noIf "yes", only moderators/owners can discover occupants' real JIDs.
persistentyes | noPersistent rooms stay open until they are explicitly destroyed and their configuration survives service restarts, unlike non-persistent rooms.
privateMessagesAllowedyes | no Whether or not occupants can exchange private messages within the room.
roomPublicyes | no Defines whether the room be discovered by anyone
subjectstringSet a room subject/topic
usersCanInviteyes | no Defines whether occupants can invite other users to enter the room
addOwnervalid JabberIDMake the specified user a room owner (ex.: Rooms can have multiple owners.
removeOwnervalid JabberIDRemove the specified user from the room owner list
addAdminvalid JabberIDMake the specified user a room admin
removeAdminvalid JabberIDRemove the specified user from the room admin list
addMembervalid JabberIDMake the specified user a room member
removeMembervalid JabberIDRemove the specified user from the room member list
addOutcastvalid JabberIDMake the specified user a room outcast (banned from public rooms)
removeOutcastvalid JabberIDRemove the specified user from the room outcast list

Ultimately, if you’d like to do Student Information System (SIS) integration, or wait for an AD/OD group and then programmatically generate rooms, this is how you’d do it.

November 7th, 2016

Posted In: Mac OS X Server

Tags: , , , , ,

My latest Huffington Post article is up at and starts a little like this:

Building and growing an organization is fun! Doing so certainly comes with a unique set of challenges, but for the most part they’re interesting and morale is high, which makes the job all kinds of interesting. Managing an organization that is static or shrinking can totally suck if you don’t do it right.


November 5th, 2016

Posted In: Business

Tags: , , , ,

My first piece on is up at and deals with Social Networks that you might not consider social networks. I should probably do a follow-up on fair play on them… Either way, hope you enjoy.


November 2nd, 2016

Posted In: Articles and Books, Business

Tags: , ,

25 minutes about TV
13 and 14 inch pros, 14% thinner and comes in at 4 pounds – that’s extreme! Also 12% thinner than a MacBook Air, and 13% less volume
67% Brighter
25% more colors
Core i7, Quad-core 2133MHz
3.1GB/s storage, up to 2TB, 50% faster storage
New thinner thermal architecture, quite
New Speakers, 2x dynamic range audio
130% 3d graphics
60% Gaming
57% Video Editor
Intel Iris Graphics
4 Thunderbolt 3 ports
100Gbps, all those ports can be USB, thunderbolt, etc – AND OMG a headphone jack

Phil didn’t iron his shirt
Function keys are now different
Force Touch Trackpad
2x larger
Butterfly switch mechanism, responsive and “a greater sense of keyboard travel”
Above the keyboard, we get no function keys, but instead gesture-driven responsive Touch Bar, that’s “application specific”
No escape key (it’s on the app bar)
Touch ID – Apple T1 Chip brings Secure Enclave to Mac
Dedicated Siri key, shown by HAIR FORCE ONE
Formatting controls for text
Predictive text and emoji on that bar, not sure if there’s one for Courage
The TV app
Fast user switching based on touch
“Fantastic finger work, Phil”
Touch Bar support on Terminal
Just mentioning Video editing again, showing FCP enhancements with touchID. Nice.
Creatives should love what was being demo’d

So as sysadmins:
Will the same policies available around TouchID via MDM be available for the Mac now?
The T1 is another step towards an iOS-centric OS. Secure Enclave means real crypto the way iOS does it.
Signed boot means you can now lock a device to IPSW-based images and use SIP to block ANY changes to /System.
Can you manage the Control Strip with an MDM policy
Expect toggling users on iPads with touch, eventually
IT Depts are going to have to stock so very much adapters, offsetting the smaller/lighter computer

October 27th, 2016

Posted In: Mac OS X

Stoked that we got to interview Michael Lynn (@mikeymikey) for the MacAdmins podcast. It turned out to be a great episode on the future of Mac management and MDM. I’m glad we were able to have him join in! Pepijn and Marcus did a great job as well, so all round, a great episode. Hope you enjoy!

Or find it on the Podcast site at

October 24th, 2016

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

Tags: , , , , , ,

Automating OS installations is going to eventually be about as easy on macOS as it is in iOS (er, if you have MDM that is). But in the meantime, it’s getting a bit more challenging. The obvious way Apple would prefer this to happen these days is via the startosinstall command that first shipped with El Capitan and with brtool getting moved around all the time, and becoming less of a thing, there’s one quick and easy thing you can do:

sudo "/Applications/Install macOS" --applicationpath "/Applications/Install macOS" --agreetolicense --nointeraction --volume /Volumes/Macintosh\ HD

In the above command, we’ve dropped “Install macOS” on a machine. While you’d guess that it would find the application path based on its own surname, we went ahead and supplied it as that seems to basically be a thing. Basically, –agreetolicense keeps us from having to run some expect scripts to accept a license agreement, –nointeraction suppresses as many of the screens as possible, and –volume allows us to install to any volume we’d like. This isn’t fully automated, but I have been able to layer in some more logic to quit apps before the script fires and then expect out other items from the script to automate a restart, watching for osinstallersetupd as a key.

This is all a bit bulkier than just using something like createOSXinstallPkg but it’s important to mention that there are a number of system components that are allowed for in SIP that use osinstallersetupd and so this blessed mechanism is likely the future until you can trigger an OS upgrade (and update I suppose) using an MDM command.

October 23rd, 2016

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

Tags: , , , , , , ,

« Previous PageNext Page »