Just where I place my rants and raves...

Friday, January 06, 2006

Automated CD Burning using AutoMount

One recent project for my employer was to create a headless (pc with no keyboard, mouse, or monitor) CD burner that automagically detects an inserted flash card, renames the files, and burns them to a CD along with a Flash Projector application that plays the images on PC's or Mac's.

My solution was to use the AutoFS automounter daemon, and shell scripts. Much of the scripting ideas borrowed heavily from the BashBurn project.

The hardware used was commodity workstations, and a 9-in-one flashcard reader configured as a SCSI device. See the following articles for interesting info:
http://www.grack.com/news/2003/Atech9-in-1CardReader.html
http://www.cs.sfu.ca/~ggbaker/personal/cf-linux

The file test.sh is run by cron every 20 seconds, piping the command through sleep:
* * * * * root sleep 0; /usr/local/copydisk/test.sh && sleep 20; /usr/local/copydisk/test.sh && sleep 40; /usr/local/copydisk/test.sh

Test.sh contents:

#!/bin/bash

if [ -f /usr/local/copydisk/cd.pid ];then
echo "We are running..."
exit
else
echo "Not running...better check the drives..."
/usr/local/copydisk/copydisk.sh

fi


All that does is check for a pid, so we don't get too many running copies of our copying script, copydisk.sh:

#!/bin/bash


touch /usr/local/copydisk/cd.pid

export CONFFILE="/usr/local/copydisk/burnrc"

export ROOTDIR="$(cat ${CONFFILE} | grep -v '^#' | grep ROOTDIR: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]//g")"
export ROOTDIR="${ROOTDIR%*/}"

export CDROM="$(cat ${CONFFILE} | grep -v '^#' | grep CDROM: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]//g")"
export CDMNT="$(cat ${CONFFILE} | grep -v '^#' | grep CDMNT: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]//g")"
export CDWRITER="$(cat ${CONFFILE} | grep -v '^#' | grep CDWRITER: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]//g")"
export SPEED="$(cat ${CONFFILE} | grep -v '^#' | grep SPEED: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]//g")"
export BLANKING="$(cat ${CONFFILE} | grep -v '^#' | grep BLANKING: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]//g")"
export BURNDIR="$(cat ${CONFFILE} | grep -v '^#' | grep BURNDIR: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]//g")"
export WORKDIR="$(cat ${CONFFILE} | grep -v '^#' | grep WORKDIR: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]//g")"
export RUNDIR="$(cat ${CONFFILE} | grep -v '^#' | grep RUNDIR: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]//g")"
export BURNDIR="${BURNDIR%*/}"


# additional information for the CD:
export LABEL="$(cat ${CONFFILE} | grep -v '^#' | grep LABEL: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"
export COPYRIGHT="$(cat ${CONFFILE} | grep -v '^#' | grep COPYRIGHT: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"
export DESCRIPTION="$(cat ${CONFFILE} | grep -v '^#' | grep DESCRIPTION: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"
export AUTHOR="$(cat ${CONFFILE} | grep -v '^#' | grep AUTHOR: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"
export PUBLISHER="$(cat ${CONFFILE} | grep -v '^#' | grep PUBLISHER: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"
export NAMEOFPACKAGE="$(cat ${CONFFILE} | grep -v '^#'| grep NAMEOFPACKAGE: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"
export NUMBEROFCDS="$(cat ${CONFFILE} | grep -v '^#' | grep NUMBEROFCDS: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"
export CURRENTNUMBER="$(cat ${CONFFILE} | grep -v '^#' | grep CURRENTNUMBER: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"

# some advanced options:
export NORMALIZE="$(cat ${CONFFILE} | grep -v '^#' | grep NORMALIZE: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"
export OPT_ONE="$(cat ${CONFFILE} | grep -v '^#' | grep OPT_ONE: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"
export FIFODIR="$(cat ${CONFFILE} | grep -v '^#' | grep FIFODIR: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"
export OVERBURN="$(cat ${CONFFILE} | grep -v '^#' | grep OVERBURN: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"

# voice rendering
export BURNF="$(cat ${CONFFILE} | grep -v '^#' | grep BURNF: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"
export BURNS="$(cat ${CONFFILE} | grep -v '^#' | grep BURNS: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"
export COPYI="$(cat ${CONFFILE} | grep -v '^#' | grep COPYI: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"
export COPYM="$(cat ${CONFFILE} | grep -v '^#' | grep COPYM: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"
export CALLS="$(cat ${CONFFILE} | grep -v '^#' | grep CALLS: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"
export TOOBIG="$(cat ${CONFFILE} | grep -v '^#' | grep TOOBIG: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"
export TMPJPG="$(cat ${CONFFILE} | grep -v '^#' | grep TMPJPG: | cut -d ":" -f 2- | sed -e "s/^[[:blank:]]*//g")"



SDA="/misc/sda"
SDB="/misc/sdb"
SDC="/misc/sdc"
SDD="/misc/sdd"
SDE="/misc/sde"
SDF="/misc/sdf"
SDG="/misc/sdg"
SDH="/misc/sdh"
FIND="/usr/bin/find"
IMAGES="( -iname *.jpg -o -iname *.tif )"
MOVIES="( -iname *.avi -o -iname *.mpg -o -iname *.mpeg -o -iname *.mp3 -o -iname *.wav -o -iname *.mov )"

# Test for files...

# /dev/sda1

# Find all jpg's and tif's
SDAFILES=`$FIND $SDA $IMAGES`

# Set our counter to 0
FCNT=0

# Count the number of images found
for i in $SDAFILES; do
FCNT=`expr $FCNT + 1`
done

# If we have more than one picture, copy them
if [ $FCNT -gt 0 ]; then

# Keep track of what had files on it
touch ${WORKDIR}/mount/sda
echo $COPYI | festival --tts
echo "Copying files from SDA..."


cd ${WORKDIR}/temp
for F in $SDAFILES; do
echo "Copying $F to ${WORKDIR}/temp"
cp $F ./
done

# Find any extra movie files, or audio files
SDAMOV=`$FIND $SDA $MOVIES`
MCNT=0
for i in $SDAMOV; do
MCNT=`expr $MCNT + 1`
done

if [ $MCNT -gt 0 ]; then

# Make sure we know we found files
if [ ! -e ${WORKDIR}/mount/sda ]; then
touch ${WORKDIR}/mound/sda
fi
echo $COPYM | festival --tts
cd ${BURNDIR}
for M in $SDAMOV; do
echo "Copying $M to ${BURNDIR}."
cp $M ./
done
fi
#// end movie/audio copy

fi


# /dev/sdb1

SDBFILES=`$FIND $SDB $IMAGES`


FCNT=0

for i in $SDBFILES; do
FCNT=`expr $FCNT + 1`
done

if [ $FCNT -gt 0 ]; then
touch ${WORKDIR}/mount/sdb
echo $COPYI | festival --tts
echo "Copying files from SDB..."
cd ${WORKDIR}/temp
for F in $SDBFILES; do
echo "Copying $F to ${WORKDIR}/temp"
cp $F ./
done

# Find any extra movie files, or audio files
SDBMOV=`$FIND $SDB $MOVIES`
MCNT=0
for i in $SDBMOV; do
MCNT=`expr $MCNT + 1`
done

if [ $MCNT -gt 0 ]; then
if [ ! -e ${WORKDIR}/mount/sdb ]; then
touch ${WORKDIR}/mount/sdb
fi
echo $COPYM | festival --tts
cd ${BURNDIR}
for M in $SDBMOV; do
echo "Copying $M to ${BURNDIR}."
cp $M ./
done
fi
#// end movie/audio copy

fi


# /dev/sdc1

SDCFILES=`$FIND $SDC $IMAGES`

FCNT=0

for i in $SDCFILES; do
FCNT=`expr $FCNT + 1`
done

