New Folder in List View

I often use List View in the Finder for the directory where I organize all my packages.  There doesn’t seem to be any way to create a folder within the highlighted folder below.Screen Shot 2018-03-23 at 4.48.33 PM.png In this post I will show how we can create that option.

Continue reading


Automator application to run script as root

I was recently asked to create a shortcut on our users’ Desktops to kick off the High Sierra install. We are caching the installer through our management system. In the past I have created a shortcut to the installer on their Desktop, but that required them to click through the many continue buttons. This method will use the startosinstall script from Slack member @bp to start the install with minimal user interaction. Continue reading

Using installer choices.xml to modify AnyConnect and McAfee deployments

I have seen several posts on MacAdmin Slack asking for help deploying only components of big packages that the business wants or needs.  There are often several ways of handling this.  For example, from the McAfee ePO console, your admin can give you a Threat Prevention only installer instead of the full Endpoint Security package.  That is great if you can grab that yourself or the admin is helpful and able to get it for you.  This isn’t always the case.  Another route is to install the full package and then uninstall the pieces that you don’t want/need.  The Cisco AnyConnect Secure Mobility client installer does put uninstall scripts for each piece of the package in /opt/cisco/anyconnect/bin.  Both of these options can get your Macs to the end state you want, but they do have potential drawbacks/complications.  Using the Apple provided installer command line tool, we can see what options are available in these packages and then create a file to set which pieces we want.  This does take some work upfront, but we have all the tools we need.   Continue reading

Signing Installer Packages with Automator

Apple packages (.pkgs) are opened by the GUI or the command line installer command. If a package is unsigned and gets a quarantine flag (from being transferred over a network), the GUI Installer will refuse to run it.Screen Shot 2016-11-02 at 3.07.35 PM.png We can get around that with a right-click -> Open, but we shouldn’t be training computer users to ignore security warnings like this.

Screen Shot 2016-11-04 at 4.49.33 PM.png
If you are creating your own packages, and users or techs may run them manually, then you really should be signing them. Even if you are deploying them in a way that a person won’t see a warning, signing packages can be very easy and provide a check that nothing changed since you created it. See below the break for how to easily automate signing packages. Continue reading

Mounting File Shares Based on AD Group Membership using Enterprise Connect

[edit] Apple changed something in macOS 10.13 High Sierra. The mount_share() function in the below python needs to be changed to set the open_options and mount_options to ‘None’. This can be done like

def mount_share(share_path):
    # Mounts a share at /Volumes, returns the mount point or raises an error
    sh_url = CoreFoundation.CFURLCreateWithString(None, share_path, None)
    # Set UI to reduced interaction
    #open_options  = {NetFS.kNAUIOptionKey: NetFS.kNAUIOptionNoUI}
    # Allow mounting sub-directories of root shares
    #mount_options = {NetFS.kNetFSAllowSubMountsKey: True}
    # Mount!
    result, output = NetFS.NetFSMountURLSync(sh_url, None, None, None, None, None, None)
    # Check if it worked
    if result != 0:
         raise Exception('Error mounting url "%s": %s' % (share_path, output))
    # Return the mountpath
    return str(output[0])


In a previous post, I discussed using ldapsearch to look up user data from AD.  In this post we will use the user’s memberOf attribute to mount the appropriate file share.

Some background on my use case for this.  The company I work for has ~15,000 Windows computers in use bound to AD.  When a user logs in, a GPO runs a batch file hosted on the domain controller’s file share.  The batch file is basically a large case statement

if in group A; then
    mount shares X and Y
if in group B; then
    mount share Z

I wanted to provide our Mac users with a similar experience.  Read how below the break. Continue reading

Using ldapsearch to get AD data

It has been common for Macs to be bound to Active Directory for a variety of reasons.  Recently, the trend has been to move away from binding due to password/lock out issues, the rise of cloud based services, and SSO options that are more comprehensive of the services users need.

With the move away from binding, one thing we lose is the ability to look up user and group data with dscl. Here is a decent primer on dscl: (just replace every instance of netinfo with dslocal in your mind).

With this move we need another tool to query for information and ldapsearch can do this for us.  There are a lot of ways to use ldapsearch depending on your end goal.  This post will discuss getting user data out of an Active Directory server.  In a future post I hope to explain how I am using this to mount the appropriate file shares for users based on their group membership. Continue reading

Update to network GeekTool script

I have been seeing a lot of noise in my logs about IO80211ScanManager scanning for Wi-Fi networks constantly.  I finally noticed that it was triggered by system_profiler and realized that I was using system_profiler to find my current Wi-Fi network and what channel I was connected to. See the original here:

So I changed how I find that data in my GeekTool script.  I also took the opportunity to simplify the whole thing a bit more.  Here is the new version:

#! /bin/bash
services=$(networksetup -listallnetworkservices)
while read service; do
	ip=$(networksetup -getinfo "$service" | grep "IP address" | grep -v "IPv6" | awk '{print $3}')
	if [ "$ip" != "" ]; then
		echo "$service : $ip"
		if [ "$service" == "Wi-Fi" ]; then
			NetName=$(/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | grep SSID | grep -v BSSID | cut -d":" -f2 | tr -d '[[:space:]]')
			Channel=$(/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | grep channel | cut -d":" -f2 | tr -d '[[:space:]]')
			echo "$NetName / $Channel"
done <<<"$services"

if [ $connection = false ]; then
	echo "No Connected Services"
	extIP=$(curl -s | sed 's/[a-zA-Z<>/ :]//g')
	if [ "$extIP" != "" ]; then
		echo "External IP: $extIP"
		echo "No External Connection"

Instead of system_profiler the airport command to get the network name and channel.  This stopped the all the message in my logs. I also moved the name and channel logic into the main while read block. This prevents the name and channel from getting separated from the Wi-Fi network IP.