Create Zero-Touch Windows 10 ISO

I’ve recently been doing some testing between the different Windows 10 releases, and wanted to quick way to be able to install new VMs without maintaining a bunch of different VM templates, or using MDT. To do this I made a ISO image that installs the base Windows 10 image without any manual interaction required. This post will go over the steps you can use to make your own Windows 10 Zero-Touch ISO.

Prerequisites

Before you begin, you must have a Windows 10 ISO. If you don’t have one, you can use the Windows Media Creation Tool to create one from any licensed installation of Windows 10.

You will also need to install the Windows Assessment and Deployment Kit (ADK). When installing the ADK you only need to install the Deployment Tools feature.

Prep the ISO Files

Since we want this to be Zero-Touch, there are a few things you need to do to prevent the “Press any key to boot from CD or DVD” prompt.

  1. Extract the contents of your ISO. In the examples used below I extracted mine to E:\Win10_ISO.
  2. Delete the file .\boot\bootfix.bin (This will prevent the prompt when booting using BIOS.)
  3. In the folder .\efi\microsoft\boot\ rename the following files (This will prevent the boot prompt on UEFI systems)
    1. bin –> efisys_prompt.bin
    2. bin –> efisys.bin
  4. The next step only applies if you used the Media Creation Tool. If you used and ISO image you can skip to the next section.
  5. In the folder .\sources\ rename the file install.esd –> install.wim

Script It

$ISO = "E:\Windows.iso"
$FolderPath = "E:\Win10_ISO\"

# Get current drive letters
$drives = (Get-Volume).DriveLetter

# Mount the ISO image
$image = Mount-DiskImage -ImagePath $ISO -PassThru

# Get the new drive letter
$drive = (Get-Volume | ?{$drives -notcontains $_.DriveLetter -and $_.DriveLetter -ne $null}).DriveLetter

# Create destination folder if it doesn't exist
If (!(test-path $FolderPath)){
    New-Item -type directory -Path $FolderPath}

# Copy the ISO files
Get-ChildItem -Path "$($drive):\" | %{
    Copy-Item -Path $_.FullName -Destination $FolderPath -recurse -Force}

# dismount the ISO
$image | Dismount-DiskImage

# Delete the bootfix.bin
Remove-Item (Join-Path $FolderPath "boot\bootfix.bin") -Force

# Rename the efisys files
Rename-Item (Join-Path $FolderPath "efi\microsoft\boot\efisys.bin") "efisys_prompt.bin" 
Rename-Item (Join-Path $FolderPath "efi\microsoft\boot\efisys_noprompt.bin") "efisys.bin" 

# Rename install.esd to install.wim
If (Test-Path $(Join-Path $FolderPath "source\install.esd")){
	Rename-Item $(Join-Path $FolderPath "source\install.esd") "install.wim"
}

Create Autounattend.xml

The Autounattend.xml is used to answer all the questions that you are asked during the installation process. I have uploaded a sample file to my Gist profile that you can download, to get started pretty quick and easily. This Autounattend.xml has been tested on version 1511, 1607, and 1709, using x64 architecture.

  1. Download the Autounattend.xml and open in your preferred text editor
  2. The DiskConfiguration section sets the partitions. This file will create a 100 MB EFI partition, a 4 GB recovery volume, and assign the rest of the disk space to the OS partition. You should not need to make any changes here.
  3. Update the sections SetupUILanguage, InputLocale, SystemLocale, UILanguage, and UserLocale to your required language and location.
  4. In the UserAccounts section you can set the password for the administrator account.
  5. Update the AutoLogon section with the same password as the UserAccounts
  6. Make note of the SkipMachineOOBE and SkipUserOOBE. These are set to true to allow you to bypass the initial setup screens after Windows is installed. These should only be used for testing purposes. If you are creating a production image be sure to remove these two sections.
  7. ComputerName is set to * to generate a random name.
  8. Update the RegisteredOwner and RegisteredOrganization to your organization.
  9. Place the xml in the top level of the folder you extracted the ISO to.

If you want to do any customization beyond what is covered above you can use the Windows System Image Manager that was included with the Windows ADK you installed earlier.

