Not much, what’s new with you?

Update: As expected the `OUIWhatsNewLastShowLink` key is being incremented to display new features on subsequent releases. The profiles below will contain the latest values for the currently released versions.

Profiles for Office 2016 version 15.31

Office 2016 offers to show users “What’s New” on first launch.  Tim Sutton has a writeup on how to suppress the initial dialogs on his blog.  However, with version 15.14 of the Office apps there’s new “What’s New”s for Outlook and Powerpoint that sets a key not mentioned in the aforementioned post to suppress the new dialog.  This only affects Powerpoint and Outlook for this version.  Word and Excel didn’t present new prompts on launch this time around.

Along with the “What’s New” keys there are some others of interest:

kSubUIAppCompletedFirstRunSetup1507 – boolean – Controls the original “What’s New” dialog and Office 365 activation prompt on first launch

OUIWhatsNewLastShownLink – string – Controls the “What’s New” dialog on first launch for new prompts offered in subsequent version.

FirstRunExperienceCompletedO15 – boolean – Controls offer to import mailbox or setup an email account. (That’s a cap o15, not zero15)

SendAllTelemetryEnabledboolean – Control the offer to send crash reports to Microsoft

ONWhatsNewShownItemIds – array – Specific to OneNote this value is an array of integers that appears to increment haphazardly.  For just OneNote, this replaces the OUIWhatsNewLastShownLink value.

OUIWhatsNewLastShownLink values

Profiles
Below are profiles that will suppress the “What’s New” and disable crash reports prompts. These examples are set to “Force” the setting as attempts using Set-Once with a timestamp didn’t seem to be effective.

Outlook – suppress “What’s New” only (see below for suppressing Inbox migration)
Outlook – suppress “What’s New” and mailbox setup*

Powerpoint

OneNote

Word

Excel

*There is also a key for Outlook that will suppress the dialog to offer to migrate or setup an email account.  That key is a boolean FirstRunExperienceCompletedO15.  That’s a captial o, not a zero at the end of the key.

 FirstRunExperienceCompletedO15 suppresses this

To extract the values of the OUIWhatsNewLastShownLink I have a script that I run after installing and running each new application.  That script is at OUIWhatsNewLastShownLink Script

Tagged ,

Mac Admin QuickLook Tools

Quicklook has been around for a while and I harness its abilities to help me with my Mac admin life.  Apple advertised it for PDFs, images, and text files, however we admins can partake in the marketing highlight as well.

Below are a few of my favorite QuickLook plugins that I’ve been using for years.  Thankfully they still function.  Some have stopped development but are still available and going strong 7 OS revisions later.

QLStephen – Nothing fancy.  But it does let you view plain text files that don’t have a file extension. It is useful for reading files like README, INSTALL, CHANGELOG, Makefile, etc.

Scriptql – shows AppleScript .script files.  Getting rarer but good to have in a pinch.

QLColorCode – syntax highlighting of code and plist files.  Very handy for peeking in on .plists as the syntax is color coded.

syntax highlight

Much better

Screen Shot 2015-09-14 at 10.47.28 PM

 

Suspicious Package – My favorite.  It opens up .pkg and .mpkg installers to show the payload, scripts and other meta data about the installer.  It’s saved me so much time being able to peek in on an installer without having to deep dive into it.  I highly recommend it for anyone messing with .pkgs.

Suspicious Package quicklook Screen Shot 2015-09-14 at 10.53.21 PM

Please share your favorites in the comments.

Tagged , ,

Help them help you

I support computers AND users. I’m sure you do, too. My users aren’t expected to know their IP address or how to find it. Occasionally I get in a situation where I can’t pre-fetch a computer name for a user I’m about to call. Once I get the user on the horn I’ll need to have them find that IP and give it to me so I can assist remotely. To make the discovery easier I wrote a quick little Applescript app they can run that outputs the computer’s hostname and current active IP address. It offers to put the name or IP address in their clipboard for easier transfer and avoid typos via IM or email.

Below is the code and output:

Computer Name display

Tagged , ,

Netboot compatibility chart for Thunderbolt adapters and docks – community feedback requested

