Tag Archives: deployment

Unified Windows PE 4.0 builder for Windows ADK

This script will build Windows PE 4.0 (for x86, or AMD64 or both) including scripts and drivers of your choosing, it will create ISO images with both BIOS and UEFI support, and will also upload the resulting WIM boot images to your WDS server automatically (and freshen them if they have been re-created). This reduces the tiresome task of boot image maintenance to just a couple of clicks.

It uses only the standard Microsoft Windows ADK tools, which is the new name for WAIK. Just save the code below as Build_WinPE.cmd and right-click on it to Run as Administrator. Notice the defined variables at the start, particularly the %SOURCE% folder. It supports using either the 32bit or the 64bit ADK, and only the Windows PE and Deployment Tools ADK components are required. The script expects the following folders:

  • %SOURCE%\scripts\WinPE – any additional scripts (e.g. OS build scripts)
  • %SOURCE%\drivers\WinPE-x86\CURRENT – drivers
  • %SOURCE%\drivers\WinPE-AMD64\CURRENT
  • %SOURCE%\tools\WinPE-x86 – optional tools such as GImageX, or apps from portableapps.com
  • %SOURCE%\tools\WinPE-AMD64

Notice the optional components section at lines 90-95. Modify this if you need your image to contain additional items, for instance PowerShell or .NET Framework 4.

One further observation is that Macs don’t seem to be able to boot this version of Windows PE. I’m not sure whether this is a GOP display driver issue, or whether only true UEFI firmwares are required (Macs are EFI which is an earlier specification). To carry out an unattended Windows 8 install on a Mac via BootCamp you will need to build a Windows PE 3.0 ISO since Macs can’t PXE boot.

There’s some more info about UEFI booting on 32bit architectures here – apparently UEFI 2.3.1 compliance is a requirement. My VAIO’s Insyde H2O UEFI firmware certainly seems to ignore EFI loaders.

:: Build_WinPE.cmd
::
:: patters 2012
::
:: This script will build x86 and AMD64 Windows PE 4.0, 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
setlocal ENABLEDELAYEDEXPANSION

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

if "%PROCESSOR_ARCHITECTURE%"=="x86" set PRGFILES32=%PROGRAMFILES%
if "%PROCESSOR_ARCHITECTURE%"=="AMD64" set PRGFILES32=%PROGRAMFILES(X86)%

if not exist "%PRGFILES32%\Windows Kits\8.0\Assessment and Deployment Kit\Deployment Tools\*.*" (
     echo This script requires the Windows Assessment and Deployment Kit to be installed
     echo Download it from http://www.microsoft.com/en-us/download/details.aspx?id=30652
     echo.
     pause
     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-AMD64\mount" /discard
     goto :eof
)
:prompt
cls
set /P SELECTION=Build WinPE for which CPU architecture (AMD64, x86, both)? [AMD64]: 
if "%SELECTION%"=="" set SELECTION=AMD64
if "%SELECTION%"=="amd64" set SELECTION=AMD64
if "%SELECTION%"=="X86" set SELECTION=x86
if "%SELECTION%"=="b" set SELECTION=both
if "%SELECTION%"=="BOTH" set SELECTION=both
if "%SELECTION%"=="AMD64" (
     start "Building Windows PE for AMD64 - NEVER CANCEL THIS SCRIPT IN PROGRESS" cmd /c "%0" relaunch AMD64
     goto :eof
)
if "%SELECTION%"=="x86" (
     start "Building Windows PE for x86 - NEVER CANCEL THIS SCRIPT IN PROGRESS" cmd /c "%0" relaunch x86
     goto :eof
)
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 nopause
     start "Building Windows PE for AMD64 - NEVER CANCEL THIS SCRIPT IN PROGRESS" cmd /c "%0" relaunch AMD64
     goto :eof
)
goto :prompt