if [ $FCNT -gt 0 ]; then
touch ${WORKDIR}/mount/sdc
echo $COPYI | festival --tts
echo "Copying files from SDC..."
cd ${WORKDIR}/temp
for F in $SDCFILES; do
echo "Copying $F to ${WORKDIR}/temp"
cp $F ./
done

# Find any extra movie files, or audio files
SDCMOV=`$FIND $SDC $MOVIES`
MCNT=0
for i in $SDCMOV; do
MCNT=`expr $MCNT + 1`
done

if [ $MCNT -gt 0 ]; then
if [ ! -e ${WORKDIR}/mount/sdc ]; then
touch ${WORKDIR}/mount/sdc
fi
echo $COPYM | festival --tts
cd ${BURNDIR}
for M in $SDCMOV; do
echo "Copying $M to ${BURNDIR}."
cp $M ./
done
fi
#// end movie/audio copy

fi

# /dev/sdd1

# Find all jpg's and tif's, this search is NOT case sensitive
SDDFILES=`$FIND $SDD $IMAGES`


FCNT=0

for i in $SDDFILES; do
FCNT=`expr $FCNT + 1`
done

if [ $FCNT -gt 0 ]; then
touch ${WORKDIR}/mount/sdd
echo $COPYI | festival --tts
echo "Copying files from SDD..."
cd ${WORKDIR}/temp
for F in $SDDFILES; do
echo "Copying $F to ${WORKDIR}/temp"
cp $F ./
done

# Find any extra movie files, or audio files
SDDMOV=`$FIND $SDD $MOVIES`
MCNT=0
for i in $SDDMOV; do
MCNT=`expr $MCNT + 1`
done

if [ $MCNT -gt 0 ]; then
if [ ! -e ${WORKDIR}/mount/sdd ]; then
touch ${WORKDIR}/mount/sdd
fi
echo $COPYM | festival --tts
cd ${BURNDIR}
for M in $SDDMOV; do
echo "Copying $M to ${BURNDIR}."
cp $M ./
done
fi
#// end movie/audio copy

fi




# /dev/sde1

SDEFILES=`$FIND $SDE $IMAGES`


FCNT=0

for i in $SDEFILES; do
FCNT=`expr $FCNT + 1`
done

if [ $FCNT -gt 0 ]; then
touch ${WORKDIR}/mount/sde
echo $COPYI | festival --tts
echo "Copying files from SDE..."
cd ${WORKDIR}/temp
for F in $SDEFILES; do
echo "Copying $F to ${WORKDIR}/temp"
cp $F ./
done

# Find any extra movie files, or audio files
SDEMOV=`$FIND $SDE $MOVIES`
MCNT=0
for i in $SDEMOV; do
MCNT=`expr $MCNT + 1`
done

if [ $MCNT -gt 0 ]; then
if [ ! -e ${WORKDIR}/mount/sde ]; then
touch ${WORKDIR}/mount/sde
fi
echo $COPYM | festival --tts
cd ${BURNDIR}
for M in $SDEMOV; do
echo "Copying $M to ${BURNDIR}."
cp $M ./
done
fi
#// end movie/audio copy

fi



# /dev/sdf1

SDFFILES=`$FIND $SDF $IMAGES`


FCNT=0

for i in $SDFFILES; do
FCNT=`expr $FCNT + 1`
done

if [ $FCNT -gt 0 ]; then
touch ${WORKDIR}/mount/sdf
echo $COPYI | festival --tts
echo "Copying files from SDF..."
cd ${WORKDIR}/temp
for F in $SDFFILES; do
echo "Copying $F to ${WORKDIR}/temp"
cp $F ./
done

# Find any extra movie files, or audio files
SDFMOV=`$FIND $SDF $MOVIES`
MCNT=0
for i in $SDFMOV; do
MCNT=`expr $MCNT + 1`
done

if [ $MCNT -gt 0 ]; then
if [ ! -e ${WORKDIR}/mount/sdf ]; then
touch ${WORKDIR}/mount/sdf
fi
echo $COPYM | festival --tts
cd ${BURNDIR}
for M in $SDFMOV; do
echo "Copying $M to ${BURNDIR}."
cp $M ./
done
fi
#// end movie/audio copy

fi




# /dev/sdg1

SDGFILES=`$FIND $SDG $IMAGES`


FCNT=0

for i in $SDGFILES; do
FCNT=`expr $FCNT + 1`
done

if [ $FCNT -gt 0 ]; then
touch ${WORKDIR}/mount/sdg
echo $COPYI | festival --tts
echo "Copying files from SDG..."
cd ${WORKDIR}/temp
for F in $SDGFILES; do
echo "Copying $F to ${WORKDIR}/temp"
cp $F ./
done

# Find any extra movie files, or audio files
SDGMOV=`$FIND $SDG $MOVIES`
MCNT=0
for i in $SDGMOV; do
MCNT=`expr $MCNT + 1`
done

if [ $MCNT -gt 0 ]; then
if [ ! -e ${WORKDIR}/mount/sdg ]; then
touch ${WORKDIR}/mount/sdg
fi
echo $COPYM | festival --tts
cd ${BURNDIR}
for M in $SDGMOV; do
echo "Copying $M to ${BURNDIR}."
cp $M ./
done
fi
#// end movie/audio copy

fi



# /dev/sdh1

SDHFILES=`$FIND $SDH $IMAGES`


FCNT=0

for i in $SDHFILES; do
FCNT=`expr $FCNT + 1`
done

if [ $FCNT -gt 0 ]; then
touch ${WORKDIR}/mount/sdh
echo $COPYI | festival --tts
echo "Copying files from SDH..."
cd ${WORKDIR}/temp
for F in $SDHFILES; do
echo "Copying $F to ${WORKDIR}/temp"
cp $F ./
done

# Find any extra movie files, or audio files
SDHMOV=`$FIND $SDH $MOVIES`
MCNT=0
for i in $SDHMOV; do
MCNT=`expr $MCNT + 1`
done

if [ $MCNT -gt 0 ]; then
if [ ! -e ${WORKDIR}/mount/sdh ]; then
touch ${WORKDIR}/mount/sdh
fi
echo $COPYM | festival --tts
cd ${BURNDIR}
for M in $SDHMOV; do
echo "Copying $M to ${BURNDIR}."
cp $M ./
done
fi
#// end movie/audio copy

fi


if [ -f ${WORKDIR}/mount/sda ]; then
echo "Something in sda"
elif [ -f ${WORKDIR}/mount/sdb ]; then
echo "Something in sdb"
elif [ -f ${WORKDIR}/mount/sdc ]; then
echo "Something in sdc"
elif [ -f ${WORKDIR}/mount/sdd ]; then
echo "Something in sdd"
elif [ -f ${WORKDIR}/mount/sde ]; then
echo "Something in sde"
elif [ -f ${WORKDIR}/mount/sdf ]; then
echo "Something in sdf"
elif [ -f ${WORKDIR}/mount/sdg ]; then
echo "Something in sdg"
elif [ -f ${WORKDIR}/mount/sdh ]; then
echo "Something in sdh"
else
echo "No files to process, removing pid and exiting..."
rm -f ${WORKDIR}/po.pid
exit
fi




#Get back into the temp dir
cd ${WORKDIR}/temp

IMG=`$FIND . -iname '*.jpg' -o -iname '*.tif'`

for F in $IMG; do
echo "Working on $NAME.$SUFFIX..."
# Extract our filenames and types
SUFFIX="`expr "$F" : '.*\.\([^./]*\)$'`"
NAME="`expr "$F" : '\(.*\)\.[^./]*$' \| "$F"`"

# Convert tiffs
if [ $SUFFIX == "tif" -o $SUFFIX == "TIF" ]; then
echo "$NAME.$SUFFIX will be converted."
/usr/bin/tifftopnm -respectfillorder $F > ${WORKDIR}/temp/temp.pnm
/usr/bin/pnmtojpeg ${WORKDIR}/temp/temp.pnm > $NAME.jpg
rm -f ${WORKDIR}/temp/temp.pnm
rm -f $F
else
echo "$F is a $SUFFIX, it will not be dealt with here."
fi