Since Apple’s laptops have gotten thinner there’s less room for IT-important things like Ethernet ports.  Many of us use a network based imaging process to get machines ready for our respective environments.  The lack of a built-in Ethernet port forces us to use Ethernet adapters whether it be USB2.0, USB3.0, Thunderbolt, or Thunderbolt Docks.  Unfortunately the vendors that make these devices don’t seem to worry about the Netbootability of their adapters or docks.  That functionality is a big unknown.  At $2-300/dock guessing wrong isn’t cheap.  Some work if you hold down the “n” or “Option” key on boot but don’t provide Netboot options when trying to set it via the Startup Disk Preference Pane or using the ‘bless’ command from the command line and vice versa.  In my environment it is important to be able to send a command remotely to have the computer Netboot.  Physically holding a key is as good as not having it at all.

I’m sending a call out to all Mac admins willing and able to report back what has and has not worked for you with the adapters you’ve tried.  I’ve started a publicly accessible spreadsheet at Google Sheets trying to detail all the pertinent information.  I’m sure there are others out there that have tried and tested other adapters and docks with varied success.  All could benefit from this gathered information so please contribute if you can.

To supply feedback on different adapters and docks please do the following.  The Netboot columns require specific tests be run as the method matters:

  1. “Netboot ‘n’ on boot” : Hold the ‘n’ key down when powering on the computer.
    Success = booting to the NBI.
  2. “Netboot Boot Picker (option key) : Hold the ‘option’ key down when powering on the computer.
    Success = if you see NBI(s) to pick from the boot picker interface
  3. “Netboot ‘bless’ command” : With the computer booted to the internal drive issue the command ‘sudo bless --netboot --server bsdp://255.255.255.255‘ and reboot.
    Success = booting to the NBI
  4. “Netboot Startup Disk” : Boot up the computer to the internal disk and log in.  Open the Startup Disk System Preference.
    Success = if you see NBI(s) to pick as the startup disk

The other columns like Vendor ID, Product ID, etc., can be found by running ‘system_profiler SPUSBDataType‘ or ‘system_profiler SPThunderboltDataType‘ depending on what type of adapter you’re using.

Thanks, and go team!

Tagged , ,

Installing VMWare Tools on a Netboot NBI

Netboot is great.  VMWare Fusion is great. Yosemite is….Netboot and VMWare are great. I use VMs to test things on our builds at work.  To get those VMs setup I use our imaging process that utilizes Netboot.  However, I discovered that, new with Yosemite, when the VM Netbooted to our Yosemite NBI I wasn’t able to login to OS X. After typing in the username and password the login attempt would just hang with the spinning gear turned beachball.  No bueno. Turns out all it requires is getting the VMWare Tools installed on the NBI.  No problem right? But VMWare’s installer (read: .app) doesn’t allow installing on a non-boot volume.  Crap.  This wouldn’t be a very interesting post if we stopped here so…

TL;DR: you need to mount the NBI and install the tools via the CLI ‘installer’ command.

First, make sure that your existing NBI is read/write when mounted.  In my case the NBI is actually a .sparseimage but renamed to .dmg for Netboot use.  When mounting the image named .dmg it mounts as read-only.  Renaming the .dmg to .sparseimage mounts the volume as read-write. YMMV. There are ways to convert disk images to read-write. I’ll leave that discovery up to you if your environment requires it.

VMWare Tools acquisition/installation:

There are a couple ways to get the tools.  I prefer to pull the tools from the VMWare Fusion.app bundle itself to guarantee that the version of VMWare Fusion you’re running is compatible with the tools. If you want an automated way using AutoPkg to get the latest tools check out Rich Trouton’s post at Der Flounder.  You can also download the tools if you know what version you need at VMWare’s repository.

Locally, the tools are located in the application bundle found at /Applications/VMware\ Fusion.app/Contents/Library/isoimages/darwin.iso

iso-location

Mounting that image results in the installer and uninstaller.

mounted-iso

However attempting to use the .app installer will fail as it won’t let you target the install on a non-boot drive.  Since it’s a .app “installer” there must be a .pkg buried in the bundle. To get the actual installer .pkg right click on “Install VMWare Tools.app” and choose “Show Package Contents”.  Navigate to the /Volumes/VMware\ Tools/Install\ VMware\ Tools.app/Contents/Resources/ directory.  There you’ll find “VMWare Tools.pkg”. Jackpot.

