Task sequence fails with message "Failed to find a valid network adapter"

I recently ran into a problem trying to deploy a TS using boot media. When WinPE booted, I received an error message almost immediately stating: "Failed to find a valid network adapter. Please ensure that this machine has a network adapter and appropiate network drivers. Unspecified error (Error: 80004005; Source: Windows)". If I hit F8 to bring up a command prompt and ran ipconfig /all, I saw an IP address. I was using SCCM 1511 and 1511 ADK with the KB3143760 hotfix applied to the boot image. The client had a “Realtek PCIe GBE Family” NIC and I was using the latest RealTek drivers in my image. After doing some initial research, it seemed that this particular problem has been around for a few years and quite a few people mention the same RealTek NIC.

When WinPE boots, it launches winpeshl.exe, which, in this case, uses the information in the winpeshl.ini file to launch tsbootshell.exe. Tsbootshell.exe in turn launches wpeinit.exe, which, among other things, initializes the network. Tsbootshell.exe then proceeds to run tsmbootstrap.exe, which throws the error about the network adapter not being found. So it appears to be a race condition where tsmbootstrap simply expects the network to be available by the time it launches, which was not happening in this case.

I needed to introduce a pause in the boot sequence to allow the NIC time to come up. Some people suggested a prestart command, but prestart commands actually launch AFTER the network adapter error is thrown, so I needed the pause to be earlier in the boot sequence. Eventually I settled on editing the winpeshl.ini file to run some commands before tsbootshell.exe even launches. Most of the forum postings regarding this issue say to run a “ping –n 30 127.0.0.1 > null”, which would normally give about a 30 second pause. But in my case, the ping command was failing as well. Maybe the ping was trying to run before wpeinit did its thing? Anyway, I've always hated using the ping command as a pause, as it just seems like an inelegant hack. If we were using full Windows 10 here, we could use the choice or timeout commands to introduce a pause, but apparently these commands don't exist in WinPE 10. I could have copied those utilities to a new folder and edited the osdinjection.xml file to include them in the boot image, but that added more overhead with more files to keep track of.

I liked the idea of only editing one file, the winpeshl.ini, so I stuck with that. But if ping wouldn't work and choice and timeout didn't exist, I had to come up with another method.

This is what I came up with (contents of my winpeshl.ini file):

[LaunchApps] %windir%\system32\wpeinit.exe %windir%\system32\cmd.exe, /c echo dim objWMI > %windir%\temp\sleep.vbs %windir%\system32\cmd.exe, /c echo dim colNAS >> %windir%\temp\sleep.vbs %windir%\system32\cmd.exe, /c echo dim intCounter >> %windir%\temp\sleep.vbs %windir%\system32\cmd.exe, /c echo set objWMI = GetObject("winmgmts:\\.\root\cimv2") >> %windir%\temp\sleep.vbs %windir%\system32\cmd.exe, /c echo set colNAS = objWMI.ExecQuery("Select * from Win32_NetworkAdapter where NetConnectionStatus = 2") >> %windir%\temp\sleep.vbs %windir%\system32\cmd.exe, /c echo do while (colNAS.Count ^< 1) >> %windir%\temp\sleep.vbs %windir%\system32\cmd.exe, /c echo if intCounter ^>= 15 then >> %windir%\temp\sleep.vbs %windir%\system32\cmd.exe, /c echo wscript.quit >> %windir%\temp\sleep.vbs %windir%\system32\cmd.exe, /c echo end if >> %windir%\temp\sleep.vbs %windir%\system32\cmd.exe, /c echo wscript.sleep 2000 >> %windir%\temp\sleep.vbs %windir%\system32\cmd.exe, /c echo set colNAS = objWMI.ExecQuery("Select * from Win32_NetworkAdapter where NetConnectionStatus = 2") >> %windir%\temp\sleep.vbs %windir%\system32\cmd.exe, /c echo intCounter = intCounter + 1 >> %windir%\temp\sleep.vbs %windir%\system32\cmd.exe, /c echo loop >> %windir%\temp\sleep.vbs %windir%\system32\cmd.exe, /c echo wscript.quit >> %windir%\temp\sleep.vbs %windir%\system32\cscript.exe, //nologo %windir%\temp\sleep.vbs %SYSTEMDRIVE%\sms\bin\x64\TsBootShell.exe

The first line runs wpeinit.exe, rather than waiting for tsbootshell.exe to run it later on. This starts the process of getting the network ready earlier in the boot process. The next several lines use cmd.exe to echo some VBScript into a .vbs file. The VBScript queries the NetConnectionStatus property of the Win32_NetworkAdapter class every 2 seconds until it finds an adapter with a status of "2", which indicates an active connection. It will loop through this 15 times, which means the script takes about 30 seconds to run (15 times x 2 seconds each time). If a network adapter is found with a connection, the script will exit and move on to allow tsbootshell.exe to execute, which should be successful at this point. If the script fails to find an adapter after 30 seconds, it will exit, tsbootstrap.exe will launch and it will fail with a fairly easy to understand error message (which is why I don't do any error messages in my script).

When WinPE boots and this begins to run, you'll see several command windows open and close very quickly, as each line in the .ini file runs as a separate command. Don't be worried about this. Each command window is only active for a fraction of a second until the last window, which is the one actually running the VBScript. Assuming your network card initializes sometime during the running of the VBScript, the window should close after a few seconds and tsbootshell.exe should launch you into the task sequence wizard.

Now, if you create the custom winpeshl.ini file, you can place it in the \\siteserver\sms_sitecode\OSD\bin\x64 directory and from then on, if you update distribution points for a boot image, or create a new boot image from MDT, or add a boot image, the boot image will get your custom winpeshl.ini file. You can also change the last line of the winpeshl.ini file from “x64\TsBootShell.exe” to “i386\TsBootShell.exe” and put the .ini file in the \\siteserver\sms_sitecode\OSD\bin\i386 folder for x86 boot images.

I'm sure there are tighter, more elegant ways to do what I've done, but I really liked the idea of only editing and maintaining a single file to do everything. If you have a better solution, I'd love to hear about it.

- Matt