Creating a WinPE 5.x boot image with PowerShell

To create the WinPE 5.0 boot image you need to have Windows ADK 8.1 installed. You can download the Windows Assessment and Deployment Kit (Windows ADK) for Windows 8.1 Update here: http://www.microsoft.com/en-us/download/details.aspx?id=39982. The following are the options you can use to run adksetup.exe:

adksetup

If you download Windows ADK 8.1 on a machine that already has Windows ADK 8.0 installed, you get an error and as shown above you need to use /layout option to proceed. To continue even if previous version of Windows ADK is installed, you can run the following option:

adksetup.exe /layout “C:\OfflineADK8.1”

If you ask yourself why to download Windows ADK 8.1 and use WinPE 5.0, please consider some of the new and changed functionality:

  • Profiling in feature is removed
  • WinPE 5.0 x64 supports 4 TB of RAM (still 64 GB for x86)
  • Scratchspace set automatically to 512 MB when having more than 1 GB of RAM, otherwise 32 MB
  • You can deploy OS: Windows 8.1, Windows Server 2012 R2, Windows 8, Windows Server 2012, Windows 7, or Windows Server 2008 R2.
  • Doesn’t support: Windows Vista or Windows Server 2008.
  • Scripting tools: NET Framework optional component renamed to WinPE_NetFx; PowerShell optional component renamed to WinPE_PowerShell; and Winpeshl.ini allows you to launch apps with command-line parameters in quotes.

Creating a dual-boot WinPE 5.0 boot image

Once Windows ADK 8.1 has been downloaded and installed, you can create dual-boot WinPE by running the following PowerShell script as administrator:


# Filename: DualBoot-WinPE50.ps1 - www.alexcomputerbubble.com
# Date:     May, 2014
# Author:   Alex Dujakovic
# Description: PowerShell script to create dual boot WinPE
# -------------------------------------------------------------------------------
# Paths to WinPE folders
$WinPE_BuildFolder = "C:\WinPE-Plugin\WinPE50"
$WinPE_MountFolder = "C:\WinPE-Plugin\Mount"
$WinPE_Drivers = "C:\WinPE-Plugin\Drivers"
$WinPE_AppsFiles = "C:\WinPE-Plugin\Apps"
$WinPE_Combined = "C:\WinPE-Plugin\WinPE50_Combined"
$WinPE_Media = "C:\WinPE-Plugin\Media"
$amd64 = "$WinPE_BuildFolder" + "_amd64"
$x86 = "$WinPE_BuildFolder" + "_x86"

Function Make-WinPEBootWim($WinPE_Architecture){

# Paths to WinPE folders and tools
$ADK_Path = "C:\Program Files (x86)\Windows Kits\8.1\Assessment and Deployment Kit"
$WinPE_ADK_Path = $ADK_Path + "\Windows Preinstallation Environment"
$WinPE_OCs_Path = $WinPE_ADK_Path + "\$WinPE_Architecture\WinPE_OCs"
$DISM_Path = $ADK_Path + "\Deployment Tools" + "\$WinPE_Architecture\DISM"
$WinPE_BuildFolder = $WinPE_BuildFolder + "_" + $WinPE_Architecture

# Functions
Function Delete-Folder($folderPath){
    try {
        if (Test-Path -path $folderPath) {Remove-Item -Path $folderPath -Recurse -ErrorAction Stop}
    }
    catch{
        Write-Warning "Error deleting folder!"
        Write-Warning "Error: $($_.Exception.Message)"
        Break
    }
}

Function Make-Directory($folderPath){
	if (!(Test-Path -path $folderPath)) {New-Item $folderPath -Type Directory}
}

Function WinPE-Mount($buildFolder, $mountFolder){
    & $DISM_Path\Imagex.exe /mountrw $buildFolder\winpe.wim 1 $mountFolder
}

Function WinPE-UnMount($mountFolder){
    & $DISM_Path\Imagex.exe /unmount /commit $mountFolder
}

Delete-Folder -folderPath $WinPE_BuildFolder
Delete-Folder -folderPath $WinPE_MountFolder

Make-Directory -folderPath $WinPE_BuildFolder
Make-Directory -folderPath $WinPE_MountFolder

Copy-Item "$WinPE_ADK_Path\$WinPE_Architecture\en-us\winpe.wim" $WinPE_BuildFolder

# Mount folder
WinPE-Mount -buildFolder $WinPE_BuildFolder -mountFolder $WinPE_MountFolder

# Add WinPE 5.0 optional components using ADK 8.1 version of dism.exe
& $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\WinPE-Scripting.cab
& $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\en-us\WinPE-Scripting_en-us.cab
& $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\WinPE-WMI.cab
& $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\en-us\WinPE-WMI_en-us.cab
& $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\WinPE-MDAC.cab
& $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\en-us\WinPE-MDAC_en-us.cab
& $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\WinPE-HTA.cab
& $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\en-us\WinPE-HTA_en-us.cab
& $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\WinPE-NetFx.cab
& $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\en-us\WinPE-NetFx_en-us.cab
& $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\WinPE-PowerShell.cab
& $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\en-us\WinPE-PowerShell_en-us.cab
& $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\WinPE-DismCmdlets.cab
& $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\en-us\WinPE-DismCmdlets_en-us.cab

# Install WinPE 5.0 Drivers
If(Test-Path -Path "$WinPE_Drivers\$WinPE_Architecture"){
    & $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Driver /Driver:"$WinPE_Drivers\$WinPE_Architecture" /Recurse
}

# Copy WinPE Application Files
If(Test-Path -Path "$WinPE_AppsFiles\$WinPE_Architecture"){
Copy-Item "$WinPE_AppsFiles\$WinPE_Architecture\*" "$WinPE_MountFolder\Windows\System32\" -Recurse
}

# Unmount folder
WinPE-UnMount -mountFolder $WinPE_MountFolder

Make-Directory -folderPath "$WinPE_BuildFolder\bootiso\media\sources"

Copy-Item "$WinPE_ADK_Path\$WinPE_Architecture\Media" "$WinPE_BuildFolder\bootiso" -recurse -Force
Copy-Item "$WinPE_BuildFolder\winpe.wim" "$WinPE_BuildFolder\bootiso\media\sources\boot.wim" -Force

}

