Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/flick9000/winscript/llms.txt

Use this file to discover all available pages before exploring further.

The autounattend.xml file produced by Winscript is a valid, self-contained Windows answer file — but it also uses several techniques that go beyond the baseline Microsoft unattend schema. This page documents those internals so you can understand exactly what runs during setup and, if needed, extend or modify the generated file for your own requirements.
Do not share your autounattend.xml file with others. Depending on your configuration, it may contain your local account username or other personally identifiable setup preferences. Treat it with the same care as any other credential-bearing configuration file.

Specialize Phase

The specialize pass runs after the OS image is copied to disk but before the first boot into the installed system. Winscript extracts and then executes Specialize.ps1 during this pass. The script runs three registry operations in sequence, reporting progress to a log file: 1. Disables CloudOptimizedContent
reg.exe add "HKLM\Software\Policies\Microsoft\Windows\CloudContent" /v "DisableCloudOptimizedContent" /t REG_DWORD /d 1 /f
Prevents Windows from delivering cloud-curated content (such as suggested apps and spotlight content) during and after setup. 2. Sets BypassNRO to allow local accounts
reg.exe add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\OOBE" /v BypassNRO /t REG_DWORD /d 1 /f
BypassNRO (Bypass Network Requirement at OOBE) is required on Windows 11 to guarantee that the system allows local account creation even if a network is available. Without this, Windows 11 may still prompt for a Microsoft account. 3. Disables Windows Update during setup
reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" /v NoAutoUpdate /t REG_DWORD /d 1 /f
reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" /v DisableWindowsUpdateAccess /t REG_DWORD /d 1 /f
Prevents Windows Update from downloading or installing updates while the machine is still being configured. Both keys are deleted again at first logon once setup is complete. Progress reporting and logging All three script blocks are wrapped in a loop that calls Write-Progress to display a progress bar in the PowerShell window during execution. The full output — including each command’s text, its start time, and execution duration — is written to:
C:\Windows\Setup\Scripts\Specialize.log
This log is useful for diagnosing failures if the specialize phase stalls or errors.

FirstLogon Phase

FirstLogon.ps1 runs as a FirstLogonCommand in the oobeSystem pass — meaning it executes the first time a user logs into the desktop after OOBE completes. It performs three tasks in order: 1. Re-enables network adapters
Get-NetAdapter | Enable-NetAdapter -Confirm:$false
All network adapters were disabled at the end of the specialize pass. This command brings them all back online so the desktop session has internet access. 2. Re-enables Windows Update
Write-Host -ForegroundColor Green '-- Re-enabling Windows Update after OOBE'
reg.exe delete "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" /v NoAutoUpdate /f
reg.exe delete "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" /v DisableWindowsUpdateAccess /f
Removes the two policy values that were applied during specialize, restoring Windows Update to its default behaviour. 3. Executes your Winscript configuration
& 'C:\Windows\Setup\Scripts\winscript.ps1'
Runs the embedded Winscript PS1 file — applying all the tweaks, debloat options, and privacy settings you selected before generating the autounattend.xml.

Script Extraction Mechanism

The Extensions block in the generated XML uses a custom namespace (urn:winscript:unattend) to store both the scripts themselves and the logic needed to write them to disk. This is a Winscript-specific design and is not part of the standard Microsoft unattend schema.
The Extensions namespace urn:winscript:unattend is not recognised or processed by the Windows Setup engine. It is read exclusively by the inline PowerShell ExtractScript scriptblock that Winscript invokes during the specialize pass.

How ExtractScript works

During the specialize pass, the first RunSynchronousCommand invokes PowerShell to load the answer file as an XML document and execute the ExtractScript scriptblock inline:
powershell.exe -WindowStyle "Normal" -NoProfile -Command `
  "$xml = [xml]::new(); $xml.Load('C:\Windows\Panther\unattend.xml'); `
  $sb = [scriptblock]::Create( $xml.unattend.Extensions.ExtractScript ); `
  Invoke-Command -ScriptBlock $sb -ArgumentList $xml;"
The scriptblock itself iterates over every <File> child of Extensions, resolves the path attribute (expanding any environment variables), creates the parent directory if it does not exist, selects the correct encoding based on the file extension, and writes the file to disk:
<Extensions xmlns="urn:winscript:unattend">
  <ExtractScript>
param(
    [xml] $Document
);

foreach( $file in $Document.unattend.Extensions.File ) {
    $path = [System.Environment]::ExpandEnvironmentVariables( $file.GetAttribute( 'path' ) );
    mkdir -Path( $path | Split-Path -Parent ) -ErrorAction 'SilentlyContinue';
    $encoding = switch( [System.IO.Path]::GetExtension( $path ) ) {
        { $_ -in '.ps1', '.xml' } { [System.Text.Encoding]::UTF8; }
        { $_ -in '.reg', '.vbs', '.js' } { [System.Text.UnicodeEncoding]::new( $false, $true ); }
        default { [System.Text.Encoding]::Default; }
    };
    $bytes = $encoding.GetPreamble() + $encoding.GetBytes( $file.InnerText.Trim() );
    [System.IO.File]::WriteAllBytes( $path, $bytes );
}
  </ExtractScript>
  <File path="C:\\Windows\\Setup\\Scripts\\winscript.ps1">
    ... your embedded script content ...
  </File>
</Extensions>

Encoding behaviour

The script selects encoding based on file extension:
ExtensionEncoding
.ps1, .xmlUTF-8 (with BOM)
.reg, .vbs, .jsUTF-16 LE (with BOM)
All othersSystem default encoding
This ensures that each extracted file type is written with the encoding that its respective runtime expects — PowerShell scripts in UTF-8, registry files in UTF-16 LE, and so on.

Adding your own embedded files

You can manually add additional <File> elements to the Extensions block to have arbitrary files extracted during the specialize phase. Each element must have a path attribute pointing to the absolute destination path on the target system, with any embedded special XML characters properly escaped. The ExtractScript logic handles all file types that match the encoding table above automatically.

Product Key

The generated XML includes a placeholder product key in the windowsPE pass:
<ProductKey>
  <Key>00000-00000-00000-00000-00000</Key>
  <WillShowUI>Always</WillShowUI>
</ProductKey>
Setting WillShowUI to Always means Windows Setup will always display the product key entry screen, regardless of whether the placeholder key is present. This is intentional — Winscript does not embed a real product key, so you will be prompted to enter one (or skip it, if installing an evaluation edition) during setup. If you want to supply a key automatically, replace the placeholder value and change WillShowUI to Never.

Build docs developers (and LLMs) love