installer-location

Copy the “VMWare Tools.pkg” to the computer where the NBI is mounted and run ‘installer’ pointing the target at the mounted Netboot NBI.

 sudo installer -pkg /Volumes/VMware\ Tools/Install\ VMware\ Tools.app/Contents/Resources/VMware\ Tools.pkg -target /Volumes/Yosemite\ NetBoot -verbose

That will install on the mounted volume.  Once complete, unmount the NBI, rename it if necessary, and you should now be able to log into a Yosemite NBI when Netbooted in VMWare Fusion.

Tagged ,

Using pkgutil To Adjust Flat Packages

“I love it when companies break away from the standard pkg practices.”

– No one ever

When you run into an installer that is doing something you don’t expect or recommend we get to put on our Mac admin spelunking hat to dive into the depths of the installer to see what’s going on.  There are some handy tools that make this easier already bundled in the OS.  Those are: pkgutil and installer.  There are also good 3rd party apps like Pacifist and Suspicious Package that I use for examining installers as well.  For this exercise I didn’t need those.

I ran into an issue with the Fiery E-22C driver installer from EFI launching an app mid-install to offer to setup printers.

Not Helpful

That’s great for home users with a Fiery front end (who doesn’t have a Fiery at home?) but not for deploying in the enterprise.  The only way to get the drivers to install at this point was to click the link in the bottom left of the app window.  Not ideal. I tried many ways to bypass the “wizard” app as the installer existed but even when attempting a CLI install it would launch the app when a user was logged and the install would totally fail if no user was logged in.

One thing going for us at this point is the pkg is a flat package. Running the following will extract the pkg to better examine it:

pkgutil --expand ~/Desktop/Fiery\ Printer\ Driver.pkg ~/Desktop/fieryprinterdrivers

Navigating to ~/Desktop/fieryprinterdrivers shows us the expanded package contents:

Expanded Package

 Right click on the “FieryPrinterDriverInstaller.pkg” and choose “Show Package Contents”:

Show package contents

After digging around the piece that needed adjustments was the postinstall.  There was a system version check in there to launch the “wizard” if the OS was 10.5 or older.  If 10.5 or older it would just install the drivers.  That’s what I wanted on my new shiny OS!

#Pkg installs driver and exits in 10.5 since no Wizard is supported below 10.6
if [ "$MAJOR" = "10" ] && [ "$MINOR" = "5" ]
then
 logger "Postinstall Script: Checking for previous driver and printers with FSU and performing system cleanup"
 /bin/sh /tmp/efi_wiz_fsu_delete && logger "Postinstall Script: FSU done"
 sudo rm -f /tmp/efi_wiz_fsu_delete
 logger "Postinstall Script: Installing driver only for 10.5" && sudo installer -pkg /tmp/Fiery\ Printer\ Driver\ Installer.app/Contents/Resources/User\ Software/OSX/Printer\ Driver/OSX\ installer.pkg -target / && exit 0
fi

Further down if the OS was > 10.5 it would launch the “wizard” which is what I didn’t want.  To fix this install postinstall script all I needed to do was remove the OS Minor version check to make it just install the drivers if the OS Major version is 10.  I can handle deploying the drivers to the appropriate OS so I’m not worried about using their logic.

From:
if [ "$MAJOR" = "10" ] && [ "$MINOR" = "5" ]
to 
if [ "$MAJOR" = "10" ]

Once the postflight file is adjusted we can flatten the package back up again by running:

pkgutil --flatten ~/Desktop/fieryprinterdrivers/ ~/Desktop/Fiery\ Printers\ Driver\ Fixed.pkg

 And now I have a new package “Fiery Printers Driver Fixed.pkg” that’s deployable, won’t launch the wizard, and will install the drivers.

fixed pkg is a pkg

Tagged ,

createmobileaccount workaround for 10.10.3

UPDATE: As of Mac OS X 10.10.4 this issue has been addressed by Apple. The following still applies to 10.10.3 installs. 

