Cover Image

netboot.xyz og automatisert Windows 11-installasjon

 Thu 2023-11-23    SysAdm

Hvordan installere Windows 11 automatisk uten å bli stilt et eneste spørsmål underveis i prosessen

Denne artikkelen tar for seg automatisk installasjon av Windows 11 fra nettverk via netboot.xyz og Windows PE.

Systemer som brukes:

  • Netboot.xyz
  • Windows 10/11 for å opprette WinPE-ISO
  • unRAID for
    • netboot.xyz-docker
    • Samba filshare
    • Virtuell maskin for testing

ADVARSEL: Dersom du følger stegene under og bruker de samme kommandoene og innstillingene, vil alle data på disken i målmaskinen gå tapt automatisk og uten noen spørsmål! LES OG FORSTÅ HVA ALLE KOMMANDOER OG INNSTILLINGER GJØR FØR DU STARTER EN INSTALLASJON PÅ DENNE MÅTEN.

Det anbefales på det sterkeste å teste i en virtuell maskin som ikke inneholder data man ønsker å ta vare på.

Steg 0: Forberedelser

Også kjent som "Dette må du ha på plass før du får gjort noe som helst", og dette må naturlig nok gjøres på en Windows-maskin.

  1. Installer netboot.xyz-docker på et passende sted. Sjekk at den funker ved å PXE-boote en virtuell maskin.
  2. Last ned og installer Windows ADK for Windows 11, version 22H2: https://go.microsoft.com/fwlink/?linkid=2243390
  3. Last ned og installer Windows PE addon for Windows ADK for Windows 11, version 22H2: https://go.microsoft.com/fwlink/?linkid=2243391
  4. Last ned siste versjon av Windows 11 ISO, pr 23.11.23 er det Windows 11 23H2. Plasser denne på NAS-serveren.
  5. Opprett et arbeidsområde:
    mkdir c:\tmp
  6. Opprett et mountpoint:
    mkdir c:\tmp\mount

Nå er vi klare til å opprette Windows PE bootable ISO.

Steg 1: Opprett arbeidsfiler

  1. Start Deployment and Imaging Tools Environment som administrator.
  2. Kjør copype for å opprette en arbeidskopi av PE-filene:
    copype amd64 c:\tmp\pe

Steg 2: Tilpass Windows PE (valgfritt)

Tilpasninger er vanlig å gjøre, men ikke alle installasjoner krever tilpasninger. Hvilke tilpasninger som skal gjøre avhenger av hvor og hvordan Windows 11 skal installeres. Det er ikke anbefalt å legge til for mange programmer eller drivere, da dette øker størrelsen på PE-imaget og installasjonen vil ta lenger tid.

Vurder å legge inn drivere for Wifi, Ethernet og diskkontrollere for at Windows Setup skal klare å installere systemet automatisk og uten at admin trenger passe på systemet.

