Tag Archives: WAIK

Unified Windows PE 3.1 builder script for WAIK, with wifi and EFI support


It’s useful to have wifi support with WPA/WPA2 in Windows PE for occasions where you may want to perform an OS install or a salvage on a machine without ethernet built-in: for instance a MacBook Air running Windows or a Sony Vaio P when you don’t have the breakout dongle to hand.

When I started researching wifi support I found that the people who had clearly got it working seemed to be unwilling to share their work. One tool for the job, Holger’s PE Network Manager did not work for me at all, and judging from the dates of the files it had been created for older versions of Windows PE than the current one. There are many third party Windows PE ‘builder’ apps out there that completely replace the official Microsoft WAIK tools. However these seem more aimed at hobbyists than pros and tend to over complicate by adding features that a deployment pro does not really need. Since they’re not-so-trustworthy compiled binaries I don’t feel comfortable using them for work purposes. I decided to carefully work out for myself which registry entries and which additional files are required. There are surprisingly few.

The following unified script will use the standard WAIK tools to create both x86 and x64 builds, or either one individually, and is designed to be run by double-clicking it. Notice the defined variables at the start, particularly the %SOURCE% folder. The script expects the following folders:

  • %SOURCE%\scripts\WinPE – OS build scripts, wifi config XML, optional CA certificates
  • %SOURCE%\drivers\WinPE-x86\CURRENT – drivers
  • %SOURCE%\drivers\WinPE-x64\CURRENT
  • %SOURCE%\tools\WinPE-x86 – optional tools such as GImageX, or apps from portableapps.com
  • %SOURCE%\tools\WinPE-x64
  • %SOURCE%\tools\WinPE-x86\WLAN – the WLAN system files see highlighted section in main script below
  • %SOURCE%\tools\WinPE-x64\WLAN

It also requires your WAIK installation to be updated to Windows PE 3.1 using the WAIK supplement for Windows 7 SP1.

I had originally wanted to connect WinPE clients to a WPA-Enterprise network but although Windows PE now supports 802.1x, it appears to work only for wired connections (see my comment on that post).

There is no GUI to manage the WLAN service, but I did find the necessary registry mod to enable the hooks already present in netsh.exe. You will need to use a working Windows 7 PC which is configured for the WLAN of your choice, then export its profile. You cannot connect to a wifi network in Windows PE without having done this. The PSK must not be encrypted since it will be imported onto a different machine (you need to run this with Administrator privileges or else the key parameter will be ignored):

netsh wlan show profiles
netsh wlan export profile name="YOURWLANSSIDHERE" folder="C:\temp" key=clear

Copy this XML file into the folder %SOURCE%\scripts\WinPE in the build tree. When Windows PE boots, you simply type wifi. This wifi.cmd script which is built by the main script will automatically import any XML profiles, list the available wifi networks, and display some example netsh syntax:


The script

Save as %SOURCE%\scripts\Build_WinPE.cmd

:: Build_WinPE.cmd
:: This script will build x86 and x64 Windows PE, automatically
:: collecting drivers from the relevant folders within the
:: unattended installation, building WIM and ISO images, and
:: will also upload the WIM images to the deployment server(s).
:: DO NOT cancel this script in progress as you can end up with
:: orphaned locks on files inside mounted WIM images which
:: usually require a reboot of the server to clear.

@echo off

     set SOURCE=G:\unattended
     set PE_TEMP=C:\temp
     ::WinPE feature pack locale
     set PL=en-US
     ::commma separated list for WDS_SERVERS
::end variables

