Automating Dual-Boot Lab Deployments at RMU

RMU just finished construction on its newest campus building for the School of Communications and Information Systems. The University's CIS department teaches a computer forensics course in which they expose students to forensic tools and procedures on both Mac and Windows platforms. In addition, students have requested a greater Mac availability on campus. For those reasons, the IT department decided that for the new building's special purpose lab, it would purchase iMacs from Apple and dual-boot them with OS X Mt. Lion and Windows 7. This proved to be both a much more elegant and cost effective solution than purchasing both a PC and a Mac for each workstation. It avoided clumsy and expensive KVM switches as well. With our decision came an interesting challenge for me: How can we reliably image a dual-boot lab in a repeatable and mostly automated manner?

Below I've outlined what I came up with. It worked incredibly well, although not without some initial trial and error.
The Tools

- Apple BootCamp drivers package

- SetupComplete.cmd as part of the Windows sysprep process

- run-winsat.cmd

- A Windows 7 disk to repair the missing BOOTMGR

- DeployStudio

- A first boot script installed on the Mac side and run by DeployStudio

- BootPicker

- Munki

The Windows Image
I worked together with Jimmy, our Windows sys admin in charge of Windows imaging, to prep the image that we used for the Windows side of the Macs. Thankfully he had already assembled the base lab image for campus, so we just needed to tweak it a bit to work for the dual-boot deployment.
Apple BootCamp Drivers
The most important modification we made was the inclusion of the BootCamp Drivers from Apple. Of course, for Windows to run reliably on a Mac, these are needed. You can download the latest BootCamp ESD from Apple by finding its URL in Apple's software update catalog. We placed the extracted folder in C:\Windows\BootCamp without making any modifications.
SetupComplete.cmd
If you use sysprep, you're probably familiar with SetupComplete.cmd. If not, there's technical documentation from Microsoft available here. This script runs as part of the last step of the sysprep process immediately after Windows setup completes. In our SetupComplete.cmd, we added the following lines (each called as a separate command to avoid race conditions):
c:\windows\System32\cmd.exe /c c:\windows\System32\reg.exe ADD HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce /v RunWinsat /t REG_SZ /d "c:\windows\Setup\scripts\run-winsat.cmd" /f
c:\windows\System32\cmd.exe /c c:\windows\system32\Msiexec.exe /i c:\windows\BootCamp\Drivers\Apple\BootCamp.msi /qn /norestart /log "%SystemDrive%\Windows\BootCamp\BootCamp_Install.log"
c:\windows\System32\cmd.exe /c move C:\Windows\System32\drivers\AppleHFS.sys C:\Windows\System32\drivers\AppleHFS.sys.donotuse
c:\windows\System32\cmd.exe /c move C:\Windows\System32\drivers\AppleMNT.sys C:\Windows\System32\drivers\AppleMNT.sys.donotuse
  1. The first line tells the machine to run another script, run-winsat.cmd (detailed below) during the Admin user's first login.
  2. The second line tells msiexec.exe to install the BootCamp drivers, logging to C:\Windows\BootCamp\BootCamp_Install.log. We found that calling the Apple BootCamp msi is the best way to install the BootCamp drivers on a Mac. Apple's msi handles all of the hardware probing and only installs the necessary drivers for that particular machine.
  3. The third and fourth lines simply rename the Apple HFS related drivers so that they are not used. We didn't want the Mac partition to mount on the Windows side of the machine for security reasons.
run-winsat.cmd
Because the windows assessment tool runs during sysprep before the BootCamp drivers are installed, its assessment of the machine is not accurate. To fix this, we run winsat a second time on the Admin user's first login through the use of the run-winsat script. Below is the contents of run-winsat.cmd:
winsat formal
"%ProgramFiles%\Boot Camp\Bootcamp.exe" -StartupDisk
This script simply calls winsat formal and then uses the BooCamp executable to set the default startup disk to the Mac partition. Because the BootCamp drivers have been installed by this point, the second winsat assessment is accurate and Aero becomes enabled as a result.
Capturing the Windows Image and Fixing the Missing BOOTMGR
I used DeployStudio to capture the sysprep'd image with the modifications mentioned above included. But by default, Windows 7 stores its boot manager on a separate partition. This resulted in a "BOOTMGR Missing" error after restoring the captured image to a Mac. Because BootCamp needs all of the Windows files to reside on a single partition, it was necessary for me to "fix" the "BOOTMGR Missing" error using Startup Repair located on a Windows 7 installation DVD. After I fixed the error, I recaptured the image a second time with DeployStudio. This second capture restored and booted properly. Both captures were done with the ntfs tools included with DeployStudio. The option to use Apple's built-in tools (asr) for the NTFS captures just never worked properly for us.
The Mac Image