done


FIMG=`$FIND . -iname '*.jpg'`
I=${TMPJPG}

for F in $FIMG; do
# Rename files
I=`expr $I + 1`
TMP="image$I.jpg"
mv $F $TMP
done


chmod 666 ${WORKDIR}/temp/*


cp -a ${WORKDIR}/template/* ${WORKDIR}/burn
cp -a ${WORKDIR}/temp/*.jpg ${WORKDIR}/burn/imgs
rm -f ${WORKDIR}/temp/*


# check the size of our directory
CDSIZE=`du -s ${WORKDIR}/burn | awk '{print $1}'`

if [ $CDSIZE -lt 713031680 ]; then
cd ${WORKDIR}
${WORKDIR}/burnit.sh --data
echo "burning cd..."
else
echo $TOOBIG | festival --tts
exit

fi

It sources this file, burnrc:

# location of cd writer:
CDWRITER: ATAPI:0,0,0

# location of cdrom device file:
CDROM: /dev/cdrom

# location od cdrom mount point:
CDMNT: /media/cdrom

# the speed of your burner:
SPEED: 8

# type of blanking
BLANKING: disc

# where files to be burned are located
BURNDIR: /usr/local/copydisk/burn

# the working dir
WORKDIR: /usr/local/copydisk

# number of template jpg's
TMPJPG: 0

#########################################
# CD info #
#########################################

COPYRIGHT: © CopyDisk

DESCRIPTION: Vacation CD

AUTHOR: My Vacation CD

PUBLISHER: CopyDisk Corp

NUMBEROFCDS: 1

CURRENTNUMBER: 1

LABEL: My Vacation - CopyDisk Corp

NAMEOFPACKAGE: My Vacation - CopyDisk Corp

#################################
# Misc Options #
#################################

# use normalize or not. Default is no.
NORMALIZE: no

# driver options. For example burnsafe or swabaudio.
# leave this blank if unsure. default is nothing.
OPT_ONE:

# whether BashBurn should support overburn.
# default is no
OVERBURN: no

#################################
# Commands #
#################################

BURNF: Your CD creation failed. There was either a blank, data, or no CD in the CD tray. Insert a blank CD and try again.
BURNS: Your CD was successfully created. Please remove your CD and flash card.
COPYI: Your pictures have been found and are being processed. Please do not remove the flash card and CD until you have been prompted.
COPYM: Your movies have been found and are being processed. Please do not remove the flash card and CD until you have been prompted.
CALLS: There has been an internal error. Please call technical support.
TOOBIG: There are too many files on your disk to copy to the CD in one pass. Please edit your card and try again.You can see that the Festival package was used to actually tell the operator that the CD was done...or not, if they did something wrong.


When it gets all the files in the proper order, it calls the burnit.sh script to create the ISO and burn the CD.

The burnit.sh script:

#!/bin/bash

# Make our disk


# This is a function to burn all files in /var/copydisk/burn/ as a data-CD.
# if there is an .iso-file in the BURNDIR already, it 'll execute iso_burning
# to burn it; if there isn't one, then it'll create an iso and then execute the other function.

data_burning()
{
if [ "$(find ${BURNDIR} -iname '*iso' | sort)" != "" ]; then
iso_burning
else
if eval "mkisofs -r -J -hide-joliet-trans-tbl -copyright \"${COPYRIGHT}\" -A \"${DESCRIPTION}\" -p \"${AUTHOR}\" -P \"${PUBLISHER}\" -volset \"${NAMEOFPACKAGE}\" -volset-size \"${NUMBEROFCDS}\" -volset-seqno \"${CURRENTNUMBER}\" -V \"${LABEL}\" -hfs -map \"${WORKDIR}\"/map -no-desktop -probe --macbin -o \"${BURNDIR}\"/photoopp.iso \"${BURNDIR}\""; then
iso_burning
else
echo $CALLS | festival --tts
echo "Something bad happened to the iso creation."
rm -rf "${BURNDIR}"/*
rm -f ${RUNDIR}/${PID}
exit
fi
fi
}

# burn the .iso-file in the BURNDIR.
iso_burning()
{
check_overburn # Check if overburn was enabled in configure
if cdrecord dev=${CDWRITER} speed=${SPEED} ${OPT_ONE:+"driveropts=$OPT_ONE"} -eject ${OBURN} ${BURNDIR}/photoopp.iso; then

# REMOVE AFTER TESTING
#if [ -e ${BURNDIR}/photoopp.iso ]; then
# mv ${BURNDIR}/photoopp.iso ${WORKDIR}/
# END REMOVE

echo "The burn was successful, going to check_tempdel function for system cleanup..."
check_tempdel
else
echo "The burn to CD failed, going to burn_failed function."
burn_failed
fi


}



# A function to see if files in temp dir should be deleted after burning is done
# and an opportunity to burn more of the same iso
check_tempdel()
{
ALLFILES="( -iname *.jpg -o -iname *.tif -o -iname *.avi -o -iname *.mpg -o -iname *.mpeg -o -iname *.mp3 -o -iname *.wav -o -iname *.mov )"
#while true; do
# echo "Do ya want another?"
# read -t30 TEMP
#if [ "$TEMP" == "y" -o "Y" ]; then
# TEMP=""
# iso_burning
#else
echo "Cleaning out our burn directory."
rm -rf ${BURNDIR}/*
rm -rf ${BURNDIR}/.*
echo "Done."

echo "Checking which drive was mounted..."
if [ -e ${WORKDIR}/mount/sda ]; then
echo "Removing files from sda..."
SDA=`/usr/bin/find /misc/sda $ALLFILES`
for F in $SDA; do
rm -f $F
done
echo "Done."
rm -f ${WORKDIR}/mount/sda
elif [ -e ${WORKDIR}/mount/sdb ]
then
echo "Removing files from sdb..."
SDB=`/usr/bin/find /misc/sdb $ALLFILES`
for F in $SDB; do
rm -f $F
done
echo "Done."
rm -f ${WORKDIR}/mount/sdb
elif [ -e ${WORKDIR}/mount/sdc ]
then
echo "Removing files from sdc..."
SDC=`/usr/bin/find /misc/sdc $ALLFILES`
for F in $SDC; do
rm -f $F
done
echo "Done."
rm -f ${WORKDIR}/mount/sdc
elif [ -e ${WORKDIR}/mount/sdd ]
then
echo "Removing files from sdd..."
SDD=`/usr/bin/find /misc/sdd $ALLFILES`
for F in $SDD; do
rm -f $F
done
echo "Done."
rm -f ${WORKDIR}/mount/sdd
elif [ -e ${WORKDIR}/mount/sde ]
then
echo "Removing files from sde..."
SDE=`/usr/bin/find /misc/sde $ALLFILES`
for F in $SDE; do
rm -f $F
done
echo "Done."
rm -f ${WORKDIR}/mount/sde
elif [ -e ${WORKDIR}/mount/sdf ]
then
echo "Removing files from sdf..."
SDF=`/usr/bin/find /misc/sdf $ALLFILES`
for F in $SDF; do
rm -f $F
done
echo "Done."
rm -f ${WORKDIR}/mount/sdf
elif [ -e ${WORKDIR}/mount/sdg ]
then
echo "Removing files from sdg..."
SDG=`/usr/bin/find /misc/sdg $ALLFILES`
for F in $SDG; do
rm -f $F
done
echo "Done."
rm -f ${WORKDIR}/mount/sdg
elif [ -e ${WORKDIR}/mount/sdh ]
then
echo "Removing files from sdh..."
SDH=`/usr/bin/find /misc/sdh $ALLFILES`
for F in $SDH; do
rm -f $F
done
echo "Done."
rm -f ${WORKDIR}/mount/sdh
fi

# write to log file
if [ ! -e ${WORKDIR}/log/log.txt ]; then
echo "Log file not found...creating it."
touch ${WORKDIR}/log/log.txt
fi
DATE=`date`
echo "A successful CD was made on $DATE." >> ${WORKDIR}/log/log.txt
echo "Log written."
echo $BURNS | festival --tts
echo "Removing copydisk PID file."
rm -f /usr/local/copydisk/po.pid
echo "Exiting program."
exit
#fi
#done
}


# A function for responding to a cd containing data, or no cd in tray
burn_failed()
{

#while true; do
#play ${WORKDIR}/insertcd.wav

echo "The burning to cd failed."
eject

#read -t30 TEMP
#if [ "$TEMP" = "y" -o "$TEMP" = "Y" ]; then
# TEMP=""
# iso_burning
#else

echo "Cleaning out the burn directory and mount directory."
rm -rf ${BURNDIR}/*
rm -rf ${BURNDIR}/.*
rm -rf ${WORKDIR}/mount/*

# write to log file
#if [ ! -e ${WORKDIR}/log/errorlog.txt ]; then
# touch ${WORKDIR}/log/errorlog.txt
#fi

#DATE=`date`
#echo "A CD failed on $DATE." >> ${WORKDIR}/log/errorlog.txt
echo $BURNF | festival --tts
echo "Removing copydisk PID file."
rm -f /usr/local/copydisk/po.pid
echo "Exiting program."
exit

#fi

#done
}


#This function lets you swap cds if NUMDEV is set to 1
insert_new_CD()
{
while true; do
echo "Insert blank cd and then press enter to go on"
read TEMP
if [ "$TEMP" = "" ]; then
break
else
continue
fi
done
}


# A function to check if overburn is enabled
check_overburn()
{
if [ "${OVERBURN}" = "yes" ]; then # Is overburn enabled?
OBURN="-overburn" # yes it was
else
echo "Not enabling overburn..." # No it wasn't
OBURN=""
fi
}

# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
case "$1" in
"--data")
data_burning
;;
"--iso")
iso_burning
;;
esac
I also found it was necessary to map some file types for Mac, or they wouldn't play the Flash Projector file, since it had no "association" with the Shockwave player.

The map:

# EXTN Xlate Creator Type Comment
#
.1st Ascii 'ttxt' 'TEXT' "Text Readme"
.669 Raw 'SNPL' '6669' "669 MOD Music "
.8med Raw 'SCPL' 'STrk' "Amiga OctaMed music"
.8svx Raw 'SCPL' '8SVX' "Amiga 8-bit sound "
.Z Raw 'SITx' 'ZIVU' "Unix Compress Archive "
.a Ascii 'ttxt' 'TEXT' "Assembly Source"
.aif Raw 'SCPL' 'AIFF' "AIFF Sound"
.aifc Raw 'SCPL' 'AIFC' "AIFF Sound Compressed "
.aiff Raw 'SCPL' 'AIFF' "AIFF Sound"
.al Raw 'SCPL' 'ALAW' "ALAW Sound"
.ani Raw 'GKON' 'ANIi' "Animated NeoChrome"
.apd Ascii 'ALD3' 'TEXT' "Aldus Printer Description "
.appl Raw '????' 'APPL' "Executable file"
.arc Raw 'SITx' 'mArc' "PC ARChive"
.arj Raw 'DArj' 'BINA' "ARJ Archive"
.arr Raw 'GKON' 'ARR ' "Amber ARR image"
.art Raw 'GKON' 'ART ' "First Publisher"
.asc Ascii 'ttxt' 'TEXT' "ASCII Text"
.ascii Ascii 'ttxt' 'TEXT' "ASCII Text"
.asf Raw 'Ms01' 'ASF_' "Netshow Player"
.asm Ascii 'ttxt' 'TEXT' "Assembly Source"
.asx Raw 'Ms01' 'ASX_' "Netshow Player"
.au Raw 'TVOD' 'ULAW' "Sun Sound "
.avi Raw 'TVOD' 'VfW ' "AVI Movie "
.bar Raw 'S691' 'BARF' "Unix BAR Archive"
.bas Ascii 'ttxt' 'TEXT' "BASIC Source"
.bat Ascii 'ttxt' 'TEXT' "MS-DOS Batch File "
.bga Raw 'ogle' 'BMPp' "OS/2 Bitmap"
.bib Ascii 'ttxt' 'TEXT' "BibTex Bibliography"
.bin Raw 'SITx' 'SIT!' "MacBinary "
.binary Raw 'hDmp' 'BINA' "Untyped Binary Data"
.bld Raw 'GKON' 'BLD ' "BLD"
.bmp Raw 'ogle' 'BMPp' "Windows Bitmap"
.boo Ascii 'ttxt' 'TEXT' "BOO encoded"
.bst Ascii 'ttxt' 'TEXT' "BibTex Style"
.bum Raw 'GKON' '.bMp' "QuickTime Importer(QuickDraw) GraphicConverter"
.bw Raw 'GKON' 'SGI ' "SGI Image "
.c Ascii 'CWIE' 'TEXT' "C Source"
.cel Raw 'GKON' 'CEL ' "KISS CEL"
.cgm Raw 'GKON' 'CGMm' "Computer Graphics Meta"
.class Raw 'CWIE' 'Clss' "Java Class File"
.clp Raw 'GKON' 'CLPp' "Windows Clipboard "
.cmd Ascii 'ttxt' 'TEXT' "OS/2 Batch File"
.cnf Ascii 'TEXT' 'KiSS' "KISS Config"
.com Raw 'SWIN' 'PCFA' "MS-DOS Executable "
.cp Ascii 'CWIE' 'TEXT' "C++ Source"
.cpp Ascii 'CWIE' 'TEXT' "C++ Source"
.cpt Raw 'SITx' 'PACT' "Compact Pro Archive"
.csv Ascii 'XCEL' 'TEXT' "Comma Separated Vars"
.ct Raw 'GKON' '..CT' "Scitex-CT "
.cur Raw 'GKON' 'CUR ' "Windows Cursor"
.cut Raw 'GKON' 'Halo' "Dr Halo Image "
.cvs Raw 'DAD2' 'drw2' "Canvas Drawing"
.cwj Raw 'cwkj' 'CWSS' "ClarisWorks Document"
.dat Raw 'GKON' 'TCLl' "TCL image "
.dbf Raw 'FOX+' 'COMP' "DBase Document"
.dcx Raw 'GKON' 'DCXx' "Some PCX Images"
.dif Ascii 'XCEL' 'TEXT' "Data Interchange Format"
.diz Ascii 'R*Ch' 'TEXT' "BBS Descriptive Text"
.dl Raw 'AnVw' 'DL ' "DL Animation"
.dll Raw 'SWIN' 'PCFL' "Windows DLL"
.doc Raw 'MSWD' 'WDBN' "Word Document "
.dot Raw 'MSWD' 'sDBN' "Word for Windows Template "
.dvi Raw 'xdvi' 'ODVI' "TeX DVI Document"
.dwt Ascii 'DmWr' 'TEXT' "Dreamweaver Template"
.dxf Ascii 'SWVL' 'TEXT' "AutoCAD 3D Data"
.eps Raw 'vgrd' 'EPSF' "Postscript"
.epsf Raw 'vgrd' 'EPSF' "Postscript"
.etx Ascii 'ezVu' 'TEXT' "SEText"
.evy Raw 'ENVY' 'EVYD' "Envoy Document"
.exe Raw 'SWIN' 'PCFA' "MS-DOS Executable "
.faq Ascii 'ttxt' 'TEXT' "ASCII Text"
.fit Raw 'GKON' 'FITS' "Flexible Image Transport"
.flc Raw 'TVOD' 'FLI ' "FLIC Animation"
.fli Raw 'TVOD' 'FLI ' "FLI Animation "
.fm Raw 'FMPR' 'FMPR' "FileMaker Pro Database"
.for Ascii 'MPS ' 'TEXT' "Fortran Source"
.fts Raw 'GKON' 'FITS' "Flexible Image Transport"
.gem Raw 'GKON' 'GEM-' "GEM Metafile"
.gif Raw 'ogle' 'GIFf' "GIF Picture"
.gif Raw 'GIFf' 'MOSS' "GIF Image"
.gl Raw 'AnVw' 'GL ' "GL Animation"
.grp Raw 'GKON' 'GRPp' "GRP Image "
.gz Raw 'SITx' 'SIT!' "Gnu ZIP Archive"
.h Ascii 'CWIE' 'TEXT' "C Include File"
.hcom Raw 'SCPL' 'FSSD' "SoundEdit Sound ex SOX"
.hp Ascii 'CWIE' 'TEXT' "C Include File"
.hpgl Raw 'GKON' 'HPGL' "HP GL/2"
.hpp Ascii 'CWIE' 'TEXT' "C Include File"
.hqx Ascii 'SITx' 'TEXT' "BinHex"
.hr Raw 'GKON' 'TR80' "TSR-80 HR "
.htm Ascii 'MOSS' 'TEXT' "HyperText "
.html Ascii 'MOSS' 'TEXT' "HyperText "
.i3 Ascii 'R*ch' 'TEXT' "Modula 3 Interface"
.ic1 Raw 'GKON' 'IMAG' "Atari Image"
.ic2 Raw 'GKON' 'IMAG' "Atari Image"
.ic3 Raw 'GKON' 'IMAG' "Atari Image"
.icn Raw 'GKON' 'ICO ' "Windows Icon"
.ico Raw 'GKON' 'ICO ' "Windows Icon"
.ief Raw 'GKON' 'IEF ' "IEF image "
.iff Raw 'GKON' 'ILBM' "Amiga IFF Image"
.ilbm Raw 'GKON' 'ILBM' "Amiga ILBM Image"
.image Raw 'ddsk' 'dImg' "Apple DiskCopy Image"
.img Raw 'GKON' 'IMGg' "GEM bit image/XIMG"
.ini Ascii 'ttxt' 'TEXT' "Windows INI File"
.iss Raw 'GKON' 'ISS ' "ISS"
.java Ascii 'CWIE' 'TEXT' "Java Source File"
.jfif Raw 'ogle' 'JPEG' "JFIF Image"
.jif Raw 'GKON' 'JIFf' "JIF99a"
.jpe Raw 'ogle' 'JPEG' "JPEG Picture"
.jpeg Raw 'ogle' 'JPEG' "JPEG Picture"
.jpg Raw 'ogle' 'JPEG' "JPEG Picture"
.jpg Raw 'JPEG' 'MOSS' "JPEG Image"
.latex Ascii 'OTEX' 'TEXT' "Latex "
.lbm Raw 'GKON' 'ILBM' "Amiga IFF Image"
.lwf Raw 'GKON' 'lwfF' "LuraWave(LWF) "
.lzh Raw 'LHA ' 'LARC' "LHA Archive"
.m1a Raw 'TVOD' 'MPEG' "MPEG-1 audiostream"
.m1s Raw 'TVOD' 'MPEG' "MPEG-1 systemstream"
.m1v Raw 'TVOD' 'M1V ' "MPEG-1 IPB videostream"
.m2 Ascii 'R*ch' 'TEXT' "Modula 2 Source"
.m2v Raw 'MPG2' 'MPG2' "MPEG-2 IPB videostream"
.m3 Ascii 'R*ch' 'TEXT' "Modula 3 Source"
.mac Raw 'ogle' 'PICT' "PICT Picture"
.mak Ascii 'R*ch' 'TEXT' "Makefile"
.mbm Raw 'GKON' 'MBM ' "PSION 5(MBM)"
.mcw Raw 'MSWD' 'WDBN' "Mac Word Document "
.me Ascii 'ttxt' 'TEXT' "Text Readme"
.med Raw 'SCPL' 'STrk' "Amiga MED Sound"
.mf Ascii '*MF*' 'TEXT' "Metafont"
.mid Raw 'TVOD' 'Midi' "MIDI Music"
.mid Raw 'Midi' 'ttxt' "MIDI Sequence"
.midi Raw 'TVOD' 'Midi' "MIDI Music"
.mif Ascii 'Fram' 'TEXT' "FrameMaker MIF"
.mime Ascii 'SITx' 'TEXT' "MIME Message"
.ml Ascii 'R*ch' 'TEXT' "ML Source "
.mod Raw 'SCPL' 'STrk' "MOD Music "
.mol Ascii 'RSML' 'TEXT' "MDL Molfile"
.moov Raw 'TVOD' 'MooV' "QuickTime Movie"
.mov Raw 'TVOD' 'MooV' "QuickTime Movie"
.mp2 Raw 'hook' 'MPEG' "MPEG-1 audiostream"
.mp3 Raw 'hook' 'MPG3' "MPEG-3 audiostream"
.mpa Raw 'hook' 'MPEG' "MPEG-1 audiostream"
.mpe Raw 'TVOD' 'MPEG' "MPEG Movie of some sort"
.mpeg Raw 'TVOD' 'MPEG' "MPEG Movie of some sort"
.mpg Raw 'TVOD' 'MPEG' "MPEG Movie of some sort"
.msp Raw 'GKON' 'MSPp' "Microsoft Paint"
.mtm Raw 'SNPL' 'MTM ' "MultiMOD Music"
.mw Raw 'MWII' 'MW2D' "MacWrite Document "
.mwii Raw 'MWII' 'MW2D' "MacWrite Document "
.neo Raw 'GKON' 'NeoC' "Atari NeoChrome"
.nfo Ascii 'ttxt' 'TEXT' "Info Text "
.ngg Raw 'GKON' 'NGGC' "Mobile Phone(Nokia)Format "
.nol Raw 'GKON' 'NOL ' "Mobile Phone(Nokia)Format "
.nst Raw 'SCPL' 'STrk' "MOD Music "
.obj Raw 'SWIN' 'PCFL' "Object (DOS/Windows)"
.oda Raw 'ODA ' 'ODIF' "ODA Document"
.okt Raw 'SCPL' 'OKTA' "Oktalyser MOD Music"
.out Raw 'hDmp' 'BINA' "Output File"
.ovl Raw 'SWIN' 'PCFL' "Overlay (DOS/Windows) "
.p Ascii 'CWIE' 'TEXT' "Pascal Source "
.pac Raw 'GKON' 'STAD' "Atari STAD Image"
.pal Raw '8BIM' '8BCT' "Color Table"
.pas Ascii 'CWIE' 'TEXT' "Pascal Source "
.pbm Raw 'GKON' 'PPGM' "Portable Bitmap"
.pc1 Raw 'GKON' 'Dega' "Atari Degas Image "
.pc2 Raw 'GKON' 'Dega' "Atari Degas Image "
.pc3 Raw 'GKON' 'Dega' "Atari Degas Image "
.pcs Raw 'GKON' 'PICS' "Animated PICTs"
.pct Raw 'ogle' 'PICT' "PICT Picture"
.pcx Raw 'GKON' 'PCXx' "PC PaintBrush "
.pdb Ascii 'RSML' 'TEXT' "Brookhaven PDB file"
.pdf Raw 'CARO' 'PDF ' "Portable Doc Format"
.pdf Raw 'CARO' 'PDF ' "Portable Document Format"
.pdx Ascii 'ALD5' 'TEXT' "Printer Description"
.pf Raw 'SITx' 'CSIT' "Private File"
.pgc Raw 'GKON' 'PGCF' "PGC/PGF Atari Portfolio PCG"
.pgm Raw 'GKON' 'PPGM' "Portable Graymap"
.pi1 Raw 'GKON' 'Dega' "Atari Degas Image "
.pi2 Raw 'GKON' 'Dega' "Atari Degas Image "
.pi3 Raw 'GKON' 'Dega' "Atari Degas Image "
.pic Raw 'ogle' 'PICT' "PICT Picture"
.pics Raw 'GKON' 'PICS' "PICS-PICT Sequence"
.pict Raw 'ogle' 'PICT' "PICT Picture"
.pit Raw 'SITx' 'PIT ' "PackIt Archive"
.pkg Raw 'SITx' 'HBSF' "AppleLink Package "
.pl Ascii 'McPL' 'TEXT' "Perl Source"
.plt Raw 'GKON' 'HPGL' "HP GL/2"
.pm Raw 'GKON' 'PMpm' "Bitmap from xv"
.pm3 Raw 'ALD3' 'ALB3' "PageMaker 3 Document"
.pm4 Raw 'ALD4' 'ALB4' "PageMaker 4 Document"
.pm5 Raw 'ALD5' 'ALB5' "PageMaker 5 Document"
.png Raw 'PNG ' 'MOSS' "PNG Image"
.png Raw 'ogle' 'PNG ' "Portable Network Graphic"
.pntg Raw 'ogle' 'PNTG' "Macintosh Painting"
.ppd Ascii 'ALD5' 'TEXT' "Printer Description"
.ppm Raw 'GKON' 'PPGM' "Portable Pixmap"
.prn Ascii 'R*ch' 'TEXT' "Printer Output File"
.ps Ascii 'vgrd' 'TEXT' "PostScript"
.psd Raw '8BPS' '8BIM' "Photoshop Image"
.psd Raw '8BIM' '8BPS' "PhotoShop Document"
.pt4 Raw 'ALD4' 'ALT4' "PageMaker 4 Template"
.pt5 Raw 'ALD5' 'ALT5' "PageMaker 5 Template"
.pxr Raw '8BIM' 'PXR ' "Pixar Image"
.qdv Raw 'GKON' 'QDVf' "QDV image "
.qt Raw 'TVOD' 'MooV' "QuickTime Movie"
.qxd Raw 'XPR3' 'XDOC' "QuarkXpress Document"
.qxt Raw 'XPR3' 'XTMP' "QuarkXpress Template"
.raw Raw 'GKON' 'BINA' " Raw Image "
.readme Ascii 'ttxt' 'TEXT' "Text Readme"
.rgb Raw 'GKON' 'SGI ' "SGI Image "
.rgba Raw 'GKON' 'SGI ' "SGI Image "
.rib Ascii 'RINI' 'TEXT' "Renderman 3D Data "
.rif Raw 'GKON' 'RIFF' "RIFF Graphic"
.rle Raw 'GKON' 'RLE ' "RLE image "
.rme Ascii 'ttxt' 'TEXT' "Text Readme"
.rpl Raw 'REP!' 'FRL!' "Replica Document"
.rsc Raw 'RSED' 'rsrc' "Resource File "
.rsrc Raw 'RSED' 'rsrc' "Resource File "
.rtf Ascii 'MSWD' 'TEXT' "Rich Text Format"
.rtx Ascii 'R*ch' 'TEXT' "Rich Text "
.s3m Raw 'SNPL' 'S3M ' "ScreamTracker 3 MOD"
.scc Raw 'GKON' 'MSX ' "MSX pitcure"
.scg Raw 'GKON' 'RIX3' "ColoRIX"
.sci Raw 'GKON' 'RIX3' "ColoRIX"
.scp Raw 'GKON' 'RIX3' "ColoRIX"
.scr Raw 'GKON' 'RIX3' "ColoRIX"
.scu Raw 'GKON' 'RIX3' "ColoRIX"
.sea Raw '????' 'APPL' "Self-Extracting Archive"
.sf Raw 'SDHK' 'IRCM' "IRCAM Sound"
.sgi Raw 'ogle' '.SGI' "SGI Image "
.sha Ascii 'UnSh' 'TEXT' "Unix Shell Archive"
.shar Ascii 'UnSh' 'TEXT' "Unix Shell Archive"
.shp Raw 'GKON' 'SHPp' "Printmaster Icon Library"
.sit Raw 'SITx' 'SIT!' "StuffIt 1.5.1 Archive "
.sithqx Ascii 'SITx' 'TEXT' "BinHexed StuffIt Archive"
.six Raw 'GKON' 'SIXE' "SIXEL image"
.slk Ascii 'XCEL' 'TEXT' "SYLK Spreadsheet"
.smi Raw 'oneb' 'APPL' "Self Mount Image"
.snd Raw 'SCPL' 'BINA' "Sound of various types"
.spc Raw 'GKON' 'Spec' "Atari Spectrum 512"
.sr Raw 'GKON' 'SUNn' "Sun Raster Image"
.sty Ascii '*TEX' 'TEXT' "TeX Style "
.sun Raw 'GKON' 'SUNn' "Sun Raster Image"
.sup Raw 'GKON' 'SCRN' "StartupScreen "
.svx Raw 'SCPL' '8SVX' "Amiga IFF Sound"
.swf Raw 'SWF2' 'SWFL' "Macromedia Showckwave Flash "
.syk Ascii 'XCEL' 'TEXT' "SYLK Spreadsheet"
.sylk Ascii 'XCEL' 'TEXT' "SYLK Spreadsheet"
.tar Raw 'SITx' 'TARF' "Unix Tape ARchive "
.targa Raw 'GKON' 'TPIC' "Truevision Image"
.taz Raw 'SITx' 'ZIVU' "Compressed Tape ARchive"
.tex Ascii 'OTEX' 'TEXT' "TeX Document"
.texi Ascii 'OTEX' 'TEXT' "TeX Document"
.texinfo Ascii 'OTEX' 'TEXT' "TeX Document"
.text Ascii 'ttxt' 'TEXT' "ASCII Text"
.tga Raw 'GKON' 'TPIC' "Truevision Image"
.tgz Raw 'SITx' 'Gzip' "Gnu ZIPed Tape ARchive"
.tif Raw 'ogle' 'TIFF' "TIFF Picture"
.tiff Raw 'ogle' 'TIFF' "TIFF Picture"
.tny Raw 'GKON' 'TINY' "Atari TINY Bitmap "
.tsv Ascii 'XCEL' 'TEXT' "Tab Separated Values"
.tx8 Ascii 'ttxt' 'TEXT' "8-bit ASCII Text"
.txt Ascii 'ttxt' 'TEXT' "ASCII Text"
.txt Ascii 'TEXT' 'ttxt' "Text Document"
.ul Raw 'TVOD' 'ULAW' "Mu-Law Sound"
.url Raw 'Arch' 'AURL' "URL Bookmark"
.uu Ascii 'SITx' 'TEXT' "UUEncode"
.uue Ascii 'SITx' 'TEXT' "UUEncode"
.vff Raw 'GKON' 'VFFf' "DESR VFF Greyscale Image"
.vga Raw 'ogle' 'BMPp' "OS/2 Bitmap"
.voc Raw 'SCPL' 'VOC ' "VOC Sound "
.vpb Raw 'GKON' 'VPB ' "VPB QUANTEL"
.w51 Raw 'WPC2' '.WP5' "WordPerfect PC 5.1 Doc"
.wav Raw 'TVOD' 'WAVE' "Windows WAV Sound "
.wbmp Raw 'GKON' 'WBMP' "WBMP"
.wk1 Raw 'XCEL' 'XLBN' "Lotus Spreadsheet r2.1"
.wks Raw 'XCEL' 'XLBN' "Lotus Spreadsheet r1.x"
.wmf Raw 'GKON' 'WMF ' "Windows Metafile"
.wp Raw 'WPC2' '.WP5' "WordPerfect PC 5.1 Doc"
.wp4 Raw 'WPC2' '.WP4' "WordPerfect PC 4.2 Doc"
.wp5 Raw 'WPC2' '.WP5' "WordPerfect PC 5.x Doc"
.wp6 Raw 'WPC2' '.WP6' "WordPerfect PC 6.x Doc"
.wpg Raw 'GKON' 'WPGf' "WordPerfect Graphic"
.wpm Raw 'WPC2' 'WPD1' "WordPerfect Mac"
.wri Raw 'MSWD' 'WDBN' "MS Write/Windows"
.wve Raw 'SCPL' 'BINA' "PSION sound"
.x-face Ascii 'GKON' 'TEXT' "X-Face "
.x10 Raw 'GKON' 'XWDd' "X-Windows Dump"
.x11 Raw 'GKON' 'XWDd' "X-Windows Dump"
.xbm Raw 'GKON' 'XBM ' "X-Windows Bitmap"
.xl Raw 'XCEL' 'XLS ' "Excel Spreadsheet "
.xlc Raw 'XCEL' 'XLC ' "Excel Chart"
.xlm Raw 'XCEL' 'XLM ' "Excel Macro"
.xls Raw 'XCEL' 'XLS ' "Excel Spreadsheet "
.xlw Raw 'XCEL' 'XLW ' "Excel Workspace"
.xm Raw 'SNPL' 'XM ' "FastTracker MOD Music "
.xpm Raw 'GKON' 'XPM ' "X-Windows Pixmap"
.xwd Raw 'GKON' 'XWDd' "X-Windows Dump"
.zip Raw 'SITx' 'ZIP ' "PC ZIP Archive"
.zoo Raw 'Booz' 'Zoo ' "Zoo Archive"


This was a great project to work on.

Windows Automated Maintenance Scripts

I had a need to automate a number of tasks for remote administration, and used Windows WShell, since I am fairly comfortable with VB/VBA.

This is an automated defragmentation script that uses dirms.exe, a defragmentation utility found
here.


Option Explicit

Dim FSO, Drive, oShell, WshShell, BtnCode, rtn, hd, stComp
Set WshShell = WScript.CreateObject("WScript.Shell")
Set FSO = CreateObject("Scripting.FileSystemObject")
Set oShell = WScript.CreateObject ("WScript.shell")

'''' ''''''''''''''''''' DIRMS.EXE USAGE
' dirms c -q : Do free space evaluation, defragment, and quickly move files to the front of the drive
' dirms c DEFRAG -q : Defragment files only
' dirms c CoMpAcT -q : C ompact only
' dirms c COMFRAG -q : Perform partial compaction (quickly) on all fragmented files
' dirms c COMFRAG c:\filename.exe : Perform partial compaction on one file
' dirms c move date -q : Move files according to modification dates, and do it quickly
' dirms c move lcn : Try to free space at the bottom of the drive (moves files toward the front of the drive)
'''''''''''''''''''''''''''''''''''''''''''''''

' This sets the drive type to look for to Fixed
Const constFixed = 2

' enumerate all drives
For Each Drive in FSO.Drives
If Drive.DriveType = constFixed Then
hd = LCase(Left(Drive, 1))
stComp = StrComp("M", hd, 1) ' Returns 0 if the M drive.

' Only run if not the IFS drive
If stComp = 1 Then

' Ask the user nicely...
BtnCode = WshShell.PopUp("pcTech needs to degragment your " & Drive & " hard drive[s]. Is that OK?", 60, "pcTech", 4 + 32)
Select Case BtnCode
' Show an OK (1) or Cancel (2) button
Case 6 rtn = WshShell.PopUp("Thanks, please don't turn your PC off for 24 hours.", 5, "pcTech", 1)
If rtn = 1 Then
'do nothing
ElseIf rtn = 2 Then
Exit For
MsgBox "Defrag cancelled", 0, "pcTech"
End If
Case 7 rtn = WshShell.PopUp("Ok, we'll wait until the next time.", 5, "pcTech", 0)
End Select

Select Case ShowFileSystemType(Drive)
Case "NTFS"
' Run NTFS defrag
oShell.run "cmd /c c:\temp\dirms.exe " & hd & " -q > c:\temp\defrag_" & hd & "_hdd.txt", 0
Case "FAT"
' Run FAT defrag, yes I know, it's the same command, but I was hoping
' to find a win95 cli defrag util to use in it's place...
oShell.run "cmd /c c:\temp\dirms.exe " & hd & " -q > c:\temp\defrag_" & hd & "_hdd.txt", 0
Case "CDFS"
' Do nothing, it's a CD
Case Else
' Shit, can't defrag? We should never get this far...
BtnCode = WshShell.Popup("pcTech found no drives to defragment.", 15, "pcTech", 0 + 16)
End Select

'end of stComp check
End If

' end of Fixed Drive check
End If

Next


Set oShell = Nothing
Set FSO = Nothing
Set WshShell = Nothing


Function ShowFileSystemType(drvspec)
Dim FSO,d
Set FSO = CreateObject("Scripting.FileSystemObject")
Set d = FSO.GetDrive(drvspec)
ShowFileSystemType = d.FileSystem
End Function



  • This is a script that uses SpyBot to remove spyware. There was an ability to retrieve the Stats.ini file from the machine, and populate a SQL db for reporting purposes.


Option Explicit

Set objFSO = CreateObject("Scripting.FileSystemObject")


' Set the type of file access
Const ForReading = 1, ForWriting = 2, ForAppending = 8

' Set our input file
'Determine what our OS version is, since it is dependant on gathering statistics and placement of files
' Per this page that says our configuration.ini file is found in different places as noted below.
' http://www.spybot.info/pt/faq/23.html
'For Windows 95/98, the file is located in C:\Windows\Application Data\Spybot - Search & Destroy\.
'For Windows ME, the file is located in C:\Windows\All Users\Application Data\Spybot - Search & Destroy\.
'For Windows NT/2000/XP, you will find it in C:\Documents and Settings\All Users\Application Data\Spybot - Search & Destroy\.

Select Case GetOS
Case "0"
objINFile = "C:\Windows\Application Data\Spybot - Search & Destroy\Statistics.ini "
Case "4.9"
objINFile = "C:\Windows\All Users\Application Data\Spybot - Search & Destroy\Statistics.ini"
Case Else
objINFile = "C:\Documents and Settings\All Users\Application Data\Spybot - Search & Destroy\Statistics.ini"
End Select

' Set our output file and it's location
objOUTFile = "C:\Temp\Stats.ini"

' If our output file doesn't exist, create it, if it does, delete and create
If Not objFSO.FileExists(objOUTFile) Then
Set fso = CreateObject("Scripting.FileSystemObject")
Set f1 = fso.CreateTextFile(objOUTFile, True)
Set fso = Nothing
Set f1 = Nothing
ElseIf objFSO.FileExists(objOutFile) Then
Set fso = CreateObject("Scripting.FileSystemObject")
fso.DeleteFile objOUTFile
Set f1 = fso.CreateTextFile(objOUTFile, True)
Set fso = Nothing
Set f1 = Nothing
End If

' Move our configuration.ini file to it's proper location
Select Case GetOS
Case "0"
objConfPath = "C:\Windows\Application Data\Spybot - Search & Destroy\"
Case "4.9"
objConfPath = "C:\Windows\All Users\Application Data\Spybot - Search & Destroy\"
Case Else
objConfPath = "C:\Documents and Settings\All Users\Application Data\Spybot - Search & Destroy\"
End Select

' Now that our configuration path is set, copy the configuration.ini to it
' Use Error handling to ignore the absence of a configuration.ini
On Error Resume Next
FileSystemObject.CopyFile "C:\temp\Configuration.ini", objConfPath, True


'Open file for reading
Set objIFile = objFSO.OpenTextFile(objINFile, 1)

' Open file for writing
Set objOFile = objFSO.OpenTextFile(objOUTFile, 8)

Do Until objIFile.AtEndOfStream
strNextLine = objIFile.Readline

'grab the first charachter on the line
strFinder = Left(strNextLine, 1)

If strFinder = "[" Then 'we found our header descriptor
strDescription = Left(strNextLine, Len(strNextLine))

' decend into the list
'we know this one is LastFound date, and we don't care
strLastFound = objIFile.Readline

'we know this one is CountFound, again we don't care for this script
strCountFound = objIFile.Readline

'this one could be blank, or could be LastRemoved, which we need to know
strLastRemoved = objIFile.Readline

If strLastRemoved = "" Then
' This is a blank line, and we need to go throught the loop again
' so do nothing
Else
' it's not a blank line, it's our LastRemoved line and we don't care
' but we need to get to the next line
strCountRemoved = objIFile.Readline

intLen = Len(strCountRemoved)
intEq = InStr(strCountRemoved, "=")
intData = intLen - intEq
intTotal = Right(strCountRemoved, intData)

strLine = strDescription & "=" & intTotal & vbCrlf

'WScript.Echo strLine
objOFile.WriteLine strLine
End If
End If
Loop


objIFile.Close
objOFile.Close

'now delete our original statistics.ini
Set fso = CreateObject("Scripting.FileSystemObject")
fso.CreateTextFile objINFile
Set fso = Nothing


Function GetOS()
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Determines OS by reading reg val & comparing to known values
' OS version number returned as:
' Windows 9X: 0
' Windows NT4: 4
' Windows ME: 4.9
' Windows 2k: 5
' Windows XP: 5.1
' Windows 2003: 5.2
' Windows x: >5.2
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim oShell, sOStype, sOSversion, GetOsVersionNumberReg
Set oShell = CreateObject("Wscript.Shell")


'On Error Resume Next
sOStype = oShell.RegRead(_
"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ProductOptions\ProductType")
If Err.Number<>0 Then
' Hex(Err.Number)="80070002"
' - Could not find this key, OS must be Win9x
Err.Clear
GetOsVersionNumber = 0
Exit Function ' >>>
End If


GetOsVersionNumberReg = oShell.RegRead(_
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentVersion")
If Err.Number<>0 Then
GetOsVersionNumber = "Unknown NTx"
' Could not determine NT version
Exit Function ' >>>
End If


SetLocale "en-us" ' do not remove
GetOsVersionNumber = CSng(GetOsVersionNumberReg)
If GetOsVersionNumber > 49 Then
GetOsVersionNumber = CSng(Replace(GetOsVersionNumberReg, ".", ","))
End If

GetOS=GetOsVersionNumber

End Function



  • This was a quickie script to run files and not alert the user.



'///////////////////////////////////////////////////
'
' Use this script to hide any .exe, .com, .bat, etc.
' from popping up a cmd window. Run in the same directory
' as the executable does not require passing a path.
'
' Keep in mind that if you DO have to pass a path, that
' you enclose ANY spaces in quotations, or use old
' skool DOS charachters to represent Long FileNames,
' like progra~1 for Program Files...
'
'///////////////////////////////////////////////////

Dim oShell
Set oShell = WScript.CreateObject ("WScript.shell")
Set colNamedArguments = WScript.Arguments.Named

If Not colNamedArguments.Exists("FileName") Then
Wscript.Echo "Usage: RunCmdFile /FileName: is required."
Wscript.Quit
End If

oShell.run("%comspec% /c " & FileName),0
Set oShell = Nothing



  • This is a script to change a service account that a group of consultants use for administering domains.



' Create the user. If it exists, change the password
' Object Class Naming attribute
' user cn (Common Name)
' group cn (Common Name)
' computer cn (Common Name)
' container cn (Common Name)
' organizational unit ou (Organizational Unit)
' domain dc (Domain Component)
' --------------------------------------------------------------'
Option Explicit
Dim oOU, oUser, oRoot, oContainer, oSContainer, oContents, oGroup
Dim sContainer, sDomain, sPassword, bFound, sUser, oMyBusiness

sPassword = "mYwAcKyPaSs"
sUser = "consultant"
bFound = "no"

' Bind to Active Directory Domain
On Error Resume Next
Set oRoot = GetObject("LDAP://RootDSE")
If Err.Number <> 0 Then
On Error GoTo 0
' WScript.Echo "No domain found, this is a workstation."

Dim oShell
Set oShell = WScript.CreateObject ("WSCript.shell")
oShell.Run "net user techworks " & sPassword & " /ADD", 0
oShell.Run "net localgroup Administrators techworks /ADD", 0
Set oShell = Nothing

WScript.Quit
End If

sDomain = oRoot.Get("DefaultNamingContext")



Set oContents = GetObject("LDAP://" & sDomain)
For Each oContainer in oContents
' WScript.Echo oContainer.Name

'see if this is an SBS box
If oContainer.Name = "OU=MyBusiness" Then
' WScript.Echo "This might be an SBS box.."
Set oMyBusiness = GetObject("LDAP://" & oContainer.Name & "," & sDomain)
For Each oSContainer in oMyBusiness
If oSContainer.Name = "OU=Users" Then
sSContainer = "OU=SBSUsers,OU=Users,OU=MyBusiness," & sDomain
Set oOu = GetObject("LDAP://" & sSContainer)
For Each oUser in oOU
If oUser.Name = "CN=consultant" Then
bFound = "yes"
' WScript.Echo "Found techworks in " & sSContainer
oUser.SetPassword sPassword
oUser.SetInfo
WScript.Quit
End If
Next
End If
Next
End If


If oContainer.Name="CN=Users" Then
' WScript.Echo "This is not an SBS box."
sContainer=oContainer.Name
Set oOU = GetObject("LDAP://" & sContainer & ", " & sDomain)
For Each oUser in oOU
If oUser.Name = "CN=consultant" Then
bFound = "yes"
' WScript.Echo "Found user in " & sContainer
oUser.SetPassword sPassword
oUser.SetInfo
WScript.Quit
End If
Next
End If
Next

Set oOU = Nothing
Set oContents = Nothing

If bFound = "no" Then
Set oContainer = GetObject("LDAP://CN=Users," & sDomain)
' Build the actual User.
Set oUser = oContainer.Create("User", "CN=" & sUser)
Set oGroup = GetObject("LDAP://CN=Administrators,CN=Builtin," & sDomain)
oUser.Put "sAMAccountName", sUser
oUser.Put "userPrincipalName", sUser
' This will trap an error if the user exists somewhere we
' didn't check
On Error Resume Next
oUser.SetInfo
If Err.Number <> 0 Then
On Error GoTo 0
' debug
' WScript.Echo "This user exists somewhere outside normal CN containers."
' WScript.Echo "You will have to find it and change it manually."
WScript.Quit
End If


' re-use this variable to store the user path, and set the password
Set oUser = Nothing
Set oUser = GetObject("LDAP://CN=" & sUser & ",CN=Users," & sDomain)
oUser.SetPassword sPassword
oGroup.Add(oUser.ADsPath)


' give him info
oUser.Put "givenName", "Consultant"
oUser.Put "sn", "INC"
oUser.Put "displayName", "Consultant Group, INC"
oUser.Put "telephoneNumber", "(555) 555-5555"
oUser.Put "mail", "info@consultantgroup.com"
oUser.Put "wWWHomePage", "http://www.consultantgroup.com"

' enable the account
oUser.AccountDisabled = FALSE


oUser.SetInfo

End If

WScript.Quit

Blog Archive

About Me

My Photo
John Croson
I'm a middle-aged geek, father of two wonderful children, and husband to a saintly wife. I love motorcycles, especially old cafe racers, like the 50's to 70's era racers. Mike "The Bike" Halewood is my hero. I love my job as an IT Manager at IHBSOnline.com. It allows me to use my skills as a technologist. If it weren't for my past retail experience, I'd just be a introverted geek, instead of an outgoing, fun, geeky guy.
View my complete profile
View John Croson\