Brace yourself, ’cause I’m a tool (or don’t brace yourself if you’ve read much of my writing or met me since you already knew this to be the case). Classic cedge-fail moment that I just had to share. What do you do when you have a variable before a string of text but cannot have any spaces? You brace your variable. Basically, place the $ followed by the variable that is wrapped in the braces. For example, if I was going to put cedge as the content of a variable and then write a file called cedge.plist from the contents then I would use the following.
user=cedge touch “${user}.plist”
Big script, took 10 minutes to figure out I had forgotten to brace the variable.

I see a numer of environments that are running routine defragmentation scripts on Xsan volumes. I do not agree with this practice, but given certain edge cases I have watched it happen. When defragmenting a volume, there is no reason to do so to the entire volume. Especially if much of the content is static and not changing very often. And if specific files doesn’t have a lot of extents then they are easily skipped. Let’s look at a couple of quick ways to narrow down your defrag using snfsdefrag. The first is by specifying the path. In this case you would specify a -r option and follow that with the path starting path you want to recursively seek fragmented files. The second is to limit the number of extents in the file. To combine these, let’s assume that we are looking to defragment a folder called Seldon on an Xsan volume called Harry. snfsdefrag -r -m 25 /Volumes/Harry/Seldon You should also build logic into scripts if you are automating the events. For example, you could also use the -c option to just look at how many extents there are and perform the actual defragmentation as part of an if/then only in the event that there are more than a specified threshold. Another example is to check that there isn’t an existing process running in snfsdefrag. Also, if there is then don’t fire up yet another instance:
currentPID=$(ps -ewo pid,user,command | grep snfsdefrag | grep -v grep | cut -d ” ” -f 1) echo The current snfsdefrag PID is ${currentPID} so we are aborting the process. > $logfile
If you insist on automating the defragmentation of an Xsan volume, then there’s lots of other little sanity checks that you can do as well. Oh, you’re backing up, right?

Since I already started down this path, we can also push out information for a Windows box therefore programatically allowing you to push updates to two programs and be able to manage all your boxen.  You would push something along the following (creating a file that matches your naming convention followed by .rdp):
connect to console:i:0 bitmapcachepersistenable:i:1 redirectdrives:i:0 disable wallpaper:i:1 disable full window drag:i:1 disable menu anims:i:1 disable themes:i:0 audiomode:i:0 desktopwidth:i:1024 desktopheight:i:768 session bpp:i:16 cord save password:i:0 startdisplay:i:0 cord fullscreen:i:0 cord row index:i:2 full address:s:10.10.10.10 username:s:charles domain:s: cord label:s:charles
So programatically you can change any of the settings by replacing it with a variable.  Therefore, in a script if we just wanted to push a new address and user name then you could simply echo the data into a file as follows, which would use the $1 to $4 positions (thus enabling you to send the data from another applications API into CoRD):
#!/bin/bash echo "connect to console:i:0 bitmapcachepersistenable:i:1 redirectdrives:i:0 disable wallpaper:i:1 disable full window drag:i:1 disable menu anims:i:1 disable themes:i:0 audiomode:i:0 desktopwidth:i:1024 desktopheight:i:768 session bpp:i:16 cord save password:i:0 startdisplay:i:0 cord fullscreen:i:0 cord row index:i:2 full address:s:$1 username:s:$2 domain:s: cord label:s:$3"> /Users/cedge/Library/Application Support/CoRD/Servers/$4
This could be pretty handy if, let's say, you're using the EC2 scripts from earlier to derive a username and password from Amazon and then pushing them into CoRD by calling this script.  For example, if the script is called CoRDSetup.sh then you would run:
./CoRDSetup.sh address.domain.com username machinelabel filename
I'm sure there are way better ways to go about this, but it's a quick and easy proof of concept that gets the job done.  Like with the ARD article, there are again no passwords being sent to CoRD.

I’ve had a few instances where there was no way to setup round robin DNS or a load balancer and we were looking to alternate between a bunch of software update servers.  In order to do so, I’ve written a quick shell script to do so.  Here it is, in pieces, so it makes sense. The following is a quick script to pull a URL from a random list of servers:
#!/bin/bash Sus=”http://swupd.krypted.com:8088 http://sus.krypted.com:8088 http://sus1.krypted.com:8088 http://sus2.krypted.com:8088 http://sus3.krypted.com:8088 http://sus4.krypted.com:8088 http://sus5.krypted.com:8088 http://sus6.krypted.com:8088 http://sus7.krypted.com:8088 http://sus8.krypted.com:8088 http://sus9.krypted.com:8088 http://sus10.krypted.com:8088″ sus=($Sus) num_sus=${#sus[*]} echo -n ${sus[$((RANDOM%num_sus))]} exit 0
This script would simply write to the screen one of the software update servers that we’ve loaded up into an array called sus, chosen using the $RANDOM function.  You can replace the servers in this array with your own and it will simply write to the screen which server it has chosen.  Now to have it actually set the server, replace the line that begins with echo -n with the following line:
defaults write /Library/Preferences/com.apple.SoftwareUpdate CatalogURL ${sus[$((RANDOM%num_sus))]}
For deployment we’ve handled this two different ways.  The first is to have this script run at startup as a login hook (it’s really quick since it doesn’t do much) and let the OS run software updates based on whatever schedule you’ve employed.  The second is to set software updates to only ever run manually and then add a line at the end of the script to run them, which allows you to schedule the task using launchd or run it manually over ARD.  To set the software udpates to run manually, run this command on the target system once (it will persist):
softwareupdate –schedule off
Now, after the script chooses a random software update server, tell it to install all available software updates from that server each time it’s run by adding the following to the end of the script:
softwareupdate -i -a
There is a lot more logic that can be built into it, but this is the basics of assigning a random software update server using a shell script.

When packaging it is worth note that Apple reserves some positional paremeters for your scripts. These are defined at http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/SoftwareDistribution/Install_Operations/Install_Operations.html#//apple_ref/doc/uid/10000145i-CH14-SW1 They include:
  • $1: Path to the package
  • $2: Path to the destination.
  • $3: Installation volume.
  • $4: Root directory