The Mac image required nothing special to work properly. For the fall term, using InstaDMG, I created a 10.8 GM 12A269 image with iLife '11 included.
The First Boot Script
Part of our DeployStudio workflow includes running a first boot script. The entire workflow is detailed next, but these are the relevant lines from the first boot script related to the BootCamp customization:
#Begin Bootcamp customization
$echo "Beginning Bootcamp customization... checking for BOOTCAMP partition"
$diskutil info BOOTCAMP > /dev/null 2>&1
if [ $? = 0 ]; then
        $echo "BOOTCAMP partition found!"
        BOOTCAMPNODE=$($diskutil info BOOTCAMP | $awk '/Device Node/ {print $3}')
        $echo "Got BOOTCAMP Node..."
        $sleep 1
        BOOTCAMPUUID=$($diskutil info BOOTCAMP | $awk '/Volume UUID/ {print $3}')
        $echo "Got BOOTCAMP UUID..."
        $sleep 1
        $echo "Modifying /etc/fstab to not mount the BOOTCAMP volume on boot..."
        $echo "UUID=$BOOTCAMPUUID  none  ntfs  ro,noauto" > /etc/fstab
        $echo "Done!"
        $echo ""
        $echo "Writing bootpicker preference file with the BOOTCAMP device location..."
        $defaults write /Library/Preferences/bootpicker windowsPartition "$BOOTCAMPNODE"
        $echo "Done."
else
        $echo "No BOOTCAMP partition found! Continuing..."
fi
I didn't want to have a separate script to run in dual-boot labs, so I added a check to see if the BOOTCAMP partition is present on the machine. If so, it performs the customization, and if not, it simply continues. This allows us to use the same first boot script on every Mac. The customization adds the BOOTCAMP volume to /etc/fstab with the option to not automatically mount. We didn't want the Windows partition to mount when booted into OS X for security reasons. The customization also writes to the BootPicker preference file to tell it which partition is the Windows partition. Note that we capture the device ID and not the volume name. BootPicker does a sanity check, and if you use a volume name of a volume that isn't mounted, BootPicker will not display over the login window. By using the device ID, we were able to work around that.
DeployStudio Workflow