if not exist "C:\Program Files\Windows AIK\Tools\PETools\*.*" (
     echo This script requires the Windows Automatic Install Kit to be installed
     echo Download it from http://www.microsoft.com/download/en/details.aspx?id=5753
     goto :eof
if "%1"=="relaunch" (
     call :BUILD_WINPE %2 %3 %4
     goto :eof
if "%1"=="unmount" (
     :: use this if you have a problem with the script and there are WIMs still mounted
     dism /Unmount-Wim /MountDir:"%PE_TEMP%\WinPE-x86\mount" /discard
     dism /Unmount-Wim /MountDir:"%PE_TEMP%\WinPE-x64\mount" /discard
     goto :eof
set /P SELECTION=Build WinPE for which CPU architecture (x64, x86, both)? [x64]: 
if "%SELECTION%"=="" set SELECTION=x64
if "%SELECTION%"=="x64" (
     start "Building Windows PE for x64 - NEVER CANCEL THIS SCRIPT IN PROGRESS" cmd /c "%0" relaunch x64 amd64
     goto :eof
if "%SELECTION%"=="x86" (
     start "Building Windows PE for x86 - NEVER CANCEL THIS SCRIPT IN PROGRESS" cmd /c "%0" relaunch x86 i386
     goto :eof
if "%SELECTION%"=="b" set SELECTION=both
if "%SELECTION%"=="both" (
     ::opening both instances of this script simultaneously seems to cause race conditions with dism.exe
     start /wait "Building Windows PE for x86 - NEVER CANCEL THIS SCRIPT IN PROGRESS" cmd /c "%0" relaunch x86 i386 nopause
     start "Building Windows PE for x64 - NEVER CANCEL THIS SCRIPT IN PROGRESS" cmd /c "%0" relaunch x64 amd64
     goto :eof
goto :prompt

set PE_ARCH=%1
echo on
set PATH=%PATH%;C:\Program Files\Windows AIK\Tools\PETools\;C:\Program Files\Windows AIK\Tools\%PROCESSOR_ARCHITECTURE%
set PATH=%PATH%;C:\Program Files\Windows AIK\Tools\Servicing
rd /s /q %PE_TEMP%\WinPE-%PE_ARCH%

::Microsoft haven't used consistent naming in WAIK
if "%PE_ARCH%"=="x86" set WAIK_ARCH=%PE_ARCH%
if "%PE_ARCH%"=="x64" set WAIK_ARCH=%PE_ARCH_LONG%

call copype.cmd %WAIK_ARCH% %PE_TEMP%\WinPE-%PE_ARCH%
::package path
set PP=%ProgramFiles%\Windows AIK\Tools\PETools\%WAIK_ARCH%\WinPE_FPs
::image path
set IP=%PE_TEMP%\WinPE-%PE_ARCH%\mount
echo on
dism /Mount-Wim /WimFile:"%PE_TEMP%\WinPE-%PE_ARCH%\winpe.wim" /Index:1 /MountDir:"%IP%"
dism /image:"%IP%" /Add-Package /PackagePath:"%PP%\winpe-scripting.cab" /PackagePath:"%PP%\%PL%\winpe-scripting_%PL%.cab" /PackagePath:"%PP%\winpe-wmi.cab" /PackagePath:"%PP%\%PL%\winpe-wmi_%PL%.cab" /PackagePath:"%PP%\winpe-mdac.cab" /PackagePath:"%PP%\%PL%\winpe-mdac_%PL%.cab" /PackagePath:"%PP%\WinPE-HTA.cab" /PackagePath:"%PP%\%PL%\WinPE-HTA_%PL%.cab" /PackagePath:"%PP%\WINPE-DOT3SVC.CAB" /PackagePath:"%PP%\%PL%\WINPE-DOT3SVC_%PL%.CAB"
dism /image:"%IP%" /Add-Driver /driver:"%SOURCE%\drivers\WinPE-%PE_ARCH%\CURRENT" /Recurse
copy "%ProgramFiles%\Windows AIK\Tools\PETools\%WAIK_ARCH%\bootsect.exe" "%IP%\Windows"
copy /y "%SOURCE%\scripts\WinPE\*.*" "%IP%\Windows\System32"
copy "%SOURCE%\tools\WinPE-%PE_ARCH%\*.*" "%IP%\Windows\System32"
copy "%ProgramFiles%\Windows AIK\Tools\%WAIK_ARCH%\*.*" "%IP%\Windows\System32"

::add WLAN components
reg load HKLM\PE-BUILD-SYSTEM "%IP%\Windows\System32\config\SYSTEM"
reg load HKLM\PE-BUILD-SOFTWARE "%IP%\Windows\System32\config\SOFTWARE"
reg add %KEY% /v NextInstance /t REG_DWORD /d 1 /f
reg add %KEY%\0000 /v Service /t REG_SZ /d Wlansvc /f
reg add %KEY%\0000 /v Legacy /t REG_DWORD /d 1 /f
reg add %KEY%\0000 /v ConfigFlags /t REG_DWORD /d 0 /f
reg add %KEY%\0000 /v Class /t REG_SZ /d LegacyDriver /f
reg add %KEY%\0000 /v ClassGUID /t REG_SZ /d {8ECC055D-047F-11D1-A537-0000F8753ED1} /f
reg add %KEY%\0000 /v DeviceDesc /t REG_SZ /d "@%%SystemRoot%%\System32\wlansvc.dll,-257" /f
set KEY=HKLM\PE-BUILD-SYSTEM\ControlSet001\services\wlansvc
reg add %KEY% /v DisplayName /t REG_SZ /d "@%%SystemRoot%%\System32\wlansvc.dll,-257" /f
reg add %KEY% /v ErrorControl /t REG_DWORD /d 1 /f
reg add %KEY% /v Group /t REG_SZ /d TDI /f
reg add %KEY% /v ImagePath /t REG_EXPAND_SZ /d "%%SystemRoot%%\system32\svchost.exe -k LocalSystemNetworkRestricted" /f
reg add %KEY% /v Start /t REG_DWORD /d 2 /f
reg add %KEY% /v Type /t REG_DWORD /d 32 /f
reg add %KEY% /v Description /t REG_SZ /d "@%%SystemRoot%%\System32\wlansvc.dll,-258" /f
reg add %KEY% /v DependOnService /t REG_MULTI_SZ /d "nativewifip\0RpcSs\0Ndisuio\0Eaphost" /f
reg add %KEY% /v ObjectName /t REG_SZ /d LocalSystem /f
reg add %KEY% /v ServiceSidType /t REG_DWORD /d 1 /f
reg add %KEY% /v RequiredPrivileges /t REG_MULTI_SZ /d "SeChangeNotifyPrivilege\0SeImpersonatePrivilege\0SeAuditPrivilege\0SeTcbPrivilege\0SeDebugPrivilege" /f
reg add %KEY% /v FailureActions /t REG_BINARY /d 2c0100000000000000000000030000001400000001000000c0d4010001000000e09304000000000000000000 /f
reg add %KEY%\Enum /v 0 /t REG_SZ /d "Root\LEGACY_WLANSVC\0000" /f
reg add %KEY%\Enum /v Count /t REG_DWORD /d 1 /f
reg add %KEY%\Enum /v NextInstance /t REG_DWORD /d 1 /f
reg add %KEY%\Parameters /v ServiceDll /t REG_EXPAND_SZ /d "%%SystemRoot%%\System32\wlansvc.dll" /f
reg add %KEY%\Parameters /v ServiceDllUnloadOnStop /t REG_DWORD /d 1 /f
reg add %KEY%\Parameters /v ServiceMain /t REG_SZ /d WlanSvcMain /f
reg add HKLM\PE-BUILD-SOFTWARE\Microsoft\NetSh /v wlancfg /t REG_SZ /d wlancfg.dll /f
call :REG_MULTI_SZ-add "HKLM\PE-BUILD-SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost" LocalSystemNetworkRestricted wlansvc
xcopy /s "%SOURCE%\tools\WinPE-%PE_ARCH%\WLAN\*.*" "%IP%\Windows"
@echo off
:: These are the files that are required for WLAN (take them from Windows 7 machines of both CPU archs)
:: Put them in %SOURCE%\tools\WinPE-%PE_ARCH%\WLAN and create the same relative folder structure from C:\Windows onwards
:: so the file C:\Windows\inf\netnwifi.inf is copied to %SOURCE%\tools\WinPE-%PE_ARCH%\WLAN\inf\netnwifi.inf
::     C:\Windows\inf\netnwifi.inf
::     C:\Windows\inf\netvwififlt.inf
::     C:\Windows\inf\netvwifimp.inf
::     C:\Windows\l2schemas\wlan_policy_v1.xsd
::     C:\Windows\l2schemas\wlan_profile_v1.xsd
::     C:\Windows\l2schemas\wlanap_profile_v1.xsd
::     C:\Windows\schemas\availablenetwork\availablenetworkinfo.xsd
::     C:\Windows\system32\certutil.exe
::     C:\Windows\system32\wlanapi.dll
::     C:\Windows\system32\wlancfg.dll
::     C:\Windows\system32\wlanhlp.dll
::     C:\Windows\system32\wlanmsm.dll
::     C:\Windows\system32\wlansec.dll
::     C:\Windows\system32\wlansvc.dll
::     C:\Windows\system32\wlanui.dll
::     C:\Windows\system32\wlgpclnt.dll
::     C:\Windows\system32\drivers\nwifi.sys
::     C:\Windows\system32\drivers\vwififlt.sys
::     C:\Windows\system32\drivers\vwifimp.sys
::     C:\Windows\system32\en-US\certutil.exe.mui (or your locale's equivalent)
::     C:\Windows\system32\en-us\wlanapi.dll.mui
::     C:\Windows\system32\en-us\wlancfg.dll.mui
::     C:\Windows\system32\en-us\wlansvc.dll.mui
::     C:\Windows\system32\en-us\wlanui.dll.mui
::     C:\Windows\system32\en-us\wlgpclnt.dll.mui
echo on
:: build wifi.cmd
     echo @echo off
     echo drvload X:\WINDOWS\Inf\netvwifimp.inf
     echo drvload X:\WINDOWS\Inf\netvwififlt.inf
     echo drvload X:\WINDOWS\Inf\netnwifi.inf
     echo netcfg -c s -i ms_nativewifip
     echo echo Importing detected CA certificate^(s^).
     echo for %%%%i in ^(*.cer^) do certutil -addstore root %%%%i
     echo echo.
     echo net start dot3svc
     echo net start wlansvc
     echo for %%%%i in ^("Wireless Network Connection*.xml"^) do netsh wlan add profile filename="%%%%i"
     echo netsh wlan show networks
     echo echo.
     echo echo use "netsh wlan" to manage the wifi connection like so:
     echo echo   netsh wlan connect name=YOURWLANHERE ssid=YOURWLANHERE
     echo echo   ipconfig /renew
     echo echo.
) > "%IP%\Windows\System32\wifi.cmd"

dism /Unmount-Wim /MountDir:"%IP%" /commit
imagex /export /boot /compress fast "%PE_TEMP%\WinPE-%PE_ARCH%\winpe.wim" 1 "%PE_TEMP%\WinPE-%PE_ARCH%\ISO\sources\boot.wim"
@echo off

::Mac OS BootCamp will look for autorun.inf in order to validate this disk as a Windows Installer CD
::adding this allows us to start unattended installs using WinPE
date /T > "%PE_TEMP%\WinPE-%PE_ARCH%\ISO\autorun.inf"

::x64 bootable ISO includes both BIOS & EFI boot loaders
if "%PE_ARCH%" == "x64" (
     set CD_CMD=oscdimg -m -o -u2 -udfver102 -bootdata:2#p0,e,b"%PE_TEMP%\WinPE-%PE_ARCH%\etfsboot.com"#pEF,e,b"%PE_TEMP%\WinPE-%PE_ARCH%\efisys.bin" "%PE_TEMP%\WinPE-%PE_ARCH%\ISO" "%PE_TEMP%\WinPE-%PE_ARCH%\winpe_%PE_ARCH_LONG%.iso"
) else ( 
     set CD_CMD=oscdimg -n -b"%PE_TEMP%\WinPE-%PE_ARCH%\etfsboot.com" "%PE_TEMP%\WinPE-%PE_ARCH%\ISO" "%PE_TEMP%\WinPE-%PE_ARCH%\winpe_%PE_ARCH_LONG%.iso"
echo on
@echo off

::rename the WIM file to avoid having multiple image files on the WDS server with the same filename
ren "%PE_TEMP%\WinPE-%PE_ARCH%\ISO\sources\boot.wim" boot_%PE_ARCH_LONG%.wim
del "%PE_TEMP%\WinPE-%PE_ARCH%\winpe.wim"

for %%i in (%WDS_SERVERS%) do (
     echo Adding/updating boot image on WDS server: %%i
     :: try to add the image first, if that fails then replace existing
     wdsutil /Verbose /Progress /Add-Image /ImageFile:"%PE_TEMP%\WinPE-%PE_ARCH%\ISO\sources\boot_%PE_ARCH_LONG%.wim" /Server:%%i /ImageType:Boot /Name:"Microsoft Windows PE (%PE_ARCH%)" || wdsutil /Verbose /Progress /Replace-Image /Image:"Microsoft Windows PE (%PE_ARCH%)" /ImageType:Boot /Architecture:%PE_ARCH% /ReplacementImage /Name:"Microsoft Windows PE (%PE_ARCH%)" /ImageFile:"%PE_TEMP%\WinPE-%PE_ARCH%\ISO\sources\boot_%PE_ARCH_LONG%.wim" /Server:%%i
::rename the WIM back again so bootable USB devices can be created
ren "%PE_TEMP%\WinPE-%PE_ARCH%\ISO\sources\boot_%PE_ARCH_LONG%.wim" boot.wim
echo *******************************************************************
echo WDS boot image(s) updated
echo A bootable ISO of this image has been created at:
echo   %PE_TEMP%\WinPE-%PE_ARCH%\winpe_%PE_ARCH_LONG%.iso
echo To create a bootable USB key, use diskpart.exe to create a FAT32 partition
echo and mark it active, then copy the contents of this folder to its root:
echo   %PE_TEMP%\WinPE-%PE_ARCH%\ISO
echo FAT32 is required for EFI support.
if "%3"=="nopause" goto :eof
goto :eof

::subroutine to append a value to a multiple string value Registry entry
set KEY=%1
set VALUE=%2
for /f "tokens=2*" %%a in ('reg query %KEY% /v %VALUE% /t REG_MULTI_SZ ^| FIND "REG_MULTI_SZ"') do set DATA=%%b
set DATA=%DATA%\0%3
reg add %KEY% /v %VALUE% /t REG_MULTI_SZ /d %DATA% /f

Maintaining a consistent Windows PE build

UPDATE – new much improved script here.

Having a WDS server with a bootable Windows PE instance is extremely useful. Got a server into a reboot loop by deleting a driver you were sure was inactive? Run out of space on C: and need to image and repartition? OS won’t boot but you need to salvage files? You get the picture. They key though, is making sure you’ve integrated all the network and mass storage controller drivers your hardware will need.

One of the most useful tools that’s not included in the image by default is ImageX – the tool for reading and writing WIM images. Pair this up with the GUI wrapper GImageX and you’ve got yourself a free replacement for Ghost.

Once you’ve downloaded WAIK, making a Windows PE build is a pain – there’s so much messy syntax to get right. Since you’re likely to keep needing to rebuild it to add more drivers, it’s a good idea to write a script to rebuild it from scratch each time. Here’s my build_pe_amd64.cmd:

set PATH=%PATH%;C:\Program Files\Windows AIK\Tools\PETools\;C:\Program Files\Windows AIK\Tools\%PROCESSOR_ARCHITECTURE%
set PATH=%PATH%;C:\Program Files\Windows AIK\Tools\Servicing
del c:\temp\pe_amd64\ISO\sources\boot.wim
del c:\temp\pe_amd64\winpe_amd64.iso
rd /s /q c:\temp\pe_amd64
call copype.cmd amd64 c:\temp\pe_amd64
dism /Mount-Wim /WimFile:c:\temp\pe_amd64\winpe.wim /Index:1 /MountDir:c:\temp\pe_amd64\mount
dism /image:c:\temp\pe_amd64\mount /Add-Package /PackagePath:"%ProgramFiles%\Windows AIK\Tools\PETools\amd64\WinPE_FPs\winpe-scripting.cab"
dism /image:c:\temp\pe_amd64\mount /Add-Package /PackagePath:"%ProgramFiles%\Windows AIK\Tools\PETools\amd64\WinPE_FPs\en-us\winpe-scripting_en-us.cab"
dism /image:c:\temp\pe_amd64\mount /Add-Package /PackagePath:"%ProgramFiles%\Windows AIK\Tools\PETools\amd64\WinPE_FPs\winpe-wmi.cab"
dism /image:c:\temp\pe_amd64\mount /Add-Package /PackagePath:"%ProgramFiles%\Windows AIK\Tools\PETools\amd64\WinPE_FPs\en-us\winpe-wmi_en-us.cab"
dism /image:c:\temp\pe_amd64\mount /Add-Package /PackagePath:"%ProgramFiles%\Windows AIK\Tools\PETools\amd64\WinPE_FPs\winpe-mdac.cab"
dism /image:c:\temp\pe_amd64\mount /Add-Package /PackagePath:"%ProgramFiles%\Windows AIK\Tools\PETools\amd64\WinPE_FPs\en-us\winpe-mdac_en-us.cab"
dism /image:c:\temp\pe_amd64\mount /Add-Package /PackagePath:"%ProgramFiles%\Windows AIK\Tools\PETools\amd64\WinPE_FPs\WinPE-HTA.cab"
dism /image:c:\temp\pe_amd64\mount /Add-Package /PackagePath:"%ProgramFiles%\Windows AIK\Tools\PETools\amd64\WinPE_FPs\en-us\WinPE-HTA_en-us.cab"
dism /image:c:\temp\pe_amd64\mount /Add-Driver /driver:%SOURCE%\common\vmxnet3\vmxnet3ndis5.inf
dism /image:c:\temp\pe_amd64\mount /Add-Driver /driver:%SOURCE%\x64\pvscsi\pvscsi.inf
dism /image:c:\temp\pe_amd64\mount /Add-Driver /driver:%SOURCE%\x64\perc4esi\oemsetup.inf
dism /image:c:\temp\pe_amd64\mount /Add-Driver /driver:%SOURCE%\x64\lsi_sas\lsi_sas.inf /forceunsigned
dism /image:c:\temp\pe_amd64\mount /Add-Driver /driver:%SOURCE%\x64\nc373i_ris\b06nd.inf
dism /image:c:\temp\pe_amd64\mount /Add-Driver /driver:%SOURCE%\x64\sa_5x6x\hpcisss.inf
dism /image:c:\temp\pe_amd64\mount /Add-Driver /driver:%SOURCE%\x64\sa_p400\hpcissx2.inf
dism /image:c:\temp\pe_amd64\mount /Add-Driver /driver:%SOURCE%\x64\yk62\yk62x64.inf
copy "%ProgramFiles%\Windows AIK\Tools\PETools\amd64\bootsect.exe" c:\temp\pe_amd64\mount\Windows
copy /y %SOURCE%\common\*.cmd c:\temp\pe_amd64\mount\Windows\System32
copy "%SOURCE%\x64\Tools\*.*" c:\temp\pe_amd64\mount\Windows\System32
copy "%ProgramFiles%\Windows AIK\Tools\amd64\*.*" c:\temp\pe_amd64\mount\Windows\System32
md c:\temp\pe_amd64\mount\scripts
::script for launching my unattended OS installer
copy \\myserver\unattended\scripts\init.vbs c:\temp\pe_amd64\mount\scripts
dism /Unmount-Wim /MountDir:c:\temp\pe_amd64\mount /commit
imagex /export c:\temp\pe_amd64\winpe.wim 1 c:\temp\pe_amd64\ISO\sources\boot.wim
::uncomment the following line to build a bootable ISO image
::oscdimg -n -bc:\temp\pe_amd64\etfsboot.com c:\temp\pe_amd64\ISO c:\temp\pe_amd64\winpe_amd64.iso
ren c:\temp\pe_amd64\ISO\sources\boot.wim boot_amd64.wim
WDSUTIL /Verbose /Progress /Replace-Image /Image:"Microsoft Windows PE 3.0 (x64)" /ImageType:Boot /Architecture:x64 /ReplacementImage /Name:"Microsoft Windows PE 3.0 (x64)" /ImageFile:"c:\temp\pe_amd64\ISO\sources\boot_amd64.wim"
ren c:\temp\pe_amd64\ISO\sources\boot_amd64.wim boot.wim