I use VMWare extensively in my daily job. Most of these are Windows virtual machines (VMs) that get refreshed on a fairly regular basis. We use the clone feature along with a customization script to refresh a VM. Add a perl script which uses the API to drive this process and it is fairly painless. If a change needs to be made to the VMs, we make the change to the template and the next time the VMs are refreshed, the change is propagated to all of the instances.

Recently, I needed to add a routine scheduled maintenance task to the VMs. Easy enough — I thought. I created the script that would perform the task. Tested it locally. All works. Tested that it works as a scheduled process. Great. Transferred it to a test VM. Performed the same tests. All is going according to plan. I add the script to the templates. I schedule the script to run at the specified times. Double check my work. Now just wait until we refresh the VMs.

After the refresh of the templates, I go to verify that the script is behaving as expected. Nope. Is the script there? Yes. Is the scheduled task there? Yes. Can the scheduled task run? No. Since our customization script creates new security IDs during the clone, the security ID associated with the scheduled tasks (which was valid in the template) is not valid in the cloned instance.

The work around was rather simple. In the customization script, there is an option to set a "Run Once" command that will execute the first time the new virtual machine is powered on. We already use this feature to invoke a batch file to download our latest code and do some configuration based on the machine name. I modified this batch file to use the "at" command to schedule the script. Test again. All looks good. Perform test clone. All looks good. Wait for VMs to refresh. Problem solved.