Siden vi her skal lage en installasjon som kan installeres på hva som helst, trenger vi noen tilpasninger.

  1. Vi starter med å mounts boot.wim fra PE-arbeidsområdet:
    Start et cmd.exe-vindu som administrator
    c:
    cd \tmp
    dism /mount-image /imagefile:"c:\tmp\pe\media\sources\boot.wim" /index:1 /mountdir:"c:\tmp\mount"
  2. Output fra DISM:
    C:\tmp>dism /mount-image /imagefile:"c:\tmp\pe\media\sources\boot.wim" /index:1 /mountdir:"c:\tmp\mount"
    Deployment Image Servicing and Management tool
    Version: 10.0.19041.3636
    Mounting image
    [==========================100.0%==========================]
    The operation completed successfully.
  3. Kjør Notepad og rediger startnet.cmd:
    notepad mount\windows\system32\startnet.cmd
  4. I startnet.cmd, legg inn følgende:
    for %%s in (sCPU sSecureBoot sTPM) do reg add HKLM\SYSTEM\Setup\LabConfig /f /v Bypas%%sCheck /d 1 /t reg_dword
    wpeinit
    net use z: \\192.168.x.y\netboot\win11
    z:\setup.exe /unattend:x:\autounattend.xml

    VIKTIG: Endre 192.168.x.y til IP-adressen for din SAMBA-server.

    Lagre filen og lukk Notepad.

  5. Den årvåkne leser vil ha lagt merke til at det henvises til en autounattend.xml-fil i koden over. I samme administrative cmd-vindu, kjør:
    notepad mount\autounattend.xml
  6. Min autounattend.xml inneholder følgende:
    <?xml version="1.0" encoding="utf-8"?>
    <unattend xmlns="urn:schemas-microsoft-com:unattend" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
        <settings pass="offlineServicing"></settings>
        <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>0414:00000414</InputLocale>
                <SystemLocale>nb-NO</SystemLocale>
                <UILanguage>en-US</UILanguage>
                <UserLocale>nb-NO</UserLocale>
            </component>
            <component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
                <ImageInstall>
                    <OSImage>
                        <InstallTo>
                            <DiskID>0</DiskID>
                            <PartitionID>3</PartitionID>
                        </InstallTo>
                    </OSImage>
                </ImageInstall>
                <UserData>
                    <ProductKey>
                        <Key>VK7JG-NPHTM-C97JM-9MPGT-3V66T</Key>
                    </ProductKey>
                    <AcceptEula>true</AcceptEula>
                </UserData>
                <RunSynchronous>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>1</Order>
                        <Path>cmd.exe /c "&gt;&gt;"X:\diskpart.txt" echo SELECT DISK=0"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>2</Order>
                        <Path>cmd.exe /c "&gt;&gt;"X:\diskpart.txt" echo CLEAN"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>3</Order>
                        <Path>cmd.exe /c "&gt;&gt;"X:\diskpart.txt" echo CONVERT GPT"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>4</Order>
                        <Path>cmd.exe /c "&gt;&gt;"X:\diskpart.txt" echo CREATE PARTITION EFI SIZE=100"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>5</Order>
                        <Path>cmd.exe /c "&gt;&gt;"X:\diskpart.txt" echo FORMAT QUICK FS=FAT32 LABEL="System""</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>6</Order>
                        <Path>cmd.exe /c "&gt;&gt;"X:\diskpart.txt" echo CREATE PARTITION MSR SIZE=16"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>7</Order>
                        <Path>cmd.exe /c "&gt;&gt;"X:\diskpart.txt" echo CREATE PARTITION PRIMARY"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>8</Order>
                        <Path>cmd.exe /c "&gt;&gt;"X:\diskpart.txt" echo SHRINK MINIMUM=1000"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>9</Order>
                        <Path>cmd.exe /c "&gt;&gt;"X:\diskpart.txt" echo FORMAT QUICK FS=NTFS LABEL="Windows""</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>10</Order>
                        <Path>cmd.exe /c "&gt;&gt;"X:\diskpart.txt" echo CREATE PARTITION PRIMARY"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>11</Order>
                        <Path>cmd.exe /c "&gt;&gt;"X:\diskpart.txt" echo FORMAT QUICK FS=NTFS LABEL="Recovery""</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>12</Order>
                        <Path>cmd.exe /c "&gt;&gt;"X:\diskpart.txt" echo SET ID="de94bba4-06d1-4d40-a16a-bfd50179d6ac""</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>13</Order>
                        <Path>cmd.exe /c "&gt;&gt;"X:\diskpart.txt" echo GPT ATTRIBUTES=0x8000000000000001"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>14</Order>
                        <Path>cmd.exe /c diskpart /s X:\diskpart.txt &gt;&gt; X:\diskpart.log</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>15</Order>
                        <Path>reg.exe add "HKLM\SYSTEM\Setup\LabConfig" /v BypassTPMCheck /t REG_DWORD /d 1 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>16</Order>
                        <Path>reg.exe add "HKLM\SYSTEM\Setup\LabConfig" /v BypassSecureBootCheck /t REG_DWORD /d 1 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>17</Order>
                        <Path>reg.exe add "HKLM\SYSTEM\Setup\LabConfig" /v BypassStorageCheck /t REG_DWORD /d 1 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>18</Order>
                        <Path>reg.exe add "HKLM\SYSTEM\Setup\LabConfig" /v BypassRAMCheck /t REG_DWORD /d 1 /f</Path>
                    </RunSynchronousCommand>
                </RunSynchronous>
            </component>
        </settings>
        <settings pass="generalize"></settings>
        <settings pass="specialize">
            <component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
                <RunSynchronous>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>1</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.Microsoft3DViewer"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>2</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Clipchamp.Clipchamp"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>3</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.WindowsAlarms"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>4</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.549981C3F5F10"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>5</Order>
                        <Path>reg.exe delete "HKLM\SOFTWARE\Microsoft\WindowsUpdate\Orchestrator\UScheduler_Oobe\DevHomeUpdate" /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>6</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.WindowsFeedbackHub"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>7</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.GetHelp"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>8</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-caps.txt" echo Browser.InternetExplorer"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>9</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.WindowsMaps"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>10</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-caps.txt" echo MathRecognizer"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>11</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.ZuneVideo"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>12</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.BingNews"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>13</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.Office.OneNote"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>14</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-caps.txt" echo OpenSSH.Client"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>15</Order>
                        <Path>reg.exe delete "HKLM\SOFTWARE\Microsoft\WindowsUpdate\Orchestrator\UScheduler_Oobe\OutlookUpdate" /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>16</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.MSPaint"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>17</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.People"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>18</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.PowerAutomateDesktop"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>19</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-caps.txt" echo App.Support.QuickAssist"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>20</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo MicrosoftCorporationII.QuickAssist"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>21</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.SkypeApp"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>22</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.MicrosoftSolitaireCollection"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>23</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-caps.txt" echo App.StepsRecorder"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>24</Order>
                        <Path>reg.exe add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Communications" /v ConfigureChatAutoInstall /t REG_DWORD /d 0 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>25</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.Getstarted"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>26</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.Todos"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>27</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.WindowsSoundRecorder"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>28</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-caps.txt" echo Media.WindowsMediaPlayer"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>29</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.ZuneMusic"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>30</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-caps.txt" echo Microsoft.Windows.WordPad"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>31</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.Xbox.TCUI"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>32</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.XboxApp"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>33</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.XboxGameOverlay"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>34</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.XboxGamingOverlay"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>35</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.XboxIdentityProvider"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>36</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.XboxSpeechToTextOverlay"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>37</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.GamingApp"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>38</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\remove-packages.txt" echo Microsoft.YourPhone"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>39</Order>
                        <Path>powershell.exe -NoProfile -Command "Get-AppxProvisionedPackage -Online | where DisplayName -In (Get-Content $env:TEMP\remove-packages.txt ) | Remove-AppxProvisionedPackage -AllUsers -Online *&gt;&amp;1 &gt;&gt; $env:TEMP\remove-packages.log;"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>40</Order>
                        <Path>powershell.exe -NoProfile -Command "Get-WindowsCapability -Online | where {($_.Name -split '~')[0] -in (Get-Content $env:TEMP\remove-caps.txt ) } | Remove-WindowsCapability -Online *&gt;&amp;1 &gt;&gt; $env:TEMP\remove-caps.log;"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>41</Order>
                        <Path>cmd.exe /c "&gt;&gt;"C:\Users\Default\AppData\Local\Microsoft\Windows\Shell\LayoutModification.xml" echo ^&lt;LayoutModificationTemplate Version="1" xmlns="http://schemas.microsoft.com/Start/2014/LayoutModification"^&gt;"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>42</Order>
                        <Path>cmd.exe /c "&gt;&gt;"C:\Users\Default\AppData\Local\Microsoft\Windows\Shell\LayoutModification.xml" echo ^&lt;LayoutOptions StartTileGroupCellWidth="6" /^&gt;"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>43</Order>
                        <Path>cmd.exe /c "&gt;&gt;"C:\Users\Default\AppData\Local\Microsoft\Windows\Shell\LayoutModification.xml" echo ^&lt;DefaultLayoutOverride^&gt;"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>44</Order>
                        <Path>cmd.exe /c "&gt;&gt;"C:\Users\Default\AppData\Local\Microsoft\Windows\Shell\LayoutModification.xml" echo ^&lt;StartLayoutCollection^&gt;"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>45</Order>
                        <Path>cmd.exe /c "&gt;&gt;"C:\Users\Default\AppData\Local\Microsoft\Windows\Shell\LayoutModification.xml" echo ^&lt;StartLayout GroupCellWidth="6" xmlns="http://schemas.microsoft.com/Start/2014/FullDefaultLayout" /^&gt;"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>46</Order>
                        <Path>cmd.exe /c "&gt;&gt;"C:\Users\Default\AppData\Local\Microsoft\Windows\Shell\LayoutModification.xml" echo ^&lt;/StartLayoutCollection^&gt;"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>47</Order>
                        <Path>cmd.exe /c "&gt;&gt;"C:\Users\Default\AppData\Local\Microsoft\Windows\Shell\LayoutModification.xml" echo ^&lt;/DefaultLayoutOverride^&gt;"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>48</Order>
                        <Path>cmd.exe /c "&gt;&gt;"C:\Users\Default\AppData\Local\Microsoft\Windows\Shell\LayoutModification.xml" echo ^&lt;/LayoutModificationTemplate^&gt;"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>49</Order>
                        <Path>reg.exe add "HKLM\SOFTWARE\Microsoft\PolicyManager\current\device\Start" /v ConfigureStartPins /t REG_SZ /d "{ \"pinnedList\": [] }" /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>50</Order>
                        <Path>reg.exe add "HKLM\SOFTWARE\Microsoft\PolicyManager\current\device\Start" /v ConfigureStartPins_ProviderSet /t REG_DWORD /d 1 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>51</Order>
                        <Path>reg.exe add "HKLM\SOFTWARE\Microsoft\PolicyManager\current\device\Start" /v ConfigureStartPins_WinningProvider /t REG_SZ /d B5292708-1619-419B-9923-E5D9F3925E71 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>52</Order>
                        <Path>reg.exe add "HKLM\SOFTWARE\Microsoft\PolicyManager\providers\B5292708-1619-419B-9923-E5D9F3925E71\default\Device\Start" /v ConfigureStartPins /t REG_SZ /d "{ \"pinnedList\": [] }" /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>53</Order>
                        <Path>reg.exe add "HKLM\SOFTWARE\Microsoft\PolicyManager\providers\B5292708-1619-419B-9923-E5D9F3925E71\default\Device\Start" /v ConfigureStartPins_LastWrite /t REG_DWORD /d 1 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>54</Order>
                        <Path>reg.exe add "HKLM\SYSTEM\CurrentControlSet\Control\FileSystem" /v LongPathsEnabled /t REG_DWORD /d 1 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>55</Order>
                        <Path>reg.exe load "HKU\mount" "C:\Users\Default\NTUSER.DAT"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>56</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\sounds.ps1" echo New-PSDrive -PSProvider 'Registry' -Root 'HKEY_USERS' -Name 'HKU';"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>57</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\sounds.ps1" echo $excludes = Get-ChildItem -LiteralPath 'HKU:\mount\AppEvents\EventLabels' ^| "</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>58</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\sounds.ps1" echo Where-Object -FilterScript { ($_ ^| Get-ItemProperty).ExcludeFromCPL -eq 1; } ^| "</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>59</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\sounds.ps1" echo Select-Object -ExpandProperty 'PSChildName';"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>60</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\sounds.ps1" echo Get-ChildItem -Path 'HKU:\mount\AppEvents\Schemes\Apps\*\*' ^| "</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>61</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\sounds.ps1" echo Where-Object -Property 'PSChildName' -NotIn $excludes ^| "</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>62</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\sounds.ps1" echo Get-ChildItem -Include '.Current' ^| Set-ItemProperty -Name '(default)' -Value '';"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>63</Order>
                        <Path>cmd.exe /c "&gt;&gt;"%TEMP%\sounds.ps1" echo Remove-PSDrive -Name 'HKU';"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>64</Order>
                        <Path>powershell.exe -NoProfile -File "%TEMP%\sounds.ps1"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>65</Order>
                        <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\Runonce" /v "NoSounds" /t REG_SZ /d "C:\Windows\System32\reg.exe add \"HKCU\AppEvents\Schemes\" /ve /t REG_SZ /d \".None\" /f" /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>66</Order>
                        <Path>reg.exe unload "HKU\mount"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>67</Order>
                        <Path>reg.exe add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI\BootAnimation" /v DisableStartupSound /t REG_DWORD /d 1 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>68</Order>
                        <Path>reg.exe load "HKU\mount" "C:\Users\Default\NTUSER.DAT"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>69</Order>
                        <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "ContentDeliveryAllowed" /t REG_DWORD /d 0 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>70</Order>
                        <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "FeatureManagementEnabled" /t REG_DWORD /d 0 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>71</Order>
                        <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "OEMPreInstalledAppsEnabled" /t REG_DWORD /d 0 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>72</Order>
                        <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "PreInstalledAppsEnabled" /t REG_DWORD /d 0 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>73</Order>
                        <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "PreInstalledAppsEverEnabled" /t REG_DWORD /d 0 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>74</Order>
                        <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SilentInstalledAppsEnabled" /t REG_DWORD /d 0 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>75</Order>
                        <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SoftLandingEnabled" /t REG_DWORD /d 0 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>76</Order>
                        <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContentEnabled" /t REG_DWORD /d 0 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>77</Order>
                        <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-310093Enabled" /t REG_DWORD /d 0 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>78</Order>
                        <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-338387Enabled" /t REG_DWORD /d 0 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>79</Order>
                        <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-338388Enabled" /t REG_DWORD /d 0 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>80</Order>
                        <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-338389Enabled" /t REG_DWORD /d 0 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>81</Order>
                        <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-338393Enabled" /t REG_DWORD /d 0 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>82</Order>
                        <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-353698Enabled" /t REG_DWORD /d 0 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>83</Order>
                        <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SystemPaneSuggestionsEnabled" /t REG_DWORD /d 0 /f</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>84</Order>
                        <Path>reg.exe unload "HKU\mount"</Path>
                    </RunSynchronousCommand>
                    <RunSynchronousCommand wcm:action="add">
                        <Order>85</Order>
                        <Path>reg.exe add "HKLM\Software\Policies\Microsoft\Windows\CloudContent" /v "DisableWindowsConsumerFeatures" /t REG_DWORD /d 0 /f</Path>
                    </RunSynchronousCommand>
                </RunSynchronous>
            </component>
            <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
                <TimeZone>W. Europe Standard Time</TimeZone>
            </component>
        </settings>
        <settings pass="auditSystem"></settings>
        <settings pass="auditUser"></settings>
        <settings pass="oobeSystem">
            <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
                <InputLocale>0414:00000414</InputLocale>
                <SystemLocale>nb-NO</SystemLocale>
                <UILanguage>en-US</UILanguage>
                <UserLocale>nb-NO</UserLocale>
            </component>
            <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
                <UserAccounts>
                    <LocalAccounts>
                        <LocalAccount wcm:action="add">
                            <Name>adminbruker</Name>
                            <Group>Administrators</Group>
                            <Password>
                                <Value>SuperHemmeligPassord</Value>
                                <PlainText>true</PlainText>
                            </Password>
                        </LocalAccount>
                    </LocalAccounts>
                </UserAccounts>
                <AutoLogon>
                    <Username>sysadmin</Username>
                    <Enabled>true</Enabled>
                    <LogonCount>1</LogonCount>
                    <Password>
                        <Value>SuperHemmeligPassord</Value>
                        <PlainText>true</PlainText>
                    </Password>
                </AutoLogon>
                <OOBE>
                    <ProtectYourPC>3</ProtectYourPC>
                    <HideEULAPage>true</HideEULAPage>
                    <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
                </OOBE>
                <FirstLogonCommands>
                    <SynchronousCommand wcm:action="add">
                        <Order>1</Order>
                        <CommandLine>reg.exe add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v AutoLogonCount /t REG_DWORD /d 0 /f</CommandLine>
                    </SynchronousCommand>
                </FirstLogonCommands>
            </component>
        </settings>
    </unattend>
    Jeg brukte en unattend.xml-generator på https://schneegans.de/windows/unattend-generator/. Min config fjerner de fleste Windows 11-apper bortsett fra noen få jeg faktisk bruker, aktiverer diverse innstillinger, oppretter en administratorbruker med passord og logger denne inn automatisk ved behov, dropper requirements-sjekk (prosessor, TPM, etc). Hele installasjonen tar ca 20 minutter avhengig av hastigheten på nettet og maskinen.

    Lagre filen og lukk Notepad.

  7. (Valgfritt) Dette er et bra tidspunkt å legge inn drivere på dersom det skulle være nødvendig.

  8. Unmount boot.wim-imaget:
    C:\tmp>dism /unmount-image /mountdir:"c:\tmp\mount" /commit
    Deployment Image Servicing and Management tool
    Version: 10.0.19041.3636
    Saving image
    [==========================100.0%==========================]
    Unmounting image
    [==========================100.0%==========================]
    The operation completed successfully.
  9. Nå har vi tilpasset installasjonen vår og det er på tide å opprette den bootbare winpe.iso-filen.

    Tilbake i Deployment and Imaging Tools Environment-vinduet (som ligger og svever i bakgrunnen et sted), kjør:

    C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools>makewinpemedia /ISO c:\tmp\pe c:\tmp\winpe.iso
    Creating c:\tmp\winpe.iso...
    100% complete
    Success
  10. Kopier c:\tmp\winpe.iso til Netboot.xyz sin assets-mappe via FileZilla, scp, sftp eller tilsvarende, og pakk den ut (dette er på unRAID):

    cd /mnt/user/isos/netbootxyz/assets
    mkdir -p tmp WinPE/x64
    mount -o loop ./winpe.iso tmp
    cd tmp
    rsync -avh ./ ../WinPE/x64/
    cd ..
    umount tmp
  11. Vi må nå sette opp et nettverksshare med en utpakket Windows 11-ISOfil. Jeg bruker unRAID og opprettet et share som heter "netboot". Dette satt jeg til Secure (dvs read-only for alle, read/write for spesifikke brukere), uten passordbeskyttelse.
  12. Pakk ut ISO:
    cd /mnt/user/netboot
    mkdir Win11 ; cd Win11
    7z x /mnt/user/isos/Windows/11/Win11_23H2_English_x64.iso
    Alternativt:

    mkdir tmpmnt Win11
    mount -o loop ./Win11_23H2_English_x64.iso tmpmnt
    cd tmpmnt
    rsync -avh ./ ../Win11
    cd ..
    umount tmpmnt
  13. Jeg støtte på problemer relatert til tilgangsrettigheter, så jeg dro en chmod -R 0777 . i /mnt/user/netboot/Win11-mappen. Dette er kanskje ikke det tryggeste å gjøre, men det løste problemet jeg hadde slik at jeg kom meg videre i prosessen, og så kan jeg fundere på hva som er riktige tilganger ved en senere anledning.

  14. Da skal alt være klart til å netboote VM'en. I unRAID opprettet jeg en basic Win11-VM med 16GB RAM, 4 kjerner, 200GB disk, spesifiserte e1000 som nettverkskort siden virtio-net ikke alltid spiller ball, boot order 2 for NIC og Create.

  15. Maskinen startet fra nettverk og jeg anga http://192.168.x.y:8088/WinPE (igjen, angi din faktiske NAS-adresse) som lokasjon for Windows-filene og startet installasjonen. Scriptene ble kjørt og systemet installerte seg selv akkurat slik det var spesifisert at det skulle.

  16. Ved å opprette et PE-ISO med menybasert startnet.cmd og evt tilpassede (auto)unattend.xml-filer kan man enkelt boote og installere Windows 10, 11, Server 2019, Server 2022 avhengig av hva brukeren angir... se raske instrukser for dette under. :)

