windows-iac-vm-tooling/docs/03-packer/autounattend.md
root e4f03427b7
Some checks are pending
Build and Release / build-sign-package (push) Waiting to run
feat: Add professional hierarchical documentation
- Created comprehensive README.md with Mermaid diagrams, badges, and TOC
- Added docs/ directory with 7 sections and 14 markdown files
- Included architecture diagrams, flowcharts, and sequence diagrams
- All documentation is fully interlinked with cross-references
- Added ISO storage location on Proxmox development server
- Included troubleshooting guide and evaluation management docs
- All config files (Packer, Terraform, Ansible, Forgejo) documented
- Added icons and visual elements throughout documentation
2026-02-06 14:47:15 +00:00

7.7 KiB

📝 Autounattend.xml Guide

Windows

Overview

The Autounattend.xml file provides automated answers to Windows Setup questions. Packer injects this file to enable fully automated installation.

File Location: packer/Autounattend.xml


XML Structure

flowchart TB
    subgraph Unattend["Autounattend.xml"]
        direction TB
        Root[<unattend>] --> WindowsPE["pass='windowsPE'"] --> Specialize["pass='specialize'"]
        Specialize --> OOBE["pass='oobeSystem'"] --> UserAccounts["<UserAccounts>"]
        OOBE --> AutoLogon["<AutoLogon>"] --> FirstLogon["<FirstLogonCommands>"]
    end
    
    subgraph Purpose["Each Section"]
        WindowsPE[Language, Setup UI]
        Specialize[Computer Name, Timezone]
        OOBE[User Account, OOBE Screens]
        FirstLogon[WinRM, Firewall]
    end
    
    Unattend --> Purpose
    
    style Unattend fill:#e3f2fd
    style Purpose fill:#e8f5e9

Full Configuration

<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
  
  <!-- === Windows PE Phase === -->
  <settings pass="windowsPE">
    <component name="Microsoft-Windows-International-Core-WinPE" 
               processorArchitecture="amd64" 
               publicKeyToken="31bf3856ad364e35" 
               language="neutral" 
               versionScope="nonSxS">
      <SetupUILanguage>
        <UILanguage>en-US</UILanguage>
      </SetupUILanguage>
      <InputLocale>en-US</InputLocale>
      <SystemLocale>en-US</SystemLocale>
      <UILanguage>en-US</UILanguage>
      <UserLocale>en-US</UserLocale>
    </component>
    
    <component name="Microsoft-Windows-Setup" 
               processorArchitecture="amd64" 
               publicKeyToken="31bf3856ad364e35" 
               language="neutral" 
               versionScope="nonSxS">
      <UserData>
        <ProductKey>
          <Key></Key>  <!-- Evaluation version: no key needed -->
        </ProductKey>
        <AcceptEula>true</AcceptEula>
      </UserData>
    </component>
  </settings>
  
  <!-- === Specialize Phase === -->
  <settings pass="specialize">
    <component name="Microsoft-Windows-Shell-Setup" 
               processorArchitecture="amd64" 
               publicKeyToken="31bf3856ad364e35" 
               language="neutral" 
               versionScope="nonSxS">
      <ComputerName>*</ComputerName>  <!-- Auto-generate name -->
    </component>
    
    <component name="Microsoft-Windows-International-Core" 
               processorArchitecture="amd64" 
               publicKeyToken="31bf3856ad364e35" 
               language="neutral" 
               versionScope="nonSxS">
      <InputLocale>en-US</InputLocale>
      <SystemLocale>en-US</SystemLocale>
      <UILanguage>en-US</UILanguage>
      <UserLocale>en-US</UserLocale>
    </component>
    
    <component name="Microsoft-Windows-TerminalServices-LocalSessionManager" 
               processorArchitecture="amd64" 
               publicKeyToken="31bf3856ad364e35" 
               language="neutral" 
               versionScope="nonSxS">
      <fDenyTSConnections>false</fDenyTSConnections>
    </component>
  </settings>
  
  <!-- === OOBE System Phase === -->
  <settings pass="oobeSystem">
    <component name="Microsoft-Windows-Shell-Setup" 
               processorArchitecture="amd64" 
               publicKeyToken="31bf3856ad364e35" 
               language="neutral" 
               versionScope="nonSxS">
      <OOBE>
        <HideEULAPage>true</HideEULAPage>
        <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
        <HideOnlineAccountScreens>true</HideOnlineAccountScreens>
        <HideLocalAccountScreen>false</HideLocalAccountScreen>
        <ProtectYourPC>3</ProtectYourPC>
      </OOBE>
      
      <!-- Administrator Password -->
      <UserAccounts>
        <AdministratorPassword>
          <Value>PackerPassword123!</Value>
          <PlainText>true</PlainText>
        </AdministratorPassword>
      </UserAccounts>
      
      <!-- Auto-login (Count=1 = login once) -->
      <AutoLogon>
        <Enabled>true</Enabled>
        <Username>Administrator</Username>
        <LogonCount>1</LogonCount>
      </AutoLogon>
      
      <!-- First Logon Commands -->
      <FirstLogonCommands>
        <SynchronousCommand wcm:action="add">
          <CommandLine>powershell -Command "Set-NetFirewallProfile -Profile Private -Enabled False"</CommandLine>
          <Order>1</Order>
        </SynchronousCommand>
        <SynchronousCommand wcm:action="add">
          <CommandLine>powershell -Command "Invoke-WebRequest -Uri https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1 -OutFile C:\ConfigureRemotingForAnsible.ps1; C:\ConfigureRemotingForAnsible.ps1"</CommandLine>
          <Order>2</Order>
        </SynchronousCommand>
      </FirstLogonCommands>
    </component>
  </settings>
  