Since 10.10.3 was released on April 8, 2015, the Mac admin community has had the privilege of discovering what’s broken with this new OS. We knew about the rootPipe fix but not it’s unintended collateral damage. One piece that was discovered comprimised is the tool “createmobileaccount” found in /System/Library/CoreServices/ManagedClient.app/Contents/Resources/createmobileaccount. This tool can be used to pre-create a home folder and add the user to the local directory service node without having a user log in. It can also dynamically verify that the account attempting to be made actually exists in the directory service prior to creating the account. That can be handy for restoring user data, creating a directory based account prior to sending off-site, or giving a user admin rights prior to deployment. As of 10.10.3 and it’s rootPipe fix, that tool is broken. BUT, there is a workaround.

The workaround to still use createmobileaccount is to do the following*:

  1. Copy the user template to create the home folder: cp -R /System/Library/User\ Template/English.lproj /Users/${newUser}
  2. Change rights on the folder for the new user: chown -R ${newUser}:staff /Users/${newUser}
  3. Run createmobileaccount: /System/Library/CoreServices/ManagedClient.app/Contents/Resources/createmobileaccount -n ${newUser}

Take note if you implement this workaround in your workflow that the home folder is being created before createmobileaccount is run.  If createmobileaccount fails, the home folder you created will still exists and you may want to clean that up depending on the environment.

*thanks to mm2270’s post on JAMFNation.

Tagged , ,

10.10 – Boot Hangs after Deleting /var/folders Directory

UPDATE 4-13-2015: Apple replied back to my bug report stating it behaves as expected and deleting the /var/folders directory is not supported. So….don’t delete /var/folders.

Previously, in OS 10.9 it has been documented that removing the data in /private/var/folders is a good troubleshooting step for various reasons. There is a good writeup at blog.magnusviri.com describing what /var/folders contains and what issues arise from its bloat. Up thru OS 10.9.5 it hasn’t been an issue deleting contents or the parent directory.

The article above mentions deleting just the contents of /var/folders, which is still good advice. However a haphazard deletion of the /var/folders directory itself will cause issues in 10.10. If you delete the parent folder /var/folders and reboot, the computer will boot to about 50% and hang indefinitely. It will look a lot like the “loginLockout” behavior except the progress bar is at around 50% instead of 33% and the cursor is on screen. Don’t be fooled as I was. This is not loginLockout.

Examining the boot drive while booted from another source showed many errors in system.log when booting about /var/folders/zz not being present. Surprisingly it appears that mkdir is being called but unable to create the directory structure.

