Windows: Sysprep ohne OOBE

Sysprep ist eine feine Sache, um eine Master-Windows-Installation für die Verteilung vorzubereiten.

Mit am wichtigsten ist dabei, das eine neue SID (Sicherheitskennung) für das System generiert wird, damit es später in der Domäne, im WSUS und mehr keine Schwierigkeiten gibt.

Ein Nachteil von Sysprep kann sein, das nach dessen Ausführung man das gesamte OOBE (Out-of-the-Box Experience) durchlaufen muss. Es erscheinen also die ganzen Abfragen nach Sprache, WLAN, Cloud-Anbindung bzw. lokalen Benutzer anlegen, usw.

Mitunter ist das allerdings gar nicht gewünscht oder notwendig und man möchte den bei der Erst-Einrichtung angelegten Benutzer (samt Profil) sogar behalten.

Mit einer kleinen Antwortdatei kann man das alles umgehen:

<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
 <settings pass="oobeSystem">
  <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <OOBE>
    <HideEULAPage>true</HideEULAPage>
    <HideLocalAccountScreen>true</HideLocalAccountScreen>
    <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
    <HideOnlineAccountScreens>true</HideOnlineAccountScreens>
    <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
    <NetworkLocation>Other</NetworkLocation>
    <ProtectYourPC>3</ProtectYourPC>
    <SkipMachineOOBE>true</SkipMachineOOBE>
    <SkipUserOOBE>true</SkipUserOOBE>
    <UnattendEnableRetailDemo>false</UnattendEnableRetailDemo>
   </OOBE>
  </component>
 </settings>
</unattend>

Gestartet wird Sysprep dann mit folgendem Aufruf:

C:\Windows\System32\Sysprep\sysprep.exe /generalize /shutdown /oobe /unattend:C:\Sysprep\deploy.xml

Nachdem das System heruntergefahren ist, kann man die Antwortdatei entfernen und das Laufwerk klonen bzw. ein Image für die Verteilung erstellen.

Quelle

Bart Simons – Sysprep generalize Windows image without OOBE

Microsoft – Docs – Generalisieren einer Windows-Installation (Systemvorbereitung)

4 Kommentare

  • … hier eine Stolperfalle:

    Die Disk GUID wird von sysprep aber nicht geändert, was dazu führt, dass sich nicht zwei von diesem Image abgeleitete virtuelle Disks z.B. gleichzeitig mounten lassen, was viele Backup Programme tun.

    Diese Powershell Zeilen ändern die GPT Disk-GUID von C: (idealerweise direkt beim Ausrollen):

    # neue GUID’s vergeben und Bootmanager anpassen:
    Get-Disk | Select Guid
    $newguid = [GUID]::NewGuid()
    $guid = [string]$newguid
    Set-Disk -Number 0 -Guid “{$guid}”
    bcdedit /set “{current}” device partition=C:
    bcdedit /set “{current}” osdevice partition=C:
    bcdedit /default “{current}”
    Get-Disk | Select Guid

  • “/mode:vm” ist bei Sysprep das passende bei Generalisieren einer VHD(X) zur Verwendung auf dem gleichen Hyper-V bzw. Host:

    Sysprep Command-Line-Optionen – /mode:vm

  • … das weiß ich auch…. funktioniert nur nicht. Ich hatte ´ne Menge Probleme dadurch, das nachträgliche ändern der GUID ist Gott sei Dank kein Problem.

    Wenn man die VMs per Powershell anlegt, kann man das auch dabei gleich erledigen:

    [..]

    # leitet VHDx aus der Vorlage ab, mounten in Anwesenheit des Templates um wegen Disksignaturfehler neue GUID zu erzwingen
    New-Item “$VMPath$VMNameVirtual Hard Disks” –Type Directory
    Copy-Item $TemplateVHDX “$VMPath$VMNameVirtual Hard Disks$VMName.vhdx” -PassThru
    Set-VHD -Path “$VMPath$VMNameVirtual Hard Disks$VMName.vhdx” -ResetDiskIdentifier -Force -Passthru
    Mount-VHD -Path “$VMPath$VMNameVirtual Hard Disks$VMName.vhdx” -NoDriveLetter -PassThru

    $guid = [GUID]::NewGuid()
    $connecthost = $env:COMPUTERNAME
    $uniqueIds = Invoke-Command -Computername $connecthost {Get-Disk}
    ForEach ($uniqueId in $uniqueIds)
    {
    If ($uniqueId.FriendlyName -like “Msft Virtual Disk”)
    {
    $disknumber = $uniqueId.Number
    $cmds = “`”SELECT DISK $disknumber`””,
    “`”UNIQUEID DISK ID=$guid`””
    $scriptblock = [string]::Join(“,”,$cmds)
    $diskpart =$ExecutionContext.InvokeCommand.NewScriptBlock(“$scriptblock | DISKPART”)
    Invoke-Command -ComputerName $connecthost -ScriptBlock $diskpart
    }
    }

    Dismount-VHD -Path “$VMPath$VMNameVirtual Hard Disks$VMName.vhdx” -PassThru

    [..]

  • > … das weiß ich auch…. funktioniert nur nicht.

    Ah ok, verstehe, dieser Kontext fehlte mir im vorigen Kommentar.
    Gut zu Wissen, das man die Sache (nachträglich) korrigieren kann.

    Vielen Dank für dein Feedback.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.