</unattend>

Critical Settings

⚠️ Auto-Login Configuration

<AutoLogon>
  <Enabled>true</Enabled>
  <Username>Administrator</Username>
  <LogonCount>1</LogonCount>  <!-- Login once, then stay logged in -->
</AutoLogon>

Why? Packer needs to connect via WinRM after the OS is installed. Auto-login allows WinRM to be configured and accessed.

⚠️ Firewall Configuration

<SynchronousCommand wcm:action="add">
  <CommandLine>powershell -Command "Set-NetFirewallProfile -Profile Private -Enabled False"</CommandLine>
  <Order>1</Order>
</SynchronousCommand>

Why? Ansible connects via WinRM on the Private network profile. If the firewall blocks WinRM, connection fails.

⚠️ WinRM Enablement

<SynchronousCommand wcm:action="add">
  <CommandLine>powershell -Command "Invoke-WebRequest -Uri https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1 -OutFile C:\ConfigureRemotingForAnsible.ps1; C:\ConfigureRemotingForAnsible.ps1"</CommandLine>
  <Order>2</Order>
</SynchronousCommand>

Why? This script configures WinRM for remote management by Ansible.


Pass Phases Explained

flowchart LR
    subgraph Phases["Windows Setup Phases"]
        direction LR
        PE[windowsPE<br/>Pre-installation] --> Spec[specialize<br/>Specialize] --> OOBE[oobeSystem<br/>OOBE] --> Desktop[Desktop<br/>Ready]
    end
    
    subgraph Actions["Key Actions"]
        PE[Load drivers<br/>Setup language] --> Spec[Computer name<br/>Timezone] --> OOBE[Create accounts<br/>Run commands]
    end
    
    style Phases fill:#e3f2fd
    style Actions fill:#e8f5e9
Pass Purpose Key Settings
windowsPE Pre-installation environment Language, keyboard
specialize Specialized configuration Computer name, timezone
oobeSystem Out-of-box experience User accounts, auto-logon, first commands

Troubleshooting

Issue Cause Solution
Packer timeout WinRM not ready Check FirstLogonCommands order
Cannot join domain ComputerName conflict Use * for auto-generate
Firewall blocking Private profile enabled Add firewall disable command
Auto-login fails Password complexity Use simple password for testing

Next Steps

Goal Next Document
Build template Packer Configuration
View Terraform OpenTofu Resources
Run pipeline Forgejo Workflows

← Documentation Index | ← Packer Configuration | → OpenTofu