.
.
.
Mar 19 09:40:26 macadmins-Mac.local dirhelper[1008]: mkdir(/var/folders/tx): No such file or directory
Mar 19 09:40:26 macadmins-Mac xpcproxy[1007]: libcoreservices: _dirhelper_userdir: 351: stat: /var/folders/tx/56ff45qs2rlc89vggkr8x3yr0000gn/: No such file or directory
Mar 19 09:40:26 macadmins-Mac.local dirhelper[1008]: mkdir(/var/folders/tx): No such file or directory
Mar 19 09:40:26 macadmins-Mac fontworker[1007]: libcoreservices: _dirhelper_userdir: 351: stat: /var/folders/tx/56ff45qs2rlc89vggkr8x3yr0000gn/: No such file or directory
Mar 19 09:40:26 macadmins-Mac fontworker[1007]: libcoreservices: _dirhelper: 454: mkdir: path=/var/folders/tx/56ff45qs2rlc89vggkr8x3yr0000gn/T/ modes[1]=0700: No such file or directory
Mar 19 09:40:26 macadmins-Mac fontworker[1007]: libcoreservices: _dirhelper: 454: mkdir: path=/var/folders/tx/56ff45qs2rlc89vggkr8x3yr0000gn/C/ modes[2]=0700: No such file or directory
Mar 19 09:40:27 macadmins-Mac storeassetd[304]: libcoreservices: _dirhelper: 454: mkdir: path=/var/folders/tx/56ff45qs2rlc89vggkr8x3yr0000gn/T/ modes[1]=0700: No such file or directory
Mar 19 09:40:27 macadmins-Mac fontd[227]: libcoreservices: _dirhelper: 454: mkdir: path=/var/folders/tx/56ff45qs2rlc89vggkr8x3yr0000gn/T/ modes[1]=0700: No such file or directory
Mar 19 09:40:31 macadmins-Mac.local dirhelper[1008]: mkdir(/var/folders/tx): No such file or directory
Mar 19 09:40:31 macadmins-Mac xpcproxy[1011]: libcoreservices: _dirhelper_userdir: 351: stat: /var/folders/tx/56ff45qs2rlc89vggkr8x3yr0000gn/: No such file or directory
Mar 19 09:40:31 macadmins-Mac.local dirhelper[1008]: mkdir(/var/folders/tx): No such file or directory
Mar 19 09:40:31 macadmins-Mac xpcproxy[1012]: libcoreservices: _dirhelper_userdir: 351: stat: /var/folders/tx/56ff45qs2rlc89vggkr8x3yr0000gn/: No such file or directory
Mar 19 09:40:31 macadmins-Mac fontd[227]: libcoreservices: _dirhelper: 454: mkdir: path=/var/folders/tx/56ff45qs2rlc89vggkr8x3yr0000gn/T/ modes[1]=0700: No such file or directory
Mar 19 09:40:31 macadmins-Mac fontd[227]: libcoreservices: _dirhelper: 454: mkdir: path=/var/folders/tx/56ff45qs2rlc89vggkr8x3yr0000gn/T/ modes[1]=0700: No such file or directory
Mar 19 09:40:31 macadmins-Mac loginwindow[64]: libcoreservices: _dirhelper: 454: mkdir: path=/var/folders/tx/56ff45qs2rlc89vggkr8x3yr0000gn/T/ modes[1]=0700: No such file or directory
Mar 19 09:40:31 macadmins-Mac fontd[227]: libcoreservices: _dirhelper: 454: mkdir: path=/var/folders/tx/56ff45qs2rlc89vggkr8x3yr0000gn/T/ modes[1]=0700: No such file or directory
Mar 19 09:40:31 macadmins-Mac.local locationd[241]: Could not write data to disk /var/folders/zz/zyxvpxvq6csfxvn_n00000sm00006d/C/cache.plist
Mar 19 09:40:45 localhost dirhelper[61]: /var/folders/: invalid ownership
.
.
.

To fix the issue I had to maually recreate the directories folders/zz in /var to allow the system to boot once again.

I’ve file a bug report and posted on OpenRadar.

Tagged , ,

Jettisoning the Boot Cache – is it safe?

UPDATE – Apple released OS 10.10.3 on April 8, 2015 that addresses the boot lockout issue described below. Information on the release can be found at Apple’s support site.

You may have heard of this little problem with Yosemite some are giving the moniker “Login Lockout”. The problem, as described at AFP548.com, is that the computer will boot about 1/3 of the way and halt. It happens randomly, but more often after a hard reboot.

A community fix has been gaining traction at JAMFNation that suggests editing /etc/rc.server to run /usr/sbin/BootCacheControl jettison that seems to work. But is it safe to jettison the boot cache every boot?

In short, probably.

My friend @mikeymikey on Twitter spelunked into the issue at depths I’m not comfortable with and discovered, among other things, that the BootCache.kext has code that calls for a jettison on multiple occasions. The code is open sourced and available to browse at Apple’s open source site. Searching for “jettison” in the code will reveal some nice comments about different scenarios that would invalidate the cache. You can also see the command’s semi-hidden documentation by running /usr/sbin/BootCacheControl without an option. It will display the following, jettison being one option.


Usage: /usr/sbin/BootCacheControl [-vvv] [-f ] start
           Start recording history and play back .
       /usr/sbin/BootCacheControl [-vvv] [-f ] stop
           Stop recording history and write the playlist to .
       /usr/sbin/BootCacheControl mount
           Notify the boot cache of a new mount.
       /usr/sbin/BootCacheControl [-vvv] jettison
           Jettison the cache.
       /usr/sbin/BootCacheControl statistics
           Print statistics for the currently-active cache.
       /usr/sbin/BootCacheControl tag
           Insert the end-prefetch tag.
       /usr/sbin/BootCacheControl [-vvv] [-t batchnum] -f  merge  [...]
           Merge ... into .
           Playlist files after the first will be offset  batches, if provided
       /usr/sbin/BootCacheControl [-c] -f  print
           Print the contents of .
       /usr/sbin/BootCacheControl -f  unprint
           Read a playlist from standard input and write to .
       /usr/sbin/BootCacheControl -f  generate []
           Generate a playlist from standard input data for  and write to .
       /usr/sbin/BootCacheControl -f  truncate 
           Truncate  to  entries.
       /usr/sbin/BootCacheControl -f  generalize
           Modify  to apply to any root volume.