:BUILD_WINPE
set PE_ARCH=%1
set OSCDImgRoot=%PRGFILES32%\Windows Kits\8.0\Assessment and Deployment Kit\Deployment Tools\%PROCESSOR_ARCHITECTURE%\Oscdimg
set WinPERoot=%PRGFILES32%\Windows Kits\8.0\Assessment and Deployment Kit\Windows Preinstallation Environment
set DandIRoot=%PRGFILES32%\Windows Kits\8.0\Assessment and Deployment Kit\Deployment Tools
set DISMRoot=%PRGFILES32%\Windows Kits\8.0\Assessment and Deployment Kit\Deployment Tools\%PROCESSOR_ARCHITECTURE%\DISM
set PATH=%PATH%;%PRGFILES32%\Windows Kits\8.0\Assessment and Deployment Kit\Deployment Tools\%PROCESSOR_ARCHITECTURE%\Oscdimg
set PATH=%PATH%;%PRGFILES32%\Windows Kits\8.0\Assessment and Deployment Kit\Deployment Tools\%PROCESSOR_ARCHITECTURE%\BCDBoot
set PATH=%PATH%;%PRGFILES32%\Windows Kits\8.0\Assessment and Deployment Kit\Deployment Tools\%PROCESSOR_ARCHITECTURE%\DISM
set PATH=%PATH%;%PRGFILES32%\Windows Kits\8.0\Assessment and Deployment Kit\Windows Preinstallation Environment
echo on
rd /s /q %PE_TEMP%\WinPE-%PE_ARCH%
call copype.cmd %PE_ARCH% %PE_TEMP%\WinPE-%PE_ARCH%
::package path
set PP=%PRGFILES32%\Windows Kits\8.0\Assessment and Deployment Kit\Windows Preinstallation Environment\%PE_ARCH%\WinPE_OCs
::image path
set IP=%PE_TEMP%\WinPE-%PE_ARCH%\mount
echo on
dism /Mount-Wim /WimFile:"%PE_TEMP%\WinPE-%PE_ARCH%\media\sources\boot.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 "%PRGFILES32%\Windows Kits\8.0\Assessment and Deployment Kit\Deployment Tools\%PE_ARCH%\BCDBoot\bootsect.exe" "%IP%\Windows"
copy /y "%SOURCE%\scripts\WinPE\*.*" "%IP%\Windows\System32"
copy "%SOURCE%\tools\WinPE-%PE_ARCH%\*.*" "%IP%\Windows\System32"
copy /y "%PRGFILES32%\Windows Kits\8.0\Assessment and Deployment Kit\Deployment Tools\%PE_ARCH%\DISM\imagex.exe" "%IP%\Windows\System32"
dism /Unmount-Wim /MountDir:"%IP%" /commit

::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%\media\autorun.inf"

::bootable ISO includes both BIOS & EFI boot loaders
oscdimg -m -o -u2 -udfver102 -bootdata:2#p0,e,b"%PE_TEMP%\WinPE-%PE_ARCH%\fwfiles\etfsboot.com"#pEF,e,b"%PE_TEMP%\WinPE-%PE_ARCH%\fwfiles\efisys.bin" "%PE_TEMP%\WinPE-%PE_ARCH%\media" "%PE_TEMP%\WinPE-%PE_ARCH%\WinPE-40-%PE_ARCH%.iso"
@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%\media\sources\boot.wim" boot_%PE_ARCH%.wim

if "%PE_ARCH%"=="x86" set WDS_ARCH=%PE_ARCH%
if "%PE_ARCH%"=="AMD64" set WDS_ARCH=X64
for %%i in (%WDS_SERVERS%) do (
     echo.
     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%\media\sources\boot-40-%PE_ARCH%.wim"^
      /Server:%%i /ImageType:Boot /Name:"Microsoft Windows PE 4.0 (%PE_ARCH%)" || wdsutil /Verbose /Progress /Replace-Image^
      /Image:"Microsoft Windows PE 4.0 (%PE_ARCH%)" /ImageType:Boot /Architecture:%WDS_ARCH% /ReplacementImage^
      /Name:"Microsoft Windows PE 4.0 (%PE_ARCH%)" /ImageFile:"%PE_TEMP%\WinPE-%PE_ARCH%\media\sources\boot-40-%PE_ARCH%.wim"^
      /Server:%%i
     echo.
)
::rename the WIM back again so bootable USB devices can be created
ren "%PE_TEMP%\WinPE-%PE_ARCH%\media\sources\boot-40-%PE_ARCH%.wim" boot.wim
echo *******************************************************************
echo WDS boot image(s) updated
echo.
echo A bootable ISO of this image has been created at:
echo   %PE_TEMP%\WinPE-%PE_ARCH%\WinPE-40-%PE_ARCH%.iso
echo.
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%\media
echo.
echo FAT32 is required for EFI support.
echo.
if "%2"=="nopause" goto :eof
pause
goto :eof