# Make folder to combine two boot.wim files
Function Make-Directory($folderPath){
	if (!(Test-Path -path $folderPath)) {New-Item $folderPath -Type Directory}
}

# Modify the BCD store
Function Modify-BCD($bcdFolderPath){
$description = "WinPE5.0_x86"
$a = bcdedit /store $bcdFolderPath\Boot\BCD /enum
$bcdFirstEntry = $a[15].Substring(56,38).Trim()
If($a[22].Substring(0,15).Trim() -eq "custom:250000c2"){
   $removeMetroStyleEntry = "bcdedit --% /store $bcdFolderPath\Boot\BCD /deletevalue {default} custom:250000c2"
   Invoke-Expression $removeMetroStyleEntry
}
$commandEditBcdX86 = @"
bcdedit --% /store $bcdFolderPath\Boot\BCD /set {default} device ramdisk=[boot]\sources\boot_x86.wim,$($bcdFirstEntry)
bcdedit --% /store $bcdFolderPath\Boot\BCD /set {default} osdevice ramdisk=[boot]\sources\boot_x86.wim,$($bcdFirstEntry)
bcdedit --% /store $bcdFolderPath\Boot\BCD /set {default} description $description
"@
Invoke-Expression $commandEditBcdX86

$b = bcdedit /store "$bcdFolderPath\Boot\BCD" /copy '{default}' /d "WinPE5.0_x64"
foreach($i in $b){
$bcdSecondEntry = $i.Substring(37).Replace(".","")
}

$commandEditBcdx64 = @"
bcdedit --% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) device ramdisk=[boot]\sources\boot_x64.wim,$($bcdFirstEntry)
bcdedit --% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) osdevice ramdisk=[boot]\sources\boot_x64.wim,$($bcdFirstEntry)
bcdedit --% /store $bcdFolderPath\Boot\BCD -displayorder $($bcdSecondEntry) -addlast
"@
Invoke-Expression $commandEditBcdx64
}

# To create bootable WinPE x64 - Run this command only
Make-WinPEBootWim -WinPE_Architecture "amd64"

# To create bootable WinPE x 86 - Run this command only
Make-WinPEBootWim -WinPE_Architecture "x86"

# To create DualBoot WinPe x86/x64 - Run above and all the commands below as well
Make-Directory -folderPath $WinPE_Combined
Copy-Item "$x86\bootiso\media\*" -Destination $WinPE_Combined -recurse -Force
rename-item -path "$WinPE_Combined\Sources\boot.wim" -newname boot_x86.wim -Force
Copy-Item "$amd64\bootiso\media\sources\boot.wim" -Destination "$WinPE_Combined\Sources" -Force
rename-item -path "$WinPE_Combined\Sources\boot.wim" -newname boot_x64.wim -Force
rename-item -path $WinPE_Combined -newname $WinPE_Media -Force
Modify-BCD -bcdFolderPath $WinPE_Media

