Hinzufügen eines Updatepakets zu Windows RE
Sie können ein Update, entweder eine LCU oder ein Safe OS Dynamic Update (DU) auf ein Windows RE-Image anwenden. Die Schritte zum Aktualisieren eines Windows RE-Images variieren abhängig davon, ob Sie ein Offline-Image oder ein Image auf einem laufenden System aktualisieren.
- Beim Hinzufügen einer LCU: Überprüfen Sie sowohl vor dem Hinzufügen eines Updates als auch danach die WinRE-Versionsnummer, um sicherzustellen, dass das Update ordnungsgemäß angewendet wurde.
- Beim Hinzufügen eines DU-Pakets: Nachdem Sie das Paket hinzugefügt haben, überprüfen Sie die Paketliste im Image, um sicherzustellen, dass das Paket erfolgreich zum Image hinzugefügt wurde.
Aktualisieren eines Offline-Images
Die folgenden Schritte beschreiben, wie Sie einem Windows RE-Offline-Image ein aktualisiertes Paket hinzufügen.
Einbinden Ihres Windows-Images
Das Windows RE-Image (winre.wim) ist im Windows-Image (install.wim) enthalten und wird letztlich auf die Windows RE-Tools-Partition auf dem Ziel-PC oder -Gerät kopiert. Um das WinRE-Image zu ändern, müssen Sie zuerst das Windows-Image und dann das Windows RE-Image einbinden. Nachdem beide Images eingebunden wurden, können Sie Ihre Änderungen vornehmen, die Einbindung des WinRE-Images aufheben und anschließend die Einbindung des Windows-Images aufheben.
Erstellen Sie ein Bereitstellungsverzeichnis, und binden Sie „install.wim“ ein:
md C:\mount\windows Dism /Mount-Wim /WimFile:C:\images\install.wim /index:1 /MountDir:C:\mount\windows
Einbinden Ihres WinRE-Images
Binden Sie das Windows RE-Image über Ihr eingebundenes Image ein.
Md c:\mount\winre Dism /Mount-Wim /WimFile:C:\mount\windows\Windows\System32\Recovery\winre.wim /index:1 /MountDir:C:\mount\winre
Tipp
Wenn die Datei „winre.wim“ im angegebenen Verzeichnis nicht angezeigt wird, legen Sie die Datei mit dem folgenden Befehl als sichtbar fest:
attrib -h -a -s C:\mount\windows\Windows\System32\Recovery\winre.wim
Hinzufügen eines Updatepakets zur WinRE
Nachdem Ihr Wiederherstellungsimage eingebunden wurde, können Sie das Update zur Behebung des Problems hinzufügen.
Laden Sie das benötigte Updatepaket herunter, und fügen Sie es Ihrem Wiederherstellungsimage hinzu.
Dism /Add-Package /Image:C:\mount\winre /PackagePath:"c:\downloadedupdate\update.msu"
oder
Dism /Add-Package /Image:C:\mount\ /PackagePath:"c:\downloadedupdate\dynamicupdate.cab"
Wenn Sie ein Paket für ein dynamisches Update hinzugefügt haben, überprüfen Sie, ob sich das hinzugefügte Paket in Ihrem Image befindet:
Dism /Image:C:\mount\ /Get-Packages
Überprüfen Sie die Liste auf das soeben hinzugefügte Updatepaket. Das Paket sollte die KB-Anzahl enthalten, und
State
wird alsInstalled
angezeigt, wenn es erfolgreich hinzugefügt wurde:Package Identity : Package_for_KB5021041~31bf3856ad364e35~amd64~~22621.815.1.0 State : Installed Release Type : Update
Bereinigen Sie Ihr Wiederherstellungsimage, und setzen Sie die Basis für alle abgelösten Komponenten zurück:
dism /image:C:\mount /cleanup-image /StartComponentCleanup /ResetBase
Aufheben der Bereitstellung Ihrer Images
Schließen Sie alle Anwendungen, die möglicherweise auf Dateien im Image zugreifen, einschließlich des Datei-Explorers.
Übernehmen Sie die Änderungen, und heben Sie die Bereitstellung des Windows RE-Images auf:
Dism /Unmount-Image /MountDir:"C:\mount\winre" /Commit
Dieser Prozess kann einige Minuten in Anspruch nehmen.
Übernehmen Sie die Änderungen, und heben Sie die Einbeziehung des Windows-Images auf:
Dism /Unmount-Image /MountDir:"C:\mount\windows" /Commit
„C“ steht für den Laufwerkbuchstaben des Laufwerks mit dem Image. Dieser Vorgang kann mehrere Minuten dauern.
Das Windows RE-Image ist jetzt aktualisiert und Bestandteil des größeren Windows-Images.
Anwenden des Updates auf einen ausgeführten PC
Sie können den Fix auf das Windows-Wiederherstellungsimage auf einem ausgeführten PC anwenden. Die folgenden Schritte beschreiben, wie Sie ein Windows-Wiederherstellungsimage bereitstellen, ein Update darauf anwenden und dann die Änderungen speichern:
Öffnen Sie als Administrator eine Eingabeaufforderung.
Erstellen Sie ein Verzeichnis, in dem Sie das Wiederherstellungsimage bereitstellen können, um Änderungen daran vorzunehmen.
md c:\mount
Binden Sie Ihr Wiederherstellungsimage mit REAgentC ein:
ReAgentC.exe /mountre /path c:\mount
Wenn Ihr Wiederherstellungsimage eingebunden wurde, können Sie das Updatepaket herunterladen und dem Windows RE-Image hinzufügen.
Dism /Add-Package /Image:C:\mount\ /PackagePath:"c:\downloadedupdate\update.msu"
oder
Dism /Add-Package /Image:C:\mount\ /PackagePath:"c:\downloadedupdate\dynamicupdate.cab"
Wenn Sie ein Paket für ein dynamisches Update hinzugefügt haben, überprüfen Sie, ob sich das hinzugefügte Paket in Ihrem Image befindet:
Dism /Image:C:\mount\ /Get-Packages
Überprüfen Sie die Liste auf das soeben hinzugefügte Updatepaket. Das Paket sollte die KB-Anzahl enthalten, und
State
wird alsInstalled
angezeigt, wenn es erfolgreich hinzugefügt wurde:Package Identity : Package_for_KB5021041~31bf3856ad364e35~amd64~~22621.815.1.0 State : Installed Release Type : Update
Bereinigen Sie Ihr Wiederherstellungsimage, und setzen Sie die Basis für alle abgelösten Komponenten zurück:
dism /image:C:\mount /cleanup-image /StartComponentCleanup /ResetBase
Heben Sie die Einbindung des Windows-Wiederherstellungsimages auf:
ReAgentC.exe /unmountre /path c:\mount /commit
Wenn der Datenträger des PCs durch BitLocker oder Geräteverschlüsselung geschützt ist: Verwenden Sie
ReagentC
, um Windows RE zu deaktivieren und dann erneut zu aktivieren. Dadurch wird sichergestellt, dass das aktualisierte Windows RE-Image aktiviert und ordnungsgemäß für Ihre Windows-Installation konfiguriert ist:reagentc /disable reagentc /enable
Das Windows RE-Image auf dem laufenden PC ist nun aktualisiert.
Überprüfen der WinRE-Imageversion
Sie können die Versionsnummer des WinRE-Images sowohl bei Online- als auch bei Offlineinstallationen von Windows überprüfen. Dies kann hilfreich sein, um die WinRE-Version vor dem Hinzufügen eines Updates und dann nach dem Anwenden eines Updates zu überprüfen und sicherzustellen, dass das Update erfolgreich hinzugefügt wurde.
Hinweis
Die WinRE-Versionsnummer ändert sich erst, nachdem Sie eine LCU hinzugefügt haben. Wenn Sie ein DU-Paket hinzufügen, verwenden Sie DISM /get-packages, wie in den obigen Schritten beschrieben, um sicherzustellen, dass das Paket dem Image hinzugefügt wurde.
Überprüfen der Windows RE-Version in einem Windows-Onlinebetriebssystem
Verwenden Sie ReagentC, um den Speicherort des installierten WinRE-Images zu finden, indem Sie den folgenden Befehl ausführen:
reagentc /info
Dieser Befehl gibt den Windows RE-Speicherort zurück, ähnlich wie im folgenden Beispiel:
\\?\GLOBALROOT\device\harddisk0\partition4\Recovery\WindowsRE
Verwenden Sie DISM, um Versionsinformationen zum winre.wim-Image abzurufen, das sich im Pfad befindet, der im vorherigen Schritt von ReagentC zurückgegeben wurde. Fügen Sie beim Ausführen des Befehls unbedingt den WinRE-Imagenamen und die Imageindexnummer zum Pfad hinzu:
Dism /Get-ImageInfo /ImageFile:\\?\GLOBALROOT\device\harddisk0\partition4\Recovery\WindowsRE\winre.wim /index:1
Beachten Sie die Version im Bericht. Beispiel:
Version : 10.0.22621 ServicePack Build : 1 ServicePack Level : 0
Stellen Sie sicher, dass
ServicePackBuild
größer oder gleich der UBR für das hinzugefügte Update ist. Beispielsweise wird für Windows 11 Version 22H2 für das November-Sicherheitsupdate819
alsSerivcePack Build
angezeigt, weil die vollständige Versionsnummer für dieses Update 22621.819 lautet.- Wenn es sich bei der gemeldeten Version um eine frühere Version handelt, gibt dies an, dass das Windows RE-Image nicht auf dem neuesten Stand ist.
- Wenn die gemeldete Version dieselbe oder eine höhere Version ist, ist keine Aktion erforderlich.
Überprüfen der Windows RE-Version in einem Windows-Offlinebetriebssystem
Stellen Sie das Windows-Image in einen lokalen Ordner bereit, z. B. C:\mount\windows:
mkdir C:\mount\windows Dism /Mount-Image /ImageFile:C:\mount\install.wim /Index:1 /MountDir:C:\mount\windows
Verwenden Sie DISM, um Versionsinformationen zum winre.wim-Image abzurufen, das sich im Ordner
Windows\system32\recovery
befindet. Geben Sie beim Ausführen des Befehls unbedingt die Indexnummer des Images an:Dism /Get-ImageInfo /ImageFile:c:\mount\windows\windows\system32\recovery\winre.wim /index:1
Beachten Sie die Version im Bericht. Beispiel:
Version : 10.0.22621 ServicePack Build : 1 ServicePack Level : 0
Stellen Sie sicher, dass
ServicePackBuild
größer oder gleich der UBR für das hinzugefügte Update ist. Beispielsweise wird für Windows 11 Version 22H2 für das November-Sicherheitsupdate819
alsSerivcePack Build
angezeigt, weil die vollständige Versionsnummer für dieses Update 22621.819 lautet.- Wenn es sich bei der gemeldeten Version um eine frühere Version handelt, gibt dies an, dass das Windows RE-Image nicht auf dem neuesten Stand ist.
- Wenn die gemeldete Version dieselbe oder eine höhere Version ist, ist keine Aktion erforderlich.
Erweitern der Windows RE-Partition
Das folgende Beispielskript kann verwendet werden, um die Größe der Wiederherstellungspartition für eine erfolgreiche Aktualisierung der Windows Recovery Environment (WinRE) zu erhöhen. Es wird empfohlen, 250 MB freien Speicherplatz auf der Wiederherstellungspartition zu haben, damit WinRE-Updates erfolgreich installiert werden können. Auf Geräten, bei denen nicht ausreichend freier Speicherplatz auf der Wiederherstellungspartition verfügbar ist, kann die Wiederherstellungspartition mit dem folgenden Beispielskript um 250 MB erweitert werden.
Starten Sie Ihren Computer neu, bevor Sie das Skript ausführen. Dies ist wichtig, da auf Ihrem Computer möglicherweise ausstehende Partitionsvorgänge vorhanden sind, die abgeschlossen werden müssen, bevor das Skript die WinRE-Partitionsgröße sicher erhöhen kann. Nachdem Ihr Computer neu gestartet wurde, öffnen Sie PowerShell als Administrator, und führen Sie mkdir <Pfad zum neuen Sicherungsverzeichnis> aus. Damit wird ein Sicherungsverzeichnis erstellt, das das Skript bei einem Fehler beim Wiederherstellen der ursprünglichen Partition verwenden kann. Notieren Sie sich den Speicherort dieses Sicherungsverzeichnisses, da das Skript nach Ihrem Sicherungspfad fragen wird. Wenn Sie diesen umfassend bereitstellen, können Sie die Skriptaufforderung umgehen, indem Sie die folgenden Parameter verwenden:
"<Skriptdatei> -SkipConfirmation $true -BackupFolder <Ordner für die Sicherung>"
Beispiel:
Resize_script.ps1 -SkipConfirmation $true -BackupFolder c:\winre_backup
Param (
[Parameter(Mandatory=$false,HelpMessage="Skip confirmation")][bool]$SkipConfirmation=$false,
[Parameter(Mandatory=$true,HelpMessage="Path to backup old WinRE partition content to")][string]$BackupFolder
)
# ------------------------------------
# Helper functions
# ------------------------------------
# Log message
function LogMessage([string]$message)
{
$message = "$message"
Write-Host $message
}
# Extract numbers from string
function ExtractNumbers([string]$str)
{
$cleanString = $str -replace "[^0-9]"
return [long]$cleanString
}
# Display partition info using fsutil
# Return an array, the first value is total size and the second value is free space
function DisplayPartitionInfo([string[]]$partitionPath)
{
$volume = Get-WmiObject -Class Win32_Volume | Where-Object { $partitionPath -contains $_.DeviceID }
LogMessage(" Partition capacity: " + $volume.Capacity)
LogMessage(" Partition free space: " + $volume.FreeSpace)
return $volume.Capacity, $volume.FreeSpace
}
# Display WinRE status
function DisplayWinREStatus()
{
# Get WinRE partition info
$WinREInfo = Reagentc /info
foreach ($line in $WinREInfo)
{
$params = $line.Split(':')
if ($params.Count -lt 2)
{
continue
}
if (($params[1].Trim() -ieq "Enabled") -Or (($params[1].Trim() -ieq "Disabled")))
{
$Status = $params[1].Trim() -ieq "Enabled"
LogMessage($line.Trim())
}
if ($params[1].Trim() -like "\\?\GLOBALROOT*")
{
$Location = $params[1].Trim()
LogMessage($line.Trim())
}
}
return $Status, $Location
}
# ------------------------------------
# Main execution
# ------------------------------------
# Clear the error
$Error.Clear()
# ------------------------------------
# Examining the system to collect required info
# for the execution
# Need to check WinRE status, collect OS and WinRE
# partition info
# ------------------------------------
LogMessage("Start time: $([DateTime]::Now)")
LogMessage("Examining the system...")
$NeedShrink = $true
$NeedCreateNew = $false
$NeedBackup = $false
# Get WinRE partition info
$InitialWinREStatus = DisplayWinREStatus
$WinREStatus = $InitialWinREStatus[0]
$WinRELocation = $InitialWinREStatus[1]
if (!$WinREStatus)
{
LogMessage("Error: WinRE Disabled")
exit 1
}
# Get System directory and ReAgent xml file
$system32Path = [System.Environment]::SystemDirectory
LogMessage("System directory: " + $system32Path)
$ReAgentXmlPath = Join-Path -Path $system32Path -ChildPath "\Recovery\ReAgent.xml"
LogMessage("ReAgent xml: " + $ReAgentXmlPath)
if (!(Test-Path $ReAgentXmlPath))
{
LogMessage("Error: ReAgent.xml cannot be found")
exit 1
}
# Get OS partition
LogMessage("")
LogMessage("Collecting OS and WinRE partition info...")
$OSDrive = $system32Path.Substring(0,1)
$OSPartition = Get-Partition -DriveLetter $OSDrive
# Get WinRE partition
$WinRELocationItems = $WinRELocation.Split('\\')
foreach ($item in $WinRELocationItems)
{
if ($item -like "harddisk*")
{
$OSDiskIndex = ExtractNumbers($item)
}
if ($item -like "partition*")
{
$WinREPartitionIndex = ExtractNumbers($item)
}
}
LogMessage("OS Disk: " + $OSDiskIndex)
LogMessage("OS Partition: " + $OSPartition.PartitionNumber)
LogMessage("WinRE Partition: " + $WinREPartitionIndex)
$WinREPartition = Get-Partition -DiskNumber $OSDiskIndex -PartitionNumber $WinREPartitionIndex
$diskInfo = Get-Disk -number $OSDiskIndex
$diskType = $diskInfo.PartitionStyle
LogMessage("Disk PartitionStyle: " + $diskType)
# Display WinRE partition size info
LogMessage("WinRE partition size info")
$WinREPartitionSizeInfo = DisplayPartitionInfo($WinREPartition.AccessPaths)
LogMessage("WinRE Partition Offset: " + $WinREPartition.Offset)
LogMessage("WinRE Partition Type: " + $WinREPartition.Type)
LogMessage("OS partition size: " + $OSPartition.Size)
LogMessage("OS partition Offset: " + $OSPartition.Offset)
$OSPartitionEnds = $OSPartition.Offset + $OSPartition.Size
LogMessage("OS partition ends at: " + $OSPartitionEnds)
LogMessage("WinRE partition starts at: " + $WinREPartition.Offset)
$WinREIsOnSystemPartition = $false
if ($diskType -ieq "MBR")
{
if ($WinREPartition.IsActive)
{
LogMessage("WinRE is on System partition")
$WinREIsOnSystemPartition = $true
}
}
if ($diskType -ieq "GPT")
{
if ($WinREPartition.Type -ieq "System")
{
LogMessage("WinRE is on System partition")
$WinREIsOnSystemPartition = $true
}
}
# Checking the BackupFolder parameter
if ($PSBoundParameters.ContainsKey('BackupFolder'))
{
LogMessage("")
LogMessage("Backup Directory: [" + $BackupFolder + "]")
$Needbackup = $true
if ($WinREIsOnSystemPartition)
{
$Needbackup = $false
LogMessage("WinRE is on System partition which will be preserved. No need to backup content")
}
else
{
if (Test-path $BackupFolder)
{
$items = Get-ChildItem -Path $BackupFolder
if ($items)
{
LogMessage("Error: Existing backup directory is not empty")
exit 1
}
}
else
{
LogMessage("Creating backup directory...")
try
{
$item = New-Item -Path $BackupFolder -ItemType Directory -ErrorAction Stop
if ($item)
{
LogMessage("Backup directory created")
}
else
{
LogMessage("Error: Failed to create backup directory [" + $BackupFolder + "]")
exit 1
}
} catch
{
LogMessage("Error: An error occurred: $_")
exit 1
}
}
}
}
# ------------------------------------
# Verify whether we meet requirements of execution
# - WinRE cannot be on OS partition for the extension
# - WinRE partition must be the next partition after OS partition
# - If WinRE partition already have >=250MB free space, no need to do repartition
# - If there is enough unallocated space to grow the WinRE partition size, skip shrinking OS
#
# However, if the WinRE partition is before the OS partition, there is no chance to extend it
# As a result, it's better to create a new WinRE partition after the OS partition
# ------------------------------------
# Perform a few checks
LogMessage("")
LogMessage("Verifying if the WinRE partition needs to be extended or not...")
if (!(($diskType -ieq "MBR") -Or ($diskType -ieq "GPT")))
{
LogMessage("Error: Got an unexpected disk partition style: " +$diskType)
exit 1
}
# WinRE partition must be after OS partition for the repartition
if ($WinREPartitionIndex -eq $OSPartition.PartitionNumber)
{
LogMessage("WinRE and OS are on the same partition, should not perform extension")
exit 0
}
$supportedSize = Get-PartitionSupportedSize -DriveLetter $OSDrive
# if there is enough free space, skip extension
if ($WinREPartitionSizeInfo[1] -ge 250MB)
{
LogMessage("More than 250 MB of free space was detected in the WinRE partition, there is no need to extend the partition")
exit 0
}
if ($WinREPartition.Offset -lt $OSPartitionEnds)
{
LogMessage("WinRE partition is not after OS partition, cannot perform extension")
LogMessage("Need to create a new WinRE partition after OS partition")
$NeedCreateNew = $true
$NeedShrink = $true
# Calculate the size of repartition
# Will create a new WinRE partition with current WinRE partition size + 250 MB
# The OS partition size will be shrunk by the new WinRE partition size
$targetWinREPartitionSize = $WinREPartitionSizeInfo[0] + 250MB
$shrinkSize = [Math]::Ceiling($targetWinREPartitionSize / 1MB) * 1MB
$targetOSPartitionSize = $OSPartition.Size - $shrinkSize
if ($targetOSPartitionSize -lt $supportedSize.SizeMin)
{
LogMessage("Error: The target OS partition size after shrinking is smaller than the supported minimum size, cannot perform the repartition")
exit 1
}
}
else
{
if ($WinREIsOnSystemPartition)
{
LogMessage("WinRE parititon is after the OS partition and it's also System partition")
LogMessage("Error: Got unexpected disk layout, cannot proceed")
exit 1
}
if (!($WinREPartitionIndex -eq ($OSPartition.PartitionNumber + 1)))
{
LogMessage("Error: WinRE partition is not right after the OS partition, cannot extend WinRE partition")
exit 1
}
# Calculate the size of repartition
# Will shrink OS partitition by 250 MB
$shrinkSize = 250MB
$targetOSPartitionSize = $OSPartition.Size - $shrinkSize
$targetWinREPartitionSize = $WinREPartitionSizeInfo[0] + 250MB
$UnallocatedSpace = $WinREPartition.Offset - $OSPartitionEnds;
# If there is unallocated space, consider using it
if ($UnallocatedSpace -ge 250MB)
{
$UnallocatedSpace = $WinREPartition.Offset - $OSPartitionEnds;
LogMessage("Found unallocated space between OS and WinRE partition: " + $UnallocatedSpace)
LogMessage("There is already enough space to extend WinRE partition without shrinking the OS partition")
$NeedShrink = $false
$targetOSPartitionSize = 0
}
else
{
$shrinkSize = [Math]::Ceiling((250MB - $UnallocatedSpace)/ 1MB) * 1MB
if ($shrinkSize > 250MB)
{
$shrinkSize = 250MB
}
$targetOSPartitionSize = $OSPartition.Size - $shrinkSize
if ($targetOSPartitionSize -lt $supportedSize.SizeMin)
{
LogMessage("Error: The target OS partition size after shrinking is smaller than the supported minimum size, cannot perform the repartition")
exit 1
}
}
}
# ------------------------------------
# Report execution plan and ask for user confirmation to continue
# ------------------------------------
# Report the changes planned to be executed, waiting for user confirmation
LogMessage("")
LogMessage("Summary of proposed changes")
if ($NeedCreateNew)
{
LogMessage("Note: WinRE partition is before OS partition, need to create a new WinRE partition after OS partition")
LogMessage("Will shrink OS partition by " + $shrinkSize)
LogMessage(" Current OS partition size: " + $OSPartition.Size)
LogMessage(" Target OS partition size after shrinking: " + $targetOSPartitionSize)
LogMessage("New WinRE partition will be created with size: ", $targetWinREPartitionSize)
if ($WinREIsOnSystemPartition)
{
LogMessage("Existing WinRE partition is also system partition, it will be preserved")
}
else
{
LogMessage("Existing WinRE partition will be deleted")
LogMessage(" WinRE partition: Disk [" + $OSDiskIndex + "] Partition [" + $WinREPartitionIndex + "]")
LogMessage(" Current WinRE partition size: " + $WinREPartitionSizeInfo[0])
}
}
else
{
if ($NeedShrink)
{
LogMessage("Will shrink OS partition by " + $shrinkSize)
LogMessage(" Current OS partition size: " + $OSPartition.Size)
LogMessage(" Target OS partition size after shrinking: " + $targetOSPartitionSize)
if ($UnallocatedSpace -ge 0)
{
LogMessage("Unallocated space between OS and WinRE partition that will be used towards the new WinRE partition: " + $UnallocatedSpace)
}
}
else
{
LogMessage("Will use 250MB from unallocated space between OS and WinRE partition")
}
LogMessage("Will extend WinRE partition size by 250MB")
LogMessage(" WinRE partition: Disk [" + $OSDiskIndex + "] Partition [" + $WinREPartitionIndex + "]")
LogMessage(" Current WinRE partition size: " + $WinREPartitionSizeInfo[0])
LogMessage(" New WinRE partition size: " + $targetWinREPartitionSize)
LogMessage("WinRE will be temporarily disabled before extending the WinRE partition and enabled automatically in the end")
if ($UnallocatedSpace -ge 100MB)
{
LogMessage("Warning: More than 100MB of unallocated space was detected between the OS and WinRE partitions")
LogMessage("Would you like to proceed by using the unallocated space between the OS and the WinRE partitions?")
}
}
if ($Needbackup)
{
LogMessage("")
LogMessage("The contents of the old WinRE partition will be backed up to [" + $BackupFolder + "]")
}
LogMessage("")
LogMessage("Please reboot the device before running this script to ensure any pending partition actions are finalized")
LogMessage("")
if ($SkipConfirmation)
{
LogMessage("User chose to skip confirmation")
LogMessage("Proceeding with changes...")
}
else
{
$userInput = Read-Host -Prompt "Would you like to proceed? Y for Yes and N for No"
if ($userInput -ieq "Y")
{
LogMessage("Proceeding with changes...")
}
elseif ($userInput -ieq "N")
{
LogMessage("Canceling based on user request, no changes were made to the system")
exit 0
}
else
{
LogMessage("Error: Unexpected user input: [" + $userInput + "]")
exit 0
}
}
LogMessage("")
LogMessage("Note: To prevent unexpected results, please do not interrupt the execution or restart your system")
# ------------------------------------
# Do the actual execution
# The main flow is:
# 1. Check whether ReAgent.xml has stage location and clear it for repartiion
# 2. Disable WinRE as WinRE partition will be deleted
# 3. Perform the repartition to create a larger WinRE partition
# 4. Re-enable WinRE
# ------------------------------------
LogMessage("")
# Load ReAgent.xml to clear Stage location
LogMessage("Loading [" + $ReAgentXmlPath + "] ...")
$xml = [xml](Get-Content -Path $ReAgentXmlPath)
$node = $xml.WindowsRE.ImageLocation
if (($node.path -eq "") -And ($node.guid -eq "{00000000-0000-0000-0000-000000000000}") -And ($node.offset -eq "0") -And ($node.id -eq "0"))
{
LogMessage("Stage location info is empty")
}
else
{
LogMessage("Clearing stage location info...")
$node.path = ""
$node.offset = "0"
$node.guid= "{00000000-0000-0000-0000-000000000000}"
$node.id="0"
# Save the change
LogMessage("Saving changes to [" + $ReAgentXmlPath + "]...")
$xml.Save($ReAgentXmlPath)
}
# Disable WinRE
LogMessage("Disabling WinRE...")
reagentc /disable
if (!($LASTEXITCODE -eq 0))
{
LogMessage("Warning: encountered an error when disabling WinRE: " + $LASTEXITCODE)
exit $LASTEXITCODE
}
# Verify WinRE is under C:\Windows\System32\Recovery\WinRE.wim
$disableWinREPath = Join-Path -Path $system32Path -ChildPath "\Recovery\WinRE.wim"
LogMessage("Verifying that WinRE wim exists in downlevel at default location")
if (!(Test-Path $disableWinREPath))
{
LogMessage("Error: Cannot find " + $disableWinREPath)
# Re-enable WinRE
LogMessage("Re-enabling WinRE on error...")
reagentc /enable
if (!($LASTEXITCODE -eq 0))
{
LogMessage("Warning: encountered an error when enabling WinRE: " + $LASTEXITCODE)
}
exit 1
}
# ------------------------------------
# Perform the repartition
# 1. Resize the OS partition
# 2. Delete the WinRE partition
# 3. Create a new WinRE partition
# ------------------------------------
LogMessage("Performing repartition to extend the WinRE partition ...")
# 1. Resize the OS partition
if ($NeedShrink)
{
LogMessage("Shrinking the OS partition to create a larger WinRE partition")
LogMessage("Resizing the OS partition to: [" + $targetOSPartitionSize + "]...")
Resize-Partition -DriveLetter $OSDrive -Size $targetOSPartitionSize
if ($Error.Count -gt 0) {
LogMessage("Error: Resize-Partition encountered errors: " + $Error[0].Exception.Message)
# Re-enable WinRE
LogMessage("Re-enabling WinRE on error...")
reagentc /enable
if (!($LASTEXITCODE -eq 0))
{
LogMessage("Warning: encountered an error when enabling WinRE: " + $LASTEXITCODE)
}
exit 1
}
$OSPartitionAfterShrink = Get-Partition -DriveLetter $OSDrive
LogMessage("Target partition size: " + $targetOSPartitionSize)
LogMessage("Size of OS partition after shrinking: " + $OSPartitionAfterShrink.Size)
}
# 2. Delete the WinRE partition
LogMessage("")
if ($WinREIsOnSystemPartition)
{
LogMessage("Existing WinRE partition is System partition, skipping deletion")
}
else
{
# If requested by user, backup rest of the content on WinRE partition to backup directory
if ($Needbackup)
{
$sourcePath = $WinREPartition.AccessPaths[0]
LogMessage("Copying content on WinRE partition from [" + $sourcePath + "] to [" + $BackupFolder + "]...")
# Copy-Item may have access issue with certain system folders, enumerate the children items and exlcude them
$items = Get-ChildItem -LiteralPath $sourcePath -Force
foreach ($item in $items)
{
if ($item.Name -ieq "System Volume Information")
{
continue
}
$sourceItemPath = Join-Path -Path $sourcePath -ChildPath $item.Name
$destItemPath = Join-Path -Path $BackupFolder -ChildPath $item.Name
try
{
LogMessage("Copying [" + $sourceItemPath + "] to [" + $destItemPath + "]...")
Copy-Item -LiteralPath $sourceItemPath -Destination $destItemPath -Recurse -Force
} catch
{
LogMessage("Error: An error occurred during copy: $_")
exit 1
}
}
LogMessage("Backup completed")
LogMessage("")
}
LogMessage("Deleting WinRE partition: Disk [" + $OSDiskIndex + "] Partition [" + $WinREPartitionIndex + "]...")
Remove-Partition -DiskNumber $OSDiskIndex -PartitionNumber $WinREPartitionIndex -Confirm:$false
if ($Error.Count -gt 0) {
LogMessage("Error: Remove-Partition encountered errors: " + $Error[0].Exception.Message)
exit 1
}
}
# A short sleep for the partition change
Sleep 5
# 3. Create a new WinRE partition
LogMessage("")
LogMessage("Creating new WinRE partition...")
LogMessage("Target size: " + $targetWinREPartitionSize)
if ($diskType -ieq "GPT")
{
$partition = New-Partition -DiskNumber $OSDiskIndex -Size $targetWinREPartitionSize -GptType "{de94bba4-06d1-4d40-a16a-bfd50179d6ac}"
$newPartitionIndex = $partition.PartitionNumber
# A short sleep to make sure the partition is ready for formatting
Sleep 2
LogMessage("Formating the partition...")
$result = Format-Volume -Partition $partition -FileSystem NTFS -Confirm:$false
if ($Error.Count -gt 0) {
LogMessage("Error: Format-Volume encountered errors: " + $Error[0].Exception.Message)
exit 1
}
}
else
{
#$partition = New-Partition -DiskNumber $OSDiskIndex -Size $targetWinREPartitionSize -MbrType 0x27
$targetWinREPartitionSizeInMb = [int]($targetWinREPartitionSize/1MB)
$diskpartScript =
@"
select disk $OSDiskIndex
create partition primary size=$targetWinREPartitionSizeInMb id=27
format quick fs=ntfs label="Recovery"
set id=27
"@
$TempPath = $env:Temp
$diskpartSciptFile = Join-Path -Path $TempPath -ChildPath "\ExtendWinRE_MBR_PowershellScript.txt"
LogMessage("Creating temporary diskpart script to create Recovery partition on MBR disk...")
LogMessage("Temporary diskpart script file: " + $diskpartSciptFile)
$diskpartScript | Out-File -FilePath $diskpartSciptFile -Encoding ascii
LogMessage("Executing diskpart script...")
try
{
$diskpartOutput = diskpart /s $diskpartSciptFile
if ($diskpartOutput -match "DiskPart successfully")
{
LogMessage("Diskpart script executed successfully")
}
else
{
LogMessage("Error executing diskpart script:" + $diskpartOutput)
exit 1
}
LogMessage("Deleting temporary diskpart script file...")
Remove-Item $diskpartSciptFile
}
catch
{
LogMessage("Error executing diskpart script: $_")
exit 1
}
$vol = Get-Volume -FileSystemLabel "Recovery"
$newPartitionIndex = (Get-Partition | Where-Object { $_.AccessPaths -contains $vol.Path } ).PartitionNumber
}
if ($Error.Count -gt 0)
{
LogMessage("Error: New-Partition encountered errors: " + $Error[0].Exception.Message)
exit 1
}
LogMessage("New Partition index: " + $newPartitionIndex)
# Re-enable WinRE
LogMessage("Re-enabling WinRE...")
reagentc /enable
if (!($LASTEXITCODE -eq 0))
{
LogMessage("Warning: encountered an error when enabling WinRE: " + $LASTEXITCODE)
exit $LASTEXITCODE
}
# In the end, Display WinRE status to verify WinRE is enabled correctly
LogMessage("")
LogMessage("WinRE Information:")
$FinalWinREStatus = DisplayWinREStatus
$WinREStatus = $FinalWinREStatus[0]
$WinRELocation = $FinalWinREStatus[1]
if (!$WinREStatus)
{
LogMessage("Warning: WinRE Disabled")
}
$WinRELocationItems = $WinRELocation.Split('\\')
foreach ($item in $WinRELocationItems)
{
if ($item -like "partition*")
{
$WinREPartitionIndex = ExtractNumbers($item)
}
}
LogMessage("WinRE Partition Index: " + $WinREPartitionIndex)
$WinREPartition = Get-Partition -DiskNumber $OSDiskIndex -PartitionNumber $WinREPartitionIndex
$WinREPartitionSizeInfoAfter = DisplayPartitionInfo($WinREPartition.AccessPaths)
LogMessage("")
LogMessage("OS Information:")
$OSPartition = Get-Partition -DriveLetter $OSDrive
LogMessage("OS partition size: " + $OSPartition.Size)
LogMessage("OS partition Offset: " + $OSPartition.Offset)
if (!($WinREPartitionIndex -eq $newPartitionIndex))
{
LogMessage("Warning: WinRE is installed to partition [" + $WinREPartitionIndex +"], but the newly created Recovery partition is [" + $newPartitionIndex + "]")
}
LogMessage("End time: $([DateTime]::Now)")
if ($NeedBackup)
{
LogMessage("")
LogMessage("The contents of the old WinRE partition has been backed up to [" + $BackupFolder + "]")
}
LogMessage("")
LogMessage("Successfully completed the operation")