The result of running this on every boot just means that the computer may boot a smidge slower as the cache is not there to reference.

There are rumors of a fix coming from Apple but it’s unclear if that will be included in 10.10.3 or not. Adding the jettison to rc.server appears to be a valid workaround until the official fix is out. This temporary workaround is easily revertible by just removing the rc.server file and rebooting.

Tagged , ,

Custom location detection using CIDR range

Ask the right questions and you’ll get helpful answers.  Ask some code if an IP exists within the CIDR range and the brief answer can be powerful.

Services like munki, reposado, or other internal offering in your company can be replicated out to other locations but if the client settings never change they’ll continue to use the original settings even if the computer is in a different office across the country. That can be expensive in time and bandwidth — if there is inter-office connectivity at all. Every computer on the network gets an IP, and every IP is in a CIDR range. Why not use that information to help.

You can determine where a computer is based on your documented CIDR ranges and checking if the current IP is in one of those ranges. Systematically processing that information can help with the task of re-configuring based on locale. A simple boolean answer can be parsed to mean anything for your environment. It’s what you do with that answer that makes the difference.

First, you need to know what CIDR ranges are active in your company’s network.  Whoever setup the network should be able to provide that information.  Be sure to double check the translation of CIDR to IP ranges. There is a site that can translate CIDR to the IP range. I had a few instances of CIDRs provided were overlapping and caused unexpected results when certain IPs were used.

Next, figure out what information you want returned.  For my implementation I went the simple route and have the script return a single value that signifies which company office the IP is in.  You can have it return as much as you want and make it as complex as you want.

The following perl code returns true if a supplied IP exists in a supplied CIDR range.

#!/usr/bin/perl
use Net::CIDR::Lite;
use Getopt::Std;

#"i"P address and "c"IDR notated range
getopt ('ic');

my $cidr = Net::CIDR::Lite->new;
$cidr->add($opt_c);
print "true\n" if $cidr->find($opt_i);

The following script iterates thru the known company CIDR ranges with the current computer’s IP address and sends those two pieces of information to the perl script until a match is found. When the IP exists inside a site’s CIDR range it will return the value of the site.

#!/bin/bash
# To use this in other scripts reference it by
#   /Library/Management/Scripts/cidr/cidr-check.sh [ -i ip_address ]
#
#   If no IP is provided by the -i argument the current IP on the computer the script is being run on will be used.
# 
#   Site            Return Value
#
#   Des Moines      DSM    
#   New York        NY
#   Chicago         CHI
###############################################################

#Locations of helper scripts
scriptLocation=/Library/Management/Scripts/cidr/
cidrCheckScript=check_IP_and_CIDR.pl

activeiface=`route get google.com | awk '/interface/ {print $2}'`

#Get the current IP address
#Read in the arguments
usage="Usage: cidr-check.sh [-h] [-i ip_address]"
while getopts i:h flag
do case "$flag" in
	i ) ip="$OPTARG";;
	h ) echo $usage
		exit 1;;
    * ) echo $usage
		exit 1;;
esac
done

#Shift out the switches and arguments, leaving the actual
#variables we're operating against
shift $(($OPTIND - 1))

if [ -z $ip ]
then
    ip=`/sbin/ifconfig $activeiface | /usr/bin/awk '/inet / {print $2}'`
fi

#Flag to mark whether the IP has been found
ipFound=n

###############################################################
#           Lists of CIDR range names                         #
###############################################################
dsmCidrRangeNames=(currentCIDR_DSM1 currentCIDR_DSM2)
dsmCidrRangeNames_Site="DSM"
chiCidrRangeNames=(currentCIDR_CHI)
chiCidrRangeNames_Site="CHI"
nycCidrRangeNames=(currentCIDR_NYC)
nycCidrRangeNames_Site="NY"

##Eastern Time CIDR ranges
    #New York
        currentCIDR_NYC=1.2.0.0/18
