Send UNIX Command Scripts

from the ARD Webcast

Steve Hayman
Dec 3 2004

Enclosed in this file are the various little scripts I discussed during the ARD webcast in November. Because of the way Send Unix Command works, you pretty much need to cut and paste these scripts into its window (which you can then save as a task) so it seemed like there wasn't much point in making these into separate script files as they really don't stand on their own.

Unless otherwise specified, all these scripts are intended to be run by selecting the user "root" in the Send Unix Command window.

I have used the

Courier font
for the scripts in this file itself.

Using These Scripts

  1. Select one or more computers - or a list of computers - in ARD
  2. Choose the Send UNIX Command icon
  3. Usually you will want to check Display all output and specify the user root
  4. Hit "Send".
  5. Optionally, if you think you might do this one again, choose File > Save Task. This will save the script - AND the associated list of computers.

What I sometimes do is to create a generic list called "Selected Computers", and I set up all my tasks to use that list rather than any specific machines. Then, later, when I want to run the script, I move the computers I'm interested to into that list. ARD remembers the name of the list, not the specific computers in it.

One-Liners

Here are a few simple commands that you may find useful. They're hardly worth saving, you can just retype these as needed.

uptime

Shows how long all the selected computers have been up. Produces only one line of output, so this one looks good in the resulting table without you having to select "Display all output."

date

A nice sanity check to see if any of the clocks on your machines are out of sync. Also produces only one line of output.

periodic weekly

Run, right now, all the system maintenance commands which normally run via cron only at 4:30 on Saturday morning. To see the actual maintenance commands that are going to be executed, look in /etc/periodic/weekly. (You can also do "periodic daily" or "periodic monthly". )

diskutil repairPermissions /

Run Disk Utility's "Repair Permissions" feature on your root disk. This will take a while and produce many lines of output so be sure to check "display all output."

softwareupdate -l

Produce a list of all needed software updates.

dscl . -passwd /Users/admin newpass

Change the password on the local "admin" account.

systemsetup
networksetup

There is a lot you can do with these two tools, more than I can go into here. To see what the options are, use "systemsetup -help" and/or "networksetup -help". You may want to add /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Support to your $PATH variable so you can type these commands directly in Terminal.app to try them out.

More Complex Scripts

cd /Users
for u in *; do
	mkdir $u/NewFolder
	chown $u $u/NewFolder
done

Create a new folder for every user. This loops through every user home folder in /Users (on every computer) and creates a new folder called "NewFolder"; note that this makes the (usually correct) assumption that all user home folders are in /Users, and that the home folder name matches the user name.

networksetup -listallnetworkservices | 
grep -v '\*' |  
while read service; do
	networksetup -setwebproxy "$service" 10.1.2.3 8080
done

This script first uses "networksetup -listallnetworkservices" to produce a list of all network services (Built-in Ethernet, Airport, etc.) and then loops through each one, again using networksetup to set the web proxy for that service to 10.1.2.3, port 8080.

Software Update related scripts

softwareupdate -l

List all needed software updates.

softwareupdate -i someUpdateName

Install one specific update

softwareupdate -i -a

Installs all updates.

softwareupdate -l | grep Sec

List all needed Security updates (i.e., any update that contains the string "Sec")

tail -1 /Library/Logs/Software\ Update.log

Show the last software update installed. We use "tail -1" so there's only one line of output so we can scan the table easily. Of course you might just like to do "cat /Library/Logs/Software\ Update.log" to see all of them, in which case, don't forget to check Display All Output.

softwareupdate -l | grep Sec | awk 'length($1) == 1 {print $2}' | while read update; do 
	softwareupdate -i $update
done

Install all needed security updates. (This pipeline lists all the software updates, find the Security ones, and installs only those.)

if who | grep console; then
	echo Machine is in use
	exit 1
fi
# Set this environment variable 
# to keep the QuickTime dialog from coming up

COMMAND_LINE_INSTALL=1 softwareupdate -i -a

shutdown -r now

Install all needed updates - but first, we check to see if the machine is in use and exit if it is; otherwise, we set the magic COMMAND_LINE_INSTALL variable to keep the QuickTime installer dialogue from coming up, then install all the updates, then reboot.

Installing Packages

installer -pkg /Some/Package.pkg -target /

Install a specific package on the root disk.

cd /Volumes/Somewhere/SharedPackages
for p in *.pkg; do

	if test -d /Library/Receipts/$p; then
		echo Package $p already installed
	else
		installer -pkg $p -target /
	fi
done

Installs all needed packages from a shared folder. Look in a shared folder - in this case, /Volumes/Somewhere/SharedPackages - and for each package we find there, take a look in our receipts folder to see if we have a receipt by the same name (indicating we've already installed that package), and if not, install it.

Pointless ARD Fun

osascript <<EOF
set suList to (do shell script "softwareupdate -l") as string
say suList using "Cellos"
EOF

Get the machines to sing the output of some command - in this case, get them to sing the list of software updates we need. Note usage of osascript in order to execute a bit of Applescript. When you type this one in, make sure that the word "EOF" on the last line appears at the beginning of the line. The shell is taking everything from "<<EOF" to the line beginning with "EOF" and feeding it to "osascript" as its input. This usage of "<<" is called a "here document" in shell programming parlance.

Of course you might also use do shell script "date" to get them to sing something simpler. Or skip the shell entirely, and do

osascript <<EOF
	say "Steve needs a vacation" using "Whisper"
EOF

Fun with the Drive Tray

If you have machines - such as G4 iMacs, or G5 towers - with powered drive trays, then the drutil command will be a great source of amusement if you send commands like these to a lab full of machines.

drutil tray open
sleep 1
drutil tray close

Open the tray on all the computers, wait a second, then close it. Don't forget to sleep between the open and the close, or it won't work very well (the machine will start closing the tray before it's fully open.) Once you've got that working, why not try putting it in a loop?

for i in 1 2 3 4 5; do
	drutil tray open
	sleep 1
	drutil tray close
	sleep 1
done

And if you want to get really fancy, rather than having the machines open and close their drive trays in sync, why not insert some delays into the script so that each machine waits a little bit longer than the previous one before opening its tray, thus making the machines do "The Wave". For a movie of this in action, see this clip

Here's the script. You will need to edit the list of machines in the script (the lines after "order" below) to correspond to the names of your machines, in the order in which you'd like them to open and close the tray. The first two variables control the number of times through the loop, and the delay (in microseconds, so 500000 is half a second) between the first machine and the next.

loops=5
factor=500000


me=`systemsetup -getcomputername | sed -e 's/.*: //'`

# Edit this list to reflect the computer names of the machines you have, in the order you want them to do The Wave.

order=`(cat -n <<EOF
Node01
Node02
Node03
Node04
Node05
EOF

)  | grep "$me" | awk '{print $1}' `


for x in `jot $loops`; do
	perl -e "use Time::HiRes qw(usleep); usleep ($order * $factor);"

	drutil tray open
	sleep 1
	drutil tray close

	# Sleep again until a few seconds have gone by so we can get back in sync.

	# note: 2.5 = number of machines / 2
	# if too small, you get a negative time as a result

	perl -e "use Time::HiRes qw(usleep); usleep( 2.5 * $factor * 2 - ($order * $factor)); "

done