I recently stumbled onto a somewhat major issue during OSD that is the result of a fundamental (bad) assumption made by many including Windows itself and Internet Explorer. That assumption is that at some point during the deployment of Windows (Windows 7 in this case), an Administrator will log on to the system. This may be during the actual deployment process or maybe right after it is done. Why is this assumption important? Because both Windows setup and Internet Explorer put items in the Windows RunOnce key (HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce) to be run the first time a user logs on. The things that Windows and IE setup put there require elevated permissions however.
Why is this assumption bad? Because the whole point of OSD in ConfigMgr is to be completely hands-off and that the first (and maybe only) user to ever log onto a system has no elevated permissions. Thus, things in RunOnce never run because task sequences in ConfigMgr run in the local SYSTEM context and never actually log into the system via the GINA.
I don’t know all the ramifications of this but it recently manifested itself at a client where we were adding IE 9 to a Windows 7 SP1 deployment. We used the IEAK to create an MSI and tested it manually with the desired results. The problem came in when we tried to add that MSI to either a Build and Capture Task Sequence or a Deployment Task Sequence. The install finished fine, but neither the Start Menu nor Taskbar icon for IE existed anymore. We could manually browse to iexplore.exe and launch it that way proving that the install was fine and of course it was listed in the Updates list under Programs and Features.
After some investigation and a TechNet forum thread pointing the way, I realized what was going on. As Michael Niehaus accurately pointed out also, this isn’t really a new issue but I’ve never seen a negative impact like this one before either. Upon examining the RunOnce key, both before and after IE 9 installation but before a reboot, I discovered no less than six other items listed that were from the base Windows 7 image we had recaptured using a Build and Capture Task Sequence. So, the conclusion is that this is not just an IE problem and it’s not just a Build and Capture issue. So even if you aren’t adding IE and even if you are using LiteTouch to create your image, it’s still possible for things to end up in the RunOnce key that never get executed.
So what’s the solution? In limited testing, the following VBScript seems to do the trick:
Const HKLM = &H80000002
Const REG_SZ = 1
Const REG_EXPAND_SZ = 2
Const REG_BINARY = 3
Const REG_DWORD = 4
Const REG_MULTI_SZ = 7
computer = "."
Set shell = CreateObject("WScript.Shell")
Set registry = GetObject("winmgmts:\\" & computer & "\root\default:StdRegProv")
keyPath = "SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce"
registry.EnumValues HKLM, keyPath, valueNames, valueTypes
If Not IsNull(valueNames) Then
For i = 0 To UBound(valueNames)
text = valueNames(i)
valueName = valueNames(i)
Select Case valueTypes(i)
registry.GetStringValue HKLM, keyPath, valueName, value
WScript.Echo text & ": " & value
returnCode = shell.Run(value, 1, True)
If returnCode = 0 Then
registry.DeleteValue HKLM, keyPath, valueName
What does it do? It simply enumerates each value under the RunOnce key, executes the command-line, and if a success code of 0 is returned from executing the command-line it deletes the value from RunOnce.
Based upon my findings, you should run this is all ConfigMgr OSD task sequences somewhere after the Setup Windows and ConfigMgr task preferably also after any included application installs and after a reboot. If there’s nothing in RunOnce, it’s a no-op.
Here’s a simple little script to install fonts during OSD. Note that this is an example of not doing any manual work during OSD: manual work is un-IT. A quick web search, using Bing of course (Hey, Scripting Guy! How Can I Install Fonts Using a Script- - Hey), and a little scripting knowledge resulted in this VBScript.
Const FONTS = &H14&
Set shell = CreateObject("Shell.Application")
Set fso = CreateObject("Scripting.FileSystemObject")
Set fontsFolder = shell.Namespace(FONTS)
scriptFullName = WScript.ScriptFullName
Set currentFolder = fso.GetFolder (fso.GetParentFolderName(scriptFullName) & "\Fonts")
For Each file In currentFolder.Files
If fso.GetExtensionName(file.Name) = "ttf" Then
WScript.Echo "Installing font: " & file.Path
Dump this is a .vbs file in a ConfigMgr package with a Fonts subfolder containing any fonts that you want to import then simply use a command-line task to call the VBScript; e.g., cscript InstallFonts.vbs.
One possible improvement for this script is to check for the existence of the Font before trying to import it because if it is already imported, a message box will be displayed with an error message which is obviously not a good thing during OSD (note that the message box is actually visible and clickable though so it’s not a show stopper).