##Central Time CIDR ranges
    #Chicago
        currentCIDR_CHI=1.3.224.0/20
    #Des Moines
        currentCIDR_DSM1=1.4.0.0/16
        currentCIDR_DSM2=1.5.0.0/16
###############################################################

if [ "$ipFound" = "n" ]
then
	for cidrRange in ${dsmCidrRangeNames[@]}
	do
		if [ "`${scriptLocation}${cidrCheckScript} -i "$ip" -c ${!cidrRange}`" = "true" ]
		then
			returnValue="${dsmCidrRangeNames_Site}"

			#Mark that we fnd the IP address
			ipFound=y

			#Break out of the for loop
			break
		fi
	done
fi

#CHI
if [ "$ipFound" = "n" ]
then
	for cidrRange in ${chiCidrRangeNames[@]}
	do
		if [ "`${scriptLocation}${cidrCheckScript} -i "$ip" -c ${!cidrRange}`" = "true" ]
		then
			returnValue="${chiCidrRangeNames_Site}"

			#Mark that we fnd the IP address
			ipFound=y

			#Break out of the for loop
			break
		fi
	done
fi

#NYC
if [ "$ipFound" = "n" ]
then
	for cidrRange in ${nycCidrRangeNames[@]}
	do
		if [ "`${scriptLocation}${cidrCheckScript} -i "$ip" -c ${!cidrRange}`" = "true" ]
		then
			returnValue="${nycCidrRangeNames_Site}"

			#Mark that we fnd the IP address
			ipFound=y

			#Break out of the for loop
			break
		fi
	done
fi

if [ "$ipFound" = "n" ]
then
	#We didn't find the IP in a CIDR range
	/bin/echo "IP: $ip not within the specified CIDR ranges." 2>&1
	exit -1
fi

/bin/echo "${returnValue}"

exit 0

With that information I now know what location that computer has an IP from. Those two pieces of code can be re-used as a function in any number of ways. One way we use it is to configure munki to point at the local repo for pkgs, icons, and client_resources during its preflight execution on every run. That way regardless of what office the computer is in it won’t cross the WAN to pull a pkg.

#!/bin/bash
# Script to determine local site and change munki urls to local resources
# Uses 'cidr-check.sh' to determine the site based on IP

#Static variables
munkiConfig=/Library/Preferences/ManagedInstalls
cidrCheckScript=/Library/Management/Scripts/cidr/cidr-check.sh
centralMunkiServer=munki.YOUR.DOMAIN.COM
#################

#Check to see if we're running as root
if [ `id -u` != 0 ]; then
	echo $0: "You must have root privileges to run this command!  Exiting."
	exit 1
fi

#Set the variable "localSite" to the returned value from 'cidr-check.sh'
localSite=`"${cidrCheckScript}"`
echo Local site determined to be "${localSite}"

#Determining the local PackageURL to use
case $localSite in

	DSM )	
			localServer=('munki-dsm.YOUR.DOMAIN.COM')
			;;

	NY )	
			localServer=('munki-nyc.YOUR.DOMAIN.COM')
			;;

	CHI )	
			localServer=('munki-chi.YOUR.DOMAIN.COM')
			;;
	#All other locations should default to the central server
	* )		
			localServer=('munki-dsm.YOUR.DOMAIN.COM')
			;;
esac

echo Local server determined to be "${localServer}"

#If we can't talk to the local munki server, use the central server
if ! ping -o -c 5 "${localServer}" > /dev/null 2>&1
then
	localServer="${centralMunkiServer}"
fi

#Write the local munki URLs
defaults write "${munkiConfig}" PackageURL http://"${localServer}"/repo/pkgs
defaults write "${munkiConfig}" IconURL http://"${localServer}"/repo/icons
defaults write "${munkiConfig}" ClientResourceURL http://"${localServer}"/repo/client_resources

#Write the central munki URL for everything else
defaults write "${munkiConfig}" SoftwareRepoURL http://"${centralMunkiServer}"/repo

#echo Converting ManagedInstalls.plist to XML, the original format of the file
plutil -convert xml1 ${munkiConfig}.plist

I’m sure there are multiple ways to handle this type of problem. I’d love to hear how you handle the complexity of roaming computers and keeping configurations local.

Tagged , ,