Deploying Windows Photo Gallery 2012

Windows-Photo-Gallery

Though it seems primarily pitched at home users, Microsoft’s Windows Photo Gallery is a useful image management tool even in a professional environment. It’s distributed as part of a suite of software known collectively as Windows Essentials 2012. I don’t understand why these tools aren’t included in Windows itself, but since they were until recently part of the Live family I’m presuming that they were designed to encourage the use of Microsoft’s online services. The apparent home user bias to the setup (a single installer for the whole suite, which downloads on demand, which asks for a Live sign-in, and which alters homepage and search provider) consequently makes Photo Gallery quite difficult to deploy and automate.

Firstly the proper offline installer package is tucked away here on Microsoft’s website.

The next issue is that the silent install switches don’t seem to be officially documented by Microsoft. I was able to piece together the working command line using a TechNet forum post, this blog post about deploying the 2011 version, and some stuff on the MSFN forum.

What held me up for a while is that you can no longer target only the Photo Gallery app – MovieMaker and Photo Gallery are bundled together with 2012. So I arrived at this one-liner which I invoke from a more complex workstation startup script, if it’s needed:

start /wait WLSetup-all.exe /q /r:n /NOToolbarCEIP /NOhomepage /nolaunch /nosearch /AppSelect:MovieMaker /log:%TEMP%\WLEsetup.log

The HKCU registry customizations are pretty much the same as for the 2011 version, so to suppress the EULA and Microsoft account sign-in prompt, and to prevent nags about file type associations you will need to set the following in your login script (this is an extract from my VBScript one, but it’s pretty human-readable):

...
'default preferences for Microsoft Photo Library (agree EULA, don't steal filetype associations, no Windows Live sign-in)
objReg.CreateKey HKEY_CURRENT_USER,"Software\Microsoft\Windows Live"
objReg.CreateKey HKEY_CURRENT_USER,"Software\Microsoft\Windows Live\Common"
objReg.SetStringValue HKEY_CURRENT_USER,"Software\Microsoft\Windows Live\Common","TOUVersion","16.0.0.0"
objReg.CreateKey HKEY_CURRENT_USER,"Software\Microsoft\Windows Live\Photo Gallery"
objReg.SetDWORDValue HKEY_CURRENT_USER,"Software\Microsoft\Windows Live\Photo Gallery","SignInRemindersLeft","0"
objReg.CreateKey HKEY_CURRENT_USER,"Software\Microsoft\Windows Live\Photo Gallery\Library"
arrStringValues = Array(".WDP",".BMP",".JFIF",".JPEG",".JPE",".JPG",".PNG",".TIF",".DIB",".TIFF",".ICO")
objReg.SetMultiStringValue HKEY_CURRENT_USER,"Software\Microsoft\Windows Live\Photo Gallery\Library", "DontShowAssociationsDialogExtensions", arrStringValues
...

To install on a Windows 8 workstation you’ll need the .Net Framework 3.5 “feature” to be installed, which isn’t there by default (Control Panel > Programs > Uninstall a program > Turn Windows Features on or off). This is problematic if you’re using WSUS – the attempt to download the update will fail with error 0x800f0906. Microsoft have an MDSN article about this, but the prescribed fix of using DISM to fetch the feature from the install media didn’t work for me on Windows 8 Enterprise. I had to remove my PC from an OU which inherits WSUS settings, run gpupdate /force then try again, this time successfully.

In my organization, the requirement for Photo Gallery is for users to interact with a centralized image library. This is stored on a Window 2008 R2 server, and I discovered that I could not add this folder to the Pictures library unless it was indexed on the server side (well, without enabling offline folders – which I don’t want). The relevant information on this topic can be found in this Technet post. In summary, you need to enable the Windows Search Service on the file server, which is a “Role Service” under the File Services role in Server Manager.

The missing piece of the puzzle so far is how to programmatically add this image repository location to each user’s Pictures library. I found a page about this, though the tools did not seem to actually work. Admittedly it’s a few years old, so maybe there are some more official tools now. More research to follow…