Bonus-segment: Multi-versjon-installasjon av Windows.

Det anbefales å bruke en noe mindre hissig versjon av autounattend.xml for denne typen deployment.

For multi-versjon-installasjon trenger man en ny versjon av startnet.cmd:


@echo off
goto premain

:premain
for %%s in (sCPU sSecureBoot sTPM) do reg add HKLM\SYSTEM\Setup\LabConfig /f /v Bypas%%sCheck /d 1 /t reg_dword
wpeinit
goto main

:main
echo Select:
echo  1) Windows 10 English
echo  2) Windows 10 Norsk
echo  3) Windows 11 English
echo  4) Windows 11 Norsk
echo  5) Windows Server 2019
echo  6) Windows Server 2022
set /P num=
if %num% == 1 goto w10e
if %num% == 2 goto w10n
if %num% == 3 goto w11e
if %num% == 4 goto w11n
if %num% == 5 goto ws19
if %num% == 6 goto ws22

:w10e
ping -n 1 %ip% | find "TTL=" || goto w10e
net use z: \\192.168.x.y\netboot\win10\en
z:\setup.exe /unattend:x:\autounattend.xml
goto end

:w10n
ping -n 1 %ip% | find "TTL=" || goto w10n
net use z: \\192.168.x.y\netboot\win10\no
z:\setup.exe /unattend:x:\autounattend.xml
goto end