Script It

$FolderPath = "E:\Win10_ISO\"
[string]$password = Read-Host -Prompt "Enter the admin password to use"
[string]$ComputerName = Read-Host -Prompt "Enter the computer name use '*' to randomly generate it"
[string]$RegisteredOwner = Read-Host -Prompt "Enter the Registered Owner"
[string]$RegisteredOrganization = Read-Host -Prompt "Enter the Registered Organization"

$AutounattendXML = $(Join-Path $FolderPath "Autounattend.xml")
# Download the sample Autounattend.xml
$Uri = "https://gist.githubusercontent.com/mdowst/e81cc0608a0c554d8c3381ebc7b6e15e/raw/dc55c6c1eef66fc0c4db0652ce8300e9ff507e0f/Autounattend.xml"
Invoke-WebRequest -Uri $Uri -OutFile $AutounattendXML

# load the Autounattend.xml
[xml]$Autounattend = Get-Content $AutounattendXML

# Update the values
($Autounattend.unattend.settings | ?{$_.pass -eq 'oobeSystem'}).component.AutoLogon.Password.Value = $password
($Autounattend.unattend.settings | ?{$_.pass -eq 'oobeSystem'}).component.UserAccounts.AdministratorPassword.Value = $password
($Autounattend.unattend.settings | ?{$_.pass -eq 'specialize'}).component.ComputerName = $ComputerName
($Autounattend.unattend.settings | ?{$_.pass -eq 'specialize'}).component.RegisteredOwner = $RegisteredOwner
($Autounattend.unattend.settings | ?{$_.pass -eq 'specialize'}).component.RegisteredOrganization = $RegisteredOrganization

# Save the updated XML file
$Autounattend.Save($AutounattendXML)

Create the ISO

  1. Go to Start > Windows Kits > Deployment and Imaging Tools Environment
  2. Run the command below to generate your ISO.

oscdimg.exe -m -o -u2 -udfver102 -bootdata:2#p0,e,bE:\Win10_ISO\boot\etfsboot.com#pEF,e,bE:\Win10_ISO\efi\microsoft\boot\efisys.bin E:\Win10_ISO E:\Win10Ent1607x64.iso

That’s it! Your ISO is now ready to use.

Script It!

# Create the ISO image
$DevToolsDirectory = "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\"
$FolderPath = "E:\Win10_ISO\"
$ISO = 'E:\Win10_ISO.iso'

$command = $(Join-Path $DevToolsDirectory 'amd64\Oscdimg\oscdimg.exe')
$arguments = '-m','-o','-u2','-udfver102',"-bootdata:2#p0,e,b$(Join-Path $FolderPath 'boot\etfsboot.com')#pEF,e,b$(Join-Path $FolderPath 'efi\microsoft\boot\efisys.bin')",$FolderPath,$ISO

& $command $arguments

Bonus Script: Create Virtual Machine

The script below can be used to create a Hyper-V Virtual Machine, mount your newly created ISO, and starts the VM, so the Windows 10 installation begins.

# Create new VM and install OS
$VM = 'blog01'
$ISO = "E:\Win10Entx64.iso"
$Path = "E:\Virtual Machines"
$SwitchName = 'External NIC'

New-VM –Name $VM –NewVHDPath (Join-Path $Path "$VM\$VM.vhdx") -NewVHDSizeBytes 40GB -SwitchName $SwitchName -Path $Path -Generation 2
Set-VMMemory -VMName $VM -DynamicMemoryEnabled $true -MinimumBytes 512MB -MaximumBytes 2048MB -Buffer 20 -StartupBytes 1024MB
Add-VMDvdDrive -VMName $VM -Path $ISO
Set-VMFirmware -VMName $VM -BootOrder $(Get-VMDvdDrive -VMName $VM),$(Get-VMHardDiskDrive -VMName $VM)
Start-VM $VM
vmconnect localhost $VM

All script from this post can also be find on my Gist page.

2 Comments

  1. zmbr December 11, 2017
    • Matthew Dowst December 11, 2017

Leave a Reply to Matthew Dowst Cancel reply