WinPE 4.0 - Automated Media Creation

I maintain two Windows 8 VMs for building WinPE 4.0, one for x86 and one for x64. Unlike the Windows 7 WAIK, Apparently the Windows 8 ADK can only build x86 on x86, and x64 on x64.

This Powershell 3 script is intended to be run from a network share with subdirectories containing apps (optional) and drivers (optional), and looks something like this:

.\setup_w8_ps3.ps1

.\drivers\amd64

.\drivers\source

.\drivers\x86

.\apps\amd64

.\apps\source

.\apps\x86

Source directories contain the source files and the x86 and amd64 directories contain the expanded x86 and x64 drivers, respectively.

Run the Powershell script on each of your x86 and x64 Windows 8 ADK environments, and it will build the respective WinPE 4.0 environment and .iso file.

There is one extra step for making the USB boot sticks [ MakeWinPEMedia /UFD c:\winpe_amd64 <drive letter>: ]; You can add that to the Media function if you have the USB drive plugged in.

@@@@@@@@@@@@@@@@@@@@

<# 
setup_w8_ps3.ps1
 
Build WinPE 4.0 with PowerShell 3 cmdlets

http://technet.microsoft.com/en-us/library/hh825144.aspx
http://technet.microsoft.com/en-us/library/hh824926.aspx
 
ISO: MakeWinPEMEdia /ISO c:\winpe_amd64 c:\winpe_amd64\winpe.iso
USB: MakeWinPEMedia /UFD c:\winpe_amd64 <drive letter>:

Adam Sailer
2013.05.10
#>
 
 
$invoke = split-path -path $myinvocation.mycommand.path -parent
$os = gwmi Win32_OperatingSystem
$proc = gwmi Win32_Processor
 
$arch = 'x86'
if (($proc.AddressWidth -eq 64) -and ($proc.DataWidth -eq 64))
{ $arch = 'amd64' }
 
 
$dest = "$env:SystemDrive\winpe_$arch"; $dest
$mount = "$dest\mount"
$image = "$dest\media\sources\boot.wim"
$label = "WinPE 4.0 $arch"
 
 
$unattend = @"
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
    <settings pass="windowsPE">
        <component name="Microsoft-Windows-Setup" processorArchitecture="$arch" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
            <Display>
                <ColorDepth>32</ColorDepth>
                <HorizontalResolution>1600</HorizontalResolution>
                <RefreshRate>60</RefreshRate>
                <VerticalResolution>900</VerticalResolution>
            </Display>
        </component>
    </settings>
</unattend>
"@
 
 
Function Prep
{
    write-host "`n`n@@ Called Prep" -Fore Magenta
 
    $ident = $env:ProgramFiles
    if (($proc.AddressWidth -eq 64) -and ($proc.DataWidth -eq 64))
    { $ident = ${env:ProgramFiles(x86)} }
 
 
    $map = @{
        BCDBootRoot = "$ident\Windows Kits\8.0\Assessment and Deployment Kit\Deployment Tools\$arch\BCDBoot";
        DandIRoot = "$ident\Windows Kits\8.0\Assessment and Deployment Kit\Deployment Tools";
        DISMRoot = "$ident\Windows Kits\8.0\Assessment and Deployment Kit\Deployment Tools\$arch\DISM";
        HelpIndexerRoot = "$ident\Windows Kits\8.0\Assessment and Deployment Kit\Deployment Tools\HelpIndexer";
        ImagingRoot = "$ident\Windows Kits\8.0\Assessment and Deployment Kit\Deployment Tools\$arch\Imaging";
        KitsRoot = "$ident\Windows Kits\8.0\";
        OSCDImgRoot = "$ident\Windows Kits\8.0\Assessment and Deployment Kit\Deployment Tools\$arch\Oscdimg";
        #RegKeyPath = "$key\Windows Kits\Installed Roots";
        WdsmcastRoot = "$ident\Windows Kits\8.0\Assessment and Deployment Kit\Deployment Tools\$arch\Wdsmcast";
        WinPERoot = "$ident\Windows Kits\8.0\Assessment and Deployment Kit\Windows Preinstallation Environment";
        WSIMRoot = "$ident\Windows Kits\8.0\Assessment and Deployment Kit\Deployment Tools\WSIM";
        }
 
 
    $array = $env:Path.Split(';')
    foreach ($key in $map.Keys)
    { $array += $map.$key; [System.Environment]::SetEnvironmentVariable($key, $map.$key, "process") }
 
 
    $array = $array | sort-object -unique; $array
    $path = [string]::join(';', $array)
    [System.Environment]::SetEnvironmentVariable('PATH', $path, 'process')
}
 
 
Function CopySource
{
    write-host "`n`n@@ Called CopySource" -Fore Magenta
 
    remove-item $dest -recurse -force -ea SilentlyContinue
    copype $arch $dest
}
 
 
Function MountCurrent
{
    write-host "`n`n@@ Called MountCurrent" -Fore Magenta
 
    Mount-WindowsImage –ImagePath $image –Index 1 -Path $mount
}
 
 
Function DismountCurrent
{
    write-host "`n`n@@ Called DismountCurrent" -Fore Magenta
 
    if (Get-WindowsImage -Mounted)
    { Dismount-WindowsImage –Path $mount -Save }
}
 
 
Function Packages
{
    write-host "`n`n@@ Called Packages" -Fore Magenta
     
    $lang = 'en-us'
 
    ## Order matters! http://technet.microsoft.com/en-us/library/hh824926.aspx
 
    $order = @(
        'winpe-wmi',
        'winpe-netfx4',
        'winpe-scripting',
        'winpe-powershell3',
        'winpE-dismCmdlets',
        'winpe-hta'                
        )
 
    $packages = @()
    $order | % { $packages += @(dir $env:WinPERoot\$arch -rec -inc "$($_).cab", "$($_)_$($lang).cab" | sort-object -desc) }
 
    $packages | % { write-host "`n$($_.Name)"; Add-WindowsPackage -Path $mount -PackagePath $_.FullName }
}
 
 
Function Drivers
{
    write-host "`n`n@@ Called Drivers" -Fore Magenta
 
    DISM /image:$mount /add-driver /driver:$invoke\drivers\$arch /recurse
}
 
 
Function Apps
{
    write-host "`n`n@@ Called Media" -Fore Magenta
 
    copy-item $invoke\apps\$arch $mount\Apps -recurse
    $unattend | out-file -encoding ASCII $mount\unattend.xml
}
 
 
Function Media
{
    write-host "`n`n@@ Called Media" -Fore Magenta
 
    MakeWinPEMEdia /ISO c:\winpe_$arch c:\winpe_$arch\winpe_$arch.iso
}
 
 
#
#
 
 
Clear
Prep
DismountCurrent
CopySource
MountCurrent
Packages
Drivers
Apps
DismountCurrent
Media