:w11e
ping -n 1 %ip% | find "TTL=" || goto w11e
net use z: \\192.168.x.y\netboot\win11\en
z:\setup.exe /unattend:x:\autounattend.xml
goto end

:w11n
ping -n 1 %ip% | find "TTL=" || goto w11n
net use z: \\192.168.x.ynetboot\win11\no
z:\setup.exe /unattend:x:\autounattend.xml
goto end

:ws19
ping -n 1 %ip% | find "TTL=" || goto ws19
net use z: \\192.168.x.y\netboot\ws19
z:\setup.exe /unattend:x:\autounattend.xml
goto end

:ws22
ping -n 1 %ip% | find "TTL=" || goto ws22
net use z: \\192.168.x.y\netboot\ws22
z:\setup.exe /unattend:x:\autounattend.xml
goto end

:end
echo Thank you for playing.

I tillegg må man forberede Samba-shareområdet "netboot". Som man kan se i den menybaserte startnet.cmd-filen over henvises det til forskjellige undermapper under \\192.168.x.y\netboot\.

Jeg la opp filområdet mitt slik:

\netboot\win10\en
\netboot\win10\no
\netboot\win11\en
\netboot\win11\no
\netboot\ws19
\netboot\ws22

Hver av disse mappene inneholder en utpakket installasjons-ISO for hhv Windows 10 engelsk/norsk, Windows 11 engelsk/norsk, Windows Server 2019 og 2022. Basert på hvilket menyvalg man velger under oppstarten vil riktig filområde mappes opp, og setup-filen vil kjøres med unattend-filen som parameter.

Jeg har ikke testet installasjon av Windows Server med autounattend.xml-filen jeg opprettet, da jeg ikke vet hvordan den vil funke med disse versjonene. Filen er laget for unattended deployment av Windows 10/11, derfor anbefalingen over om å benytte en mindre hissig unattend-fil. Eksperimenter på eget ansvar - derfor en virtuell maskin for testing.

Jeg har testet installasjon uten unattend-fil og det fungerer 100% som forventet - man får opp standard WS-installasjonsflyt og ender opp med en helt generisk, ikke-aktivert serverinstallasjon. Samme med Windows 10/11 - man får standard OOBE-oppsettsrutine og alt er som forventet.