Please go to the Download/PowerShell section to download the above PowerShell script: DualBoot-WinPE50.ps1.

At the beginning of the script you will notice the paths to the WinPE build folders. You do not need to have these folders, but in my case, I like to have a folder that will house and keep organized all my WinPE drivers, applications and configuration files.  See the picture below that provides some info about the content of my WinPE-Plugin folder. WinPEFolders

WinPE-Plugin folder has subfolders Apps and Drivers that house 64 bit and 32 bit applications and drivers. Amd64 folder, for example contains all files and apps that I need in order to build my customized 64 bit WinPE. In one of my next blogs I will provide more info about GUI that I’ve build for WinPE that looks like the following – see this post about WinPE GUI.AlexWinPE Once the DualBoot-WinPE50.ps1 script finishes executing, it creates WinPE-Plugin folder with four subfolders: Media, Mount, WinPE50_amd64 and WinPE50_x64. In my case, as previously explained, I have additional Apps and Drivers subfolders as shown in the picture below:

FoldersCreated

To finalize creation of my dual boot WinPE I use my DiskPart application (you could find it in the download section) to build a bootable USB stick. It will format a USB drive and transfer all files from the following folder: C:\WinPE-Plugin\Media, as shown below.

DiskPart

At the end, I would like just to add a few lines about Make-BCD function in the script. You will notice that this function is searching BCD store for the existence of the “custom:250000c2” setting. What is the purpose of this setting in BCD? Its purpose is to tell bootmgr to go ahead and boot Windows 8 and invoke bootux.dll to display the new metro style and touch compatible boot menu. Setting that option to 0 or removing the option from the BCD entry will tell bootmgr to fall back to the behaviour we see in Vista and 7. This is why I used this function to delete this setting, and therefore have a dual boot WinPE option.





Please note: Although the author has made every reasonable attempt to achieve complete accuracy of the content, he assumes no responsibility for errors or omissions. Also, you should use this information as you see fit, and at your own risk.