DeployStudio really was the brains of the operation. Our workflow included the following tasks, in the following order:
  1. Partitioning task for 160 GB Windows partition and the rest a Mac partition named RMU Workstation (Automated: Yes)
  2. Multicast Restore task for the Mac image to the RMU Workstation partition (Automated: Yes)
  3. Restore task for the Windows image to the Windows partition (Automated: No. Since it's unicast, we only would image a few at a time). 
  4. Set the Windows partition to the default startup disk.
  5. Hostname form (Automated: No. We need to type in the name.)
  6. Generic Task to rename the computer on the Mac side (Automated: Yes)
  7. Install munkitools on the Mac side (Automated: Yes)
  8. Install the munki configuration file for the lab on the Mac side (Automated: Yes)
  9. Bind the machine to Open Directory on the Mac side for MCX management  (Automated: Yes)
  10. Bind the machine to Active Directory on the Mac side  (Automated: Yes)
  11. Enable the Firmware security when trying to use the startup manager (Automated: Yes. This is a new lab. The machines needed the firmware password.)
The Boot Process

After the workflow completes, the boot process goes something like this:
  1. Because we set the Windows partition to be the primary boot volume, the Mac first boots into Windows and begins the sysprep process with our customizations included.
  2. The machine reboots again to Windows and we login as the Admin user.
  3. Our run-winsat script runs and Aero is enabled and the default startup disk is then set to the Mac partition.
  4. We reboot the machine and then the DeployStudio finalize script runs and installs our munki packages, binds to the directories, and runs our first boot script with the customizations detailed earlier.
  5. The machine reboots after the DeployStudio finalize script is finished.
  6. After the reboot, Munki is set to be in bootstrap mode and begins installing the appropriate software on the Mac for the lab, including BootPicker and packages to update the BootPicker images and customize the text shown on the BootPicker window.
BootPicker

Although officially discontinued, BootPicker still functions on OS X 10.8 Mt. Lion. Tim Perfitt is working on a replacement called BootRunner, but it's not quite ready for release. The problem we faced with BootPicker is that because it was developed so long ago, by default, the BootPicker window shows a Leopard desktop and a Windows XP desktop. Fortunately these images are replaceable and not compiled within the application's interface file. I made a package that replaces the images (located at /Applications/Utilities/BootPicker.app/Contents/Resources/) with new ones for OS X 10.8 Mt. Lion and Windows 7. Our BootPicker text customization is done with a payload free package that runs a script that writes the appropriate lines to /Library/Preferences/bootpicker.plist. We would just install a file, but we need the process to be dynamic and work with the customization done via our first boot script. Because that script runs first and writes the device ID to the BootPicker preference file, if we installed a bootpicker.plist file with a package, that already completed customization would be lost.
Final Thoughts

Although initially a bit of a challenge, everything came together smoothly. The workflow worked every single time, and the lab of 30 machines is sitting at the login window waiting for student use for the first time tomorrow morning. I would like to thank Nate Felton from RIT and Tim Sutton from Concordia University in Montreal, Quebec for their input on our process. Nate showed us an alternative way to install the BootCamp drivers (which we ended up not using in the end), and Tim Sutton reminded us that winsat needs to be run a second time after the BootCamp drivers have been installed.
Often times I read about sys admins having time synchronization problems with dual-boot Mac labs. So far in my testing, I haven't noticed that. The Windows side of the machine pulls its time from the AD domain controllers, and the Mac side uses NTP connected to the University's NTP servers. Ideally, that should keep the time in sync and allow for properly functioning kerberos across both platforms.
Please feel free to share your thoughts, comments, and suggestions. We're always looking to improve our processes and we'd love to hear how other people are deploying dual-boot labs. If this write-up helps you in any way, we'd love to know that too!

2577 views and 7 responses

  • Jan 1 2013, 9:07 PM
    JE responded:
    "I made a package that replaces the images (located at /Applications/Utilities/BootPicker.app/Contents/Resources/) with new ones for OS X 10.8 Mt. Lion and Windows 7. Our BootPicker text customization is done with a payload free package that runs a script that writes the appropriate lines to /Library/Preferences/bootpicker.plist. "

    Would you mind sharing in greater detail exactly the process you went through to create this customisation of Bootpicker? Thanks very much.

  • Jan 3 2013, 5:24 PM
    Mike Boylan responded:
    Hi JE, sorry for the delayed response.

    Inside of BootPicker.app (right click and show contents...) is the folder structure Contents/Resources/. Inside that directory are two image files... one for Windows and one for OS X. You can replace those with your own to update the images. I made a package that had a payload of those two images with a destination path of /Applications/Utilities/BootPicker.app/Contents/Resources/.

    As for the script... I made a payload-free package that included a postinstall (or postflight? can't remember at the moment) script that ran a few defaults write commands to set the key values for BootPicker. Something like defaults write /Library/Preferences/bootpicker title "Welcome to Lab 123!".

    Hope that's helpful.

  • Jan 11 2013, 11:54 AM
    Russell responded:
    Good article and thanks for the Boot Runner mention. BR is out now and can be customized/automated with the bootrunner .plist file. twocanoes.com/boot-runner
  • Jan 13 2013, 9:07 PM
    Dan responded:
    Hi Mike,

    Please excuse the following ignorance, ive only just started working with Macs ( windows sys admin here)

    Ive been tasked to set up dual boot for OSX 10.8 /Windows 7, everything is working fine, i set up dual boot with a similar way to you.

    I would also like to change the bootpicker images, what i dont know how to do is compile a basic .pkg to copy the new images across, are you able to give me any guidance in this area?

    Also i would love to be able to have bootpicker automatically display the computers hostname and i would also like to change the welcome message, any help in this would be appreciated.

    Regards,

    Dan

  • Jan 17 2013, 9:58 PM
    Mike Boylan responded:
    Hi Dan,

    Since you're new to OS X and packaging, I would take a look at Packages from Stephanie Sudre. It's a decently simple GUI that could help you accomplish this task. http://s.sudre.free.fr/Software/Packages/about.html After that, I'd take a look at The Luggage by Joe Block. It's my favorite tool for packaging. That being said, for this particular package, I actually used Jamf's Composer tool. It literally took me a few seconds to build as it watched the filesystem for changes while I just dragged the two new images into place.

    BootPicker's welcome message cannot be (easily) changed, but the title can be by changing the value for "title" in the plist. It wouldn't be easily possible to add the hostname either as far as I know. Tim Sutton (http://macops.ca @tvsutton) has done some work on modifying the GUI for BootPicker. You may want to reach out to him for some additional assistance. I think he's removed the welcome message all together, come to think of it.

    Hope this is helpful!

  • Jan 18 2013, 6:40 PM
    Ryan Stasel responded:
    Mike,

    Good article, thanks! I guess my only question is, why no answer file (unattend.xml) for sysprep? I did a test restore, and was greeted by all the "name computer", "create user", crap. I just want to image and be done with it. Only wish DS had the ability to rename the windows side (so I won't have to do it manually).

    Thanks again! I'll be referring to this, and this: http://www.edugeek.net/forums/o-s-deployment/75778-sysprep-answer-file-window... on Tuesday when I finalize the image. =)

  • Jan 19 2013, 12:49 PM
    Mike Boylan responded:
    Ryan,

    I didn't mention it in the article because I don't manage that part of the deployment, but I believe our sysprep process does include an unattended.xml file.

    DeployStudio does actually have the ability to rename the Windows side of a bootcamp deployment, but I've never actually tried to use it. I imagine there are very specific requirements for it to work.

    Glad this was helpful to you!

    - Mike