aunt — Auto Unattend

aunt automates Windows installation with AutoUnattend.xml and reduces image size.

Dependencies

Usage

aunt -h shows the help, aunt without argument checks dependencies then shows the help:

usage: aunt [-h] [-aimnqvy] [-e ED] [-k KEY] [-l LANG] [-p NAME] [-s SUF] ISO [FILE] ...

Auto Unattend 0.3

positional arguments:
  ISO                   Windows.iso to be automated
  FILE ...              include custom files and directories

optional arguments:
  -h, --help            show this help message and exit
  -a, --all             flags -mny
  -e ED, --edition ED   Core, CoreN, Professional... not -e: registry
  -i, --inplace         rewrite ISO
  -k KEY, --key KEY     auto-activate... not -k: limited features
  -l LANG, --lang LANG  en-US, fr-FR... not -l: lang.ini
  -m, --microsoft       no Microsoft account
  -n, --network         no network setup
  -p NAME, --pc NAME    computer name... not -p: PC
  -q, --quiet           no output
  -s SUF, --suffix SUF  append to ISO name... not -s: _
  -v, --verbose         detail actions in bash syntax
  -y, --yes             accept license

aunt Windows.iso rewrites the bootable UDF *.iso and shows the steps:

extract Windows.iso to _tmp
query EditionID
read lang.ini
read boot.wim
reduce boot.wim
read install.esd
reduce install.esd
write AutoUnattend.xml
write Windows.iso
delete _tmp

aunt -v Windows.iso details actions in bash syntax, grep mv rm words are handy for understanding what’s going on, although these actions are written in pure Python:

find dependencies
  C:\Program Files\7-Zip\7z.exe
  C:\Windows\System32\dism.exe
  C:\Program Files\Quix0\oscdimg.exe

extract Windows.iso to _tmp
  7z x -y -o_tmp Windows.iso bootmgr{,.efi} boot\{bcd,bood.sdi,bootfix.bin,etfsboot.com} efi\microsoft\boot\{bcd,efisys.bin} sources\{boot.wim,compres.dll,install.esd,lang.ini,setup.exe}

query EditionID
  reg query 'HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion' /v EditionID
  = Core

read lang.ini
  grep -Eom1 '^([a-z]{2}-[a-zA-Z]{2}) ' lang.ini
  = fr-fr

read boot.wim
  dism /Get-WimInfo /WimFile:boot.wim

reduce boot.wim
  dism /Export-Image /SourceImageFile:boot.wim /SourceIndex:2 /DestinationImageFile:boot.wim_
  mv boot.wim_ boot.wim

read install.esd
  dism /Get-WimInfo /WimFile:install.esd

reduce install.esd
  dism /Export-Image /SourceImageFile:install.esd /SourceIndex:1 /DestinationImageFile:install.esd_
  mv install.esd_ install.esd

write AutoUnattend.xml

write Windows_.iso
  oscdimg -u2 -bootdata:2#p0,e,b_tmp\boot\etfsboot.com#pEF,e,b_tmp\efi\microsoft\boot\efisys.bin _tmp Windows_.iso

delete _tmp
  rm -r _tmp

The dism commands above strips all Windows editions other than the one chosen by the -e option. Without -e assumes that the desired edition is the same as the host’s EditionID.

It is possible to include custom files and directories in ISO:

aunt Windows.iso ExecTI.exe python-3.7.2-amd64.exe

-a equals -mny, which generates an AutoUnattend.xml as below:

<?xml encoding="utf-8"?>
<unattend>
    <settings pass="WindowsPE">
        <component name="Microsoft-Windows-International-Core-WinPE" ...>
            <UILanguage>en-us</UILanguage>
        </component>
        <component name="Microsoft-Windows-Setup" ...>
            <ImageInstall>
                <OSImage>
                    <InstallFrom>
                        <MetaData>
                            <Key>/IMAGE/INDEX</Key>
                            <Value>1</Value>
                        </MetaData>
                    </InstallFrom>
                </OSImage>
            </ImageInstall>
            <UserData>
                <ProductKey>
                    <Key></Key>
                </ProductKey>
                <AcceptEula>true</AcceptEula>
            </UserData>
        </component>
    </settings>
    <settings pass="specialize">
        <component name="Microsoft-Windows-Shell-Setup" ...>
            <ComputerName>PC</ComputerName>
        </component>
    </settings>
    <settings pass="OOBESystem">
        <component name="Microsoft-Windows-International-Core" ...>
            <SystemLocale>en-us</SystemLocale>
        </component>
        <component name="Microsoft-Windows-Shell-Setup" ...>
            <OOBE>
                <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
                <HideOnlineAccountScreens>true</HideOnlineAccountScreens>
            </OOBE>
        </component>
    </settings>
</unattend>

Exit status:

0: success 1: missing file 2: missing edition in image file

Screens

Hidden screen, --lang or lang.ini sets the language:

_images/00.png

Hidden screen:

_images/01.png

Hidden screen, --key sets the activation key otherwise continues without a key:

_images/10.png

Hidden screen, --edition or host’s EditionID sets the Windows edition:

_images/11.png

--yes accepts the license and hides this screen:

_images/12.png

Hidden screen, chooses “Custom” installation:

_images/13.png

Displayed:

_images/14.png _images/15.png

3 hidden screens, --lang or lang.ini sets the language:

_images/20.png _images/21.png _images/22.png

--network hides these 2 screens:

_images/23.png _images/24.png

--microsoft hides these 2 screens:

_images/25.png _images/26.png

Displayed:

_images/27.png _images/28.png _images/30.png _images/31.png _images/32.png

Writing HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System\EnableFirstLogonAnimation = 0 in install.esd is the only way to hide this animation, <FirstLogonCommands> runs too late:

_images/40.png

Tests

💿 English x64 💿 French x64 — Home Pro Education [1]VirtualBox 6 — VMware 15:

1809: November 13, 2018 — Redstone 5
[1] Education edition is Enterprise edition without long-term support

Versions

0.3: March 10, 2019 — Include custom files, -i and -s options
0.2: February 20, 2019 — First beta release, UEFI
0.1: February 16, 2019 — First alpha release