9 thoughts on “Creating a WinPE 5.x boot image with PowerShell

  1. Iris

    Hello

    We want to get a dual boot WIM file which can be imported to SCCM.
    Do you know how we can make a WIM file from the media folder?

    Reply
    1. admin Post author

      So how do I convert the folder: “C:\WinPE-DualBootExternalUSBDrive\Media” into a WIM file?
      Run this command: imagex /capture “C:\WinPE-DualBootExternalUSBDrive\Media” C:\MediaForSCCM\dualBootWim.wim “Dual Boot Wim File”
      This will copy all files and folders inside the location “C:\WinPE-DualBootExternalUSBDrive\Media“ and put them in a WIM file under the location “C:\MediaForSCCM”.

      Reply
  2. beth

    hi
    i am having problems under win7 and waik for windows 10.
    getting error in the bcdedit part.
    had to edit this part to get the correct values
    $bcdFirstEntry = $a[16].Substring(56,38).Trim()
    write-host $bcdFirstEntry

    If($a[23].Substring(0,15).Trim() -eq “custom:250000c2”){
    $removeMetroStyleEntry = “bcdedit –% /store $bcdFolderPath\Boot\BCD /deletevalue {default} custom:250000c2”
    Invoke-Expression $removeMetroStyleEntry
    }

    it works when i enter the commands direct into PS window. but when running it into script $bcdFirstEntry is empty and i am getting an error on substring

    Reply
    1. admin Post author

      Please change this code:
      If($a[-4].Substring(0,15).Trim() -eq “custom:250000c2”){
      $removeMetroStyleEntry = “bcdedit –% /store $bcdFolderPath\Boot\BCD /deletevalue {default} custom:250000c2”
      Invoke-Expression $removeMetroStyleEntry
      }

      into following code:

      If($a[-4].Substring(0,15).Trim() -eq “custom:250000c2″){
      $removeMetroStyleEntry = @”
      bcdedit –% /store $bcdFolderPath\Boot\BCD /deletevalue {default} custom:250000c2
      “@
      Invoke-Expression $removeMetroStyleEntry
      }

      Note the use of here-string. In addition I used ($a[-4].Substring(0,15).Trim() and you used: ($a[23].Substring(0,15).Trim()
      Please let me know if this helps.

      Reply
  3. beth

    PS C:\WINDOWS\system32> bcdedit /store C:\WinPE10\Media\Boot\BCD /enum

    Windows-Start-Manager
    ———————
    Bezeichner {bootmgr}
    description Windows Boot Manager
    locale en-US
    inherit {globalsettings}
    default {default}
    displayorder {default}
    {c02ec2e2-1477-11e6-9c16-48d224e43632}
    toolsdisplayorder {memdiag}
    timeout 30

    Windows-Startladeprogramm
    ————————-
    Bezeichner {default}
    device ramdisk=[boot]\sources\boot_x86.wim,{7619dcc8-fafe-11d9-b411-000476eba25f}
    path \windows\system32\boot\winload.exe
    description WinPE10.0_x86
    locale en-US
    inherit {bootloadersettings}
    osdevice ramdisk=[boot]\sources\boot_x86.wim,{7619dcc8-fafe-11d9-b411-000476eba25f}
    systemroot \windows
    detecthal Yes
    winpe Yes
    ems No

    Windows-Startladeprogramm
    ————————-
    Bezeichner {c02ec2e2-1477-11e6-9c16-48d224e43632}
    device ramdisk=[boot]\sources\boot_x64.wim,{7619dcc8-fafe-11d9-b411-000476eba25f}
    path \windows\system32\boot\winload.exe
    description WinPE10.0_x64
    locale en-US
    inherit {bootloadersettings}
    osdevice ramdisk=[boot]\sources\boot_x64.wim,{7619dcc8-fafe-11d9-b411-000476eba25f}
    systemroot \windows
    detecthal Yes
    winpe Yes
    ems No
    PS C:\WINDOWS\system32>
    is this BCD correct? because its not booting 🙁 and did not show in the boot menu only windows bootmenu which boots my current system

    Reply
  4. beth

    # Filename: DualBoot-WinPE50.ps1 – http://www.alexcomputerbubble.com
    # Date: May, 2014
    # Author: Alex Dujakovic
    # Description: PowerShell script to create dual boot WinPE
    # ——————————————————————————-
    # Paths to WinPE folders
    $WinPE_Folder = “C:\WinPE10”
    $WinPE_BuildFolder = $WinPE_Folder + “\WinPE10”
    $WinPE_MountFolder = $WinPE_Folder + “\Mount”
    $WinPE_Combined = $WinPE_Folder + “\WinPE10_Combined”
    $WinPE_Media = $WinPE_Folder + “\Media”
    $WinPE_Drivers = $WinPE_Folder + “\Drivers”
    $WinPE_AppsFiles = $WinPE_Folder + “\Apps”

    New-Item $WinPE_Drivers -Type Directory -force
    New-Item $WinPE_AppsFiles -Type Directory -force

    $ADK_Path = “C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit”
    $WinPE_ADK_Path = $ADK_Path + “\Windows Preinstallation Environment”
    $oscdimg_Path = $ADK_Path + “\Deployment Tools\amd64\Oscdimg\oscdimg.exe”
    $bcdedit_Path = $ADK_Path + “\Deployment Tools\amd64\BCDBoot\bcdedit.exe”
    $efiboot_Path = $ADK_Path + “\Deployment Tools\amd64\Oscdimg\efisys.bin”
    $EFIbcd = $WinPE_Media + “\EFI\Microsoft”

    $amd64 = “$WinPE_BuildFolder” + “_amd64”
    $x86 = “$WinPE_BuildFolder” + “_x86”
    $Language = “de-de”
    $TimeStamp = Get-Date -Format dd_MM_yyyy;
    $ISOLabel = “winpe_dualboot_$TimeStamp”

    function Get-ScriptDirectory {
    $Invocation = (Get-Variable MyInvocation -Scope 1).Value;
    if($Invocation.PSScriptRoot)
    {
    $Invocation.PSScriptRoot;
    }
    Elseif($Invocation.MyCommand.Path)
    {
    Split-Path $Invocation.MyCommand.Path
    }
    else
    {
    $Invocation.InvocationName.Substring(0,$Invocation.InvocationName.LastIndexOf(“\”));
    }
    }
    $scriptroot = Get-ScriptDirectory

    # Copy Drivers & Apps
    robocopy “$scriptroot\addon\Drivers\” “$WinPE_Drivers” /e /NDL /NJH /NJS | %{$data = $_.Split([char]9);
    if(“$($data[4])” -ne “”) { $file = “$($data[4])”} ;
    Write-Progress “Percentage $($data[0])” -Activity “Copy files…” -CurrentOperation “$($file)” -ErrorAction SilentlyContinue; }
    Write-Progress -Activity “Copy files…” -Completed

    robocopy “$scriptroot\addon\Apps\” “$WinPE_AppsFiles” /e /NDL /NJH /NJS | %{$data = $_.Split([char]9);
    if(“$($data[4])” -ne “”) { $file = “$($data[4])”} ;
    Write-Progress “Percentage $($data[0])” -Activity “Copy files…” -CurrentOperation “$($file)” -ErrorAction SilentlyContinue; }
    Write-Progress -Activity “Copy files…” -Completed

    Function Make-WinPEBootWim($WinPE_Architecture){
    # Paths to WinPE folders and tools
    $WinPE_OCs_Path = $WinPE_ADK_Path + “\$WinPE_Architecture\WinPE_OCs”
    $DISM_Path = $ADK_Path + “\Deployment Tools” + “\$WinPE_Architecture\DISM”
    $WinPE_BuildFolder = $WinPE_BuildFolder + “_” + $WinPE_Architecture

    Function Delete-Folder($folderPath){
    try {
    if (Test-Path -path $folderPath) {Remove-Item -Path $folderPath -Recurse -ErrorAction Stop}
    }
    catch{
    Write-Warning “Error deleting folder!”
    Write-Warning “Error: $($_.Exception.Message)”
    Break
    }
    }

    Function Make-Directory($folderPath){
    if (!(Test-Path -path $folderPath)) {New-Item $folderPath -Type Directory}
    }

    Function WinPE-Mount($buildFolder, $mountFolder){
    & $DISM_Path\Imagex.exe /mountrw $buildFolder\winpe.wim 1 $mountFolder
    }

    Function WinPE-UnMount($mountFolder){
    & $DISM_Path\Imagex.exe /unmount /commit $mountFolder
    }

    Delete-Folder -folderPath $WinPE_BuildFolder
    Delete-Folder -folderPath $WinPE_MountFolder

    Make-Directory -folderPath $WinPE_BuildFolder
    Make-Directory -folderPath $WinPE_MountFolder

    Copy-Item “$WinPE_ADK_Path\$WinPE_Architecture\en-us\winpe.wim” $WinPE_BuildFolder

    # Mount Wim File
    WinPE-Mount -buildFolder $WinPE_BuildFolder -mountFolder $WinPE_MountFolder

    # Add WinPE 10.0 optional components using ADK 10.0 version of dism.exe
    & $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\$Language\lp.cab
    & $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\WinPE-Scripting.cab
    & $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\$Language\WinPE-Scripting_$Language.cab
    & $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\WinPE-WMI.cab
    & $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\$Language\WinPE-WMI_$Language.cab
    & $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\WinPE-MDAC.cab
    & $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\$Language\WinPE-MDAC_$Language.cab
    & $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\WinPE-HTA.cab
    & $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\$Language\WinPE-HTA_$Language.cab
    & $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\WinPE-NetFx.cab
    & $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\$Language\WinPE-NetFx_$Language.cab
    & $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\WinPE-PowerShell.cab
    & $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\$Language\WinPE-PowerShell_$Language.cab
    & $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\WinPE-DismCmdlets.cab
    & $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Package /PackagePath:$WinPE_OCs_Path\$Language\WinPE-DismCmdlets_$Language.cab
    & $DISM_Path\dism.exe /Set-AllIntl:$Language /Image:$WinPE_MountFolder

    # Install WinPE 10.0 Drivers
    If(Test-Path -Path “$WinPE_Drivers\$WinPE_Architecture”){
    & $DISM_Path\dism.exe /Image:$WinPE_MountFolder /Add-Driver /Driver:”$WinPE_Drivers\$WinPE_Architecture” /Recurse /ForceUnsigned
    }

    # Copy WinPE Application Files
    If(Test-Path -Path “$WinPE_AppsFiles\$WinPE_Architecture”){
    robocopy “$WinPE_AppsFiles\$WinPE_Architecture\” “$WinPE_MountFolder\Windows\System32\” /e /NDL /NJH /NJS /IS | %{$data = $_.Split([char]9);
    if(“$($data[4])” -ne “”) { $file = “$($data[4])”} ;
    Write-Progress “Percentage $($data[0])” -Activity “Copy files…” -CurrentOperation “$($file)” -ErrorAction SilentlyContinue; }
    Write-Progress -Activity “Copy files…” -Completed
    }

    # Unmount folder
    WinPE-UnMount -mountFolder $WinPE_MountFolder

    Make-Directory -folderPath “$WinPE_BuildFolder\bootiso\Media\sources”

    Copy-Item “$WinPE_ADK_Path\$WinPE_Architecture\Media\$Language\” “$WinPE_BuildFolder\bootiso\Media\$Language” -recurse -Force

    Copy-Item “$WinPE_ADK_Path\$WinPE_Architecture\Media\Boot\Fonts\” “$WinPE_BuildFolder\bootiso\Media\Boot\Fonts” -recurse -Force
    Copy-Item “$WinPE_ADK_Path\$WinPE_Architecture\Media\Boot\$Language\” “$WinPE_BuildFolder\bootiso\Media\Boot\$Language” -recurse -Force
    Copy-Item “$WinPE_ADK_Path\$WinPE_Architecture\Media\Boot\Resources\” “$WinPE_BuildFolder\bootiso\Media\Boot\Resources” -recurse -Force
    Copy-Item “$WinPE_ADK_Path\$WinPE_Architecture\Media\Boot\BCD” “$WinPE_BuildFolder\bootiso\Media\Boot” -Force
    Copy-Item “$WinPE_ADK_Path\$WinPE_Architecture\Media\Boot\boot.sdi” “$WinPE_BuildFolder\bootiso\Media\Boot” -Force
    Copy-Item “$WinPE_ADK_Path\$WinPE_Architecture\Media\Boot\bootfix.bin” “$WinPE_BuildFolder\bootiso\Media\Boot” -Force
    Copy-Item “$WinPE_ADK_Path\$WinPE_Architecture\Media\Boot\memtest.exe” “$WinPE_BuildFolder\bootiso\Media\Boot” -Force

    Copy-Item “$WinPE_ADK_Path\$WinPE_Architecture\Media\EFI\Microsoft\Boot\Fonts” “$WinPE_BuildFolder\bootiso\Media\EFI\Microsoft\Boot\Fonts” -recurse -Force
    Copy-Item “$WinPE_ADK_Path\$WinPE_Architecture\Media\EFI\Microsoft\Boot\Resources” “$WinPE_BuildFolder\bootiso\Media\EFI\Microsoft\Boot\Resources” -recurse -Force
    Copy-Item “$WinPE_ADK_Path\$WinPE_Architecture\Media\EFI\Microsoft\Boot\$Language” “$WinPE_BuildFolder\bootiso\Media\EFI\Microsoft\Boot” -recurse -Force
    Copy-Item “$WinPE_ADK_Path\$WinPE_Architecture\Media\EFI\Microsoft\Boot\Microsoft\Boot\memtest.efi” “$WinPE_BuildFolder\bootiso\Media\EFI\Microsoft\Boot” -recurse -Force
    Copy-Item “$WinPE_ADK_Path\$WinPE_Architecture\Media\EFI\Microsoft\Boot\BCD” “$WinPE_BuildFolder\bootiso\Media\EFI\Microsoft\Boot” -recurse -Force

    Copy-Item “$WinPE_ADK_Path\$WinPE_Architecture\Media\bootmgr” “$WinPE_BuildFolder\bootiso\Media” -Force
    Copy-Item “$WinPE_ADK_Path\$WinPE_Architecture\Media\bootmgr.efi” “$WinPE_BuildFolder\bootiso\Media” -Force

    Copy-Item “$WinPE_BuildFolder\winpe.wim” “$WinPE_BuildFolder\bootiso\Media\sources\boot.wim” -Force

    }

    # Make folder to combine two boot.wim files
    Function Make-Directory($folderPath){
    if (!(Test-Path -path $folderPath)) {New-Item $folderPath -Type Directory}
    }

    # Modify the BCD store
    Function Modify-BCD($bcdFolderPath){
    $description = “WinPE10.0_x64”
    $a = & “$bcdedit_Path” /store $bcdFolderPath\Boot\BCD /enum
    $a2 = $a[15]
    $bcdFirstEntry = $a2.split(“,”)[1].Trim()
    if($a[22].Substring(0,14).Trim() -eq “bootmenupolicy”){
    $removeMetroStyleEntry = “& ‘$bcdedit_Path’ –% /store $bcdFolderPath\Boot\BCD /deletevalue {default} bootmenupolicy”
    Invoke-Expression $removeMetroStyleEntry
    }
    $commandEditBcdX64 = @”
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} device ramdisk=[boot]\sources\boot_x64.wim,$($bcdFirstEntry)
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} osdevice ramdisk=[boot]\sources\boot_x64.wim,$($bcdFirstEntry)
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} description $description
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} locale $($Language)
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} bootmenupolicy legacy
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} inherit {bootloadersettings}
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} winpe Yes
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} EMS No
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} detecthal Yes
    “@
    Invoke-Expression $commandEditBcdX64

    $b = & ‘bcdedit’ /store “$bcdFolderPath\Boot\BCD” /copy ‘{default}’ /d “WinPE10.0_x86″

    foreach($i in $b){$bcdSecondEntry =$i.Substring(33).split(” “)[0]}
    $commandEditBcdx86 = @”
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) device ramdisk=[boot]\sources\boot_x86.wim,$($bcdFirstEntry)
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) osdevice ramdisk=[boot]\sources\boot_x86.wim,$($bcdFirstEntry)
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) locale $($Language)
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) winpe Yes
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) EMS No
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) inherit {bootloadersettings}
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) detecthal Yes
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD -displayorder $($bcdSecondEntry) -addlast
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {bootmgr} locale $($Language)
    “@
    Invoke-Expression $commandEditBcdx86
    }

    Function Modify-EFIBCD($bcdFolderPath){
    $description = “WinPE10.0_x64”
    $a = & “$bcdedit_Path” /store $bcdFolderPath\Boot\BCD /enum
    $a2 = $a[16]
    $bcdFirstEntry = $a2.split(“,”)[1].Trim()
    if($a[22].Substring(0,14).Trim() -eq “bootmenupolicy”){
    $removeMetroStyleEntry = “& ‘$bcdedit_Path’ –% /store $bcdFolderPath\Boot\BCD /deletevalue {default} bootmenupolicy”
    Invoke-Expression $removeMetroStyleEntry
    }
    $commandEditBcdX64 = @”
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} device ramdisk=[boot]\sources\boot_x64.wim,$($bcdFirstEntry)
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} osdevice ramdisk=[boot]\sources\boot_x64.wim,$($bcdFirstEntry)
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} description $description
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} locale $($Language)
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} bootmenupolicy legacy
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} inherit {bootloadersettings}
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} winpe Yes
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} EMS No
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} detecthal Yes
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} path \windows\system32\boot\winload.efi
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {default} isolatedcontext Yes
    “@
    Invoke-Expression $commandEditBcdX64

    $b = & ‘bcdedit’ /store “$bcdFolderPath\Boot\BCD” /copy ‘{default}’ /d “WinPE10.0_x86″

    foreach($i in $b){$bcdSecondEntry =$i.Substring(33).split(” “)[0]}
    $commandEditBcdx86 = @”
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) device ramdisk=[boot]\sources\boot_x86.wim,$($bcdFirstEntry)
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) osdevice ramdisk=[boot]\sources\boot_x86.wim,$($bcdFirstEntry)
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) path \windows\system32\boot\winload.efi
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) isolatedcontext Yes
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) locale $($Language)
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) winpe Yes
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) EMS No
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) inherit {bootloadersettings}
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) detecthal Yes
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD -displayorder $($bcdSecondEntry) -addlast
    & “$bcdedit_Path” –% /store $bcdFolderPath\Boot\BCD /set {bootmgr} locale $($Language)
    “@
    Invoke-Expression $commandEditBcdx86
    }

    # Create ISO and start Rufus
    function CreateISO {
    $question = “Create ISO?”
    $message = “Press Y to create ISO!”
    $choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
    $choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList ‘&Yes’))
    $choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList ‘&No’))
    $decision = $Host.UI.PromptForChoice($question, $message, $choices, 0)
    if ($decision -eq 0) {
    & $oscdimg_Path “-b$efiboot_Path” “-pEF” “-u1” “-udfver102” “$WinPE_Media” “$WinPE_Folder\$ISOLabel.iso”
    StartRufus
    }
    }

    #Start Rufus
    function StartRufus {
    $question = “Start Rufus?”
    $message = “Press Y to start Rufus!”
    $choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
    $choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList ‘&Yes’))
    $choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList ‘&No’))
    $decision = $Host.UI.PromptForChoice($question, $message, $choices, 0)
    if ($decision -eq 0) {Start-Process “$scriptroot\rufus\rufus-2.8p.exe” -ArgumentList “–gui –iso=$WinPE_Folder\$ISOLabel.iso” -wait}
    }

    # Delete WinPE_Folder
    function DeleteWinPE_Folder {
    $question = “Delete ‘$WinPE_Folder’?”
    $message = “Press Y to delete $WinPE_Folder!”
    $choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
    $choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList ‘&Yes’))
    $choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList ‘&No’))
    $decision = $Host.UI.PromptForChoice($question, $message, $choices, 1)
    if ($decision -eq 0) {
    $ListOfFiles = Get-ChildItem -Path $WinPE_Folder -Recurse | Where-Object {!$_.PSIsContainer}
    for ($i = 1; $i -lt $ListOfFiles.count; $i++) {
    Write-Progress -Activity “Deleting files…” -Status $ListOfFiles[$i].FullName -PercentComplete ($i / ($ListOfFiles.Count*100))
    Remove-Item -Recurse -Force -Path $ListOfFiles[$i].FullName
    }
    Write-Progress -Activity “Deleting files…” -Completed
    remove-item $WinPE_Folder -force -recurse
    }
    }

    # Call functions

    # To create bootable WinPE x64 – Run this command only
    Make-WinPEBootWim -WinPE_Architecture “amd64”

    # To create bootable WinPE x 86 – Run this command only
    Make-WinPEBootWim -WinPE_Architecture “x86”

    # To create DualBoot WinPe x86/x64 – Run above and all the commands below as well
    Make-Directory -folderPath $WinPE_Combined
    Copy-Item “$amd64\bootiso\Media\*” -Destination $WinPE_Combined -recurse -Force
    Copy-Item “$x86\bootiso\Media\EFI\Boot\*” -Destination “$WinPE_Combined\EFI\Boot” -recurse -Force
    rename-item -path “$WinPE_Combined\Sources\boot.wim” -newname boot_x86.wim -Force
    Copy-Item “$amd64\bootiso\Media\sources\boot.wim” -Destination “$WinPE_Combined\Sources” -Force
    rename-item -path “$WinPE_Combined\Sources\boot.wim” -newname boot_x64.wim -Force
    rename-item -path $WinPE_Combined -newname $WinPE_Media -Force
    Modify-BCD -bcdFolderPath $WinPE_Media
    Modify-EFIBCD -bcdFolderPath $EFIbcd

    # Copy Programs
    robocopy “$scriptroot\addon\usb_root\” “$WinPE_Media” /e /NDL /NJH /NJS | %{$data = $_.Split([char]9);
    if(“$($data[4])” -ne “”) { $file = “$($data[4])”} ;
    Write-Progress “Percentage $($data[0])” -Activity “Copy files…” -CurrentOperation “$($file)” -ErrorAction SilentlyContinue; }
    Write-Progress -Activity “Copy files…” -Completed

    CreateISO
    DeleteWinPE_Folder

    Reply
  5. David Grant

    Hey Alex,
    Nice work here. Thanks for taking the time. I have one question. Upon creation of the dual boot USB stick, I assumed on boot, that I would get prompted for which platform (x86 or x64) I wanted to boot, or that if the CPU was seen as 64bit capable, would boot into 64 bit version. This is not what I am seeing.

    Could you explain what behavior is expected?

    Thank you.

    Reply
    1. admin Post author

      Note that this tool (for creation of the dual boot USB stick) is tested on Windows 7 only.
      Never had time and resources to test it with Windows 10. You are correct to assume that once your boot your computer with this USB stick, you would get prompted for which platform (“WinPE5.0_x86” or “WinPE5.0_x64”) you wanted to boot.
      This is the function that creates/modifies BCD:

      
      # Modify the BCD store
      Function Modify-BCD($bcdFolderPath){
      $description = "WinPE5.0_x86"
      $a = bcdedit /store $bcdFolderPath\Boot\BCD /enum
      $bcdFirstEntry = $a[15].Substring(56,38).Trim()
      If($a[22].Substring(0,15).Trim() -eq "custom:250000c2"){
         $removeMetroStyleEntry = "bcdedit --% /store $bcdFolderPath\Boot\BCD /deletevalue {default} custom:250000c2"
         Invoke-Expression $removeMetroStyleEntry
      }
      $commandEditBcdX86 = @"
      bcdedit --% /store $bcdFolderPath\Boot\BCD /set {default} device ramdisk=[boot]\sources\boot_x86.wim,$($bcdFirstEntry)
      bcdedit --% /store $bcdFolderPath\Boot\BCD /set {default} osdevice ramdisk=[boot]\sources\boot_x86.wim,$($bcdFirstEntry)
      bcdedit --% /store $bcdFolderPath\Boot\BCD /set {default} description $description
      "@
      Invoke-Expression $commandEditBcdX86
       
      $b = bcdedit /store "$bcdFolderPath\Boot\BCD" /copy '{default}' /d "WinPE5.0_x64"
      foreach($i in $b){
      $bcdSecondEntry = $i.Substring(37).Replace(".","")
      }
       
      $commandEditBcdx64 = @"
      bcdedit --% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) device ramdisk=[boot]\sources\boot_x64.wim,$($bcdFirstEntry)
      bcdedit --% /store $bcdFolderPath\Boot\BCD /set $($bcdSecondEntry) osdevice ramdisk=[boot]\sources\boot_x64.wim,$($bcdFirstEntry)
      bcdedit --% /store $bcdFolderPath\Boot\BCD -displayorder $($bcdSecondEntry) -addlast
      "@
      Invoke-Expression $commandEditBcdx64
      }
      
      

      See the above comments made by other readers with regards to Windows 10… I hope this helps. Cheers.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *