Aggiungere un pacchetto di aggiornamento a Ambiente ripristino Windows
È possibile applicare un aggiornamento, ovvero un aggiornamento LCU o un aggiornamento dinamico del sistema operativo sicuro (DU) a un'immagine Ambiente ripristino Windows. I passaggi per aggiornare un'immagine Ambiente ripristino Windows sono diversi a seconda che si stia aggiornando un'immagine offline o un'immagine in un sistema in esecuzione.
- Quando si aggiunge un LCU: sia prima di aggiungere un aggiornamento, sia dopo aver aggiunto un aggiornamento, controllare il numero di versione di WinRE per assicurarsi che l'aggiornamento sia stato applicato correttamente.
- Quando si aggiunge un pacchetto DU: dopo aver aggiunto il pacchetto, controllare l'elenco dei pacchetti nell'immagine per assicurarsi che il pacchetto sia stato aggiunto correttamente all'immagine.
Aggiornare un'immagine offline
I passaggi seguenti illustrano come aggiungere un pacchetto aggiornato a un'immagine di Ambiente ripristino Windows offline.
Montare l'immagine di Windows
L'immagine Ambiente ripristino Windows (winre.wim) è inclusa nell'immagine di Windows (install.wim) e viene infine copiata nella partizione degli strumenti di Ambiente ripristino Windows nel PC o nel dispositivo di destinazione. Per modificare l'immagine WinRE, devi prima montare l'immagine di Windows, quindi montare l'immagine Ambiente ripristino Windows. Dopo aver montato entrambe le immagini, è possibile apportare le modifiche, smontare l'immagine WinRE, quindi smontare l'immagine di Windows.
Creare una directory di montaggio e montare install.wim:
md C:\mount\windows Dism /Mount-Wim /WimFile:C:\images\install.wim /index:1 /MountDir:C:\mount\windows
Montare l'immagine WinRE
Montare il file immagine Ambiente ripristino Windows dall'immagine montata.
Md c:\mount\winre Dism /Mount-Wim /WimFile:C:\mount\windows\Windows\System32\Recovery\winre.wim /index:1 /MountDir:C:\mount\winre
Suggerimento
Se winre.wim non può essere visualizzato nella directory specificata, usare il comando seguente per impostare il file visibile:
attrib -h -a -s C:\mount\windows\Windows\System32\Recovery\winre.wim
Aggiungere il pacchetto di aggiornamento a WinRE
Con l'immagine di ripristino montata, è possibile aggiungere l'aggiornamento per risolvere il problema.
Scaricare il pacchetto di aggiornamento necessario e aggiungerlo all'immagine di ripristino.
Dism /Add-Package /Image:C:\mount\winre /PackagePath:"c:\downloadedupdate\update.msu"
or
Dism /Add-Package /Image:C:\mount\ /PackagePath:"c:\downloadedupdate\dynamicupdate.cab"
Se è stato aggiunto un pacchetto di aggiornamento dinamico, verificare che il pacchetto aggiunto sia presente nell'immagine:
Dism /Image:C:\mount\ /Get-Packages
Controllare l'elenco per il pacchetto di aggiornamento appena aggiunto. Il pacchetto deve includere il numero kb e mostrerà
State
comeInstalled
se fosse stato aggiunto correttamente:Package Identity : Package_for_KB5021041~31bf3856ad364e35~amd64~~22621.815.1.0 State : Installed Release Type : Update
Pulire l'immagine di ripristino e reimpostare la base di tutti i componenti sostituiti:
dism /image:C:\mount /cleanup-image /StartComponentCleanup /ResetBase
Smontare le immagini
Chiudere tutte le applicazioni che potrebbero accedere ai file dall'immagine, inclusa Esplora file.
Eseguire il commit delle modifiche e smontare l'immagine Ambiente ripristino Windows:
Dism /Unmount-Image /MountDir:"C:\mount\winre" /Commit
Questo processo può richiedere alcuni minuti.
Eseguire il commit delle modifiche e smontare l'immagine di Windows:
Dism /Unmount-Image /MountDir:"C:\mount\windows" /Commit
Dove C è la lettera di unità dell'unità che contiene l'immagine. Questo processo potrebbe richiedere alcuni minuti.
L'immagine Ambiente ripristino Windows è ora aggiornata e fa parte dell'immagine windows più grande.
Applicare l'aggiornamento a un PC in esecuzione
È possibile applicare la correzione all'immagine di Ripristino di Windows in un PC in esecuzione. I passaggi seguenti illustrano il montaggio di un'immagine di Ripristino di Windows, l'applicazione di un aggiornamento e il salvataggio delle modifiche:
Aprire un prompt dei comandi come amministratore.
Creare una directory in cui è possibile montare l'immagine di ripristino per apportare modifiche.
md c:\mount
Montare l'immagine di ripristino con REAgentC:
ReAgentC.exe /mountre /path c:\mount
Con l'immagine di ripristino montata, è possibile scaricare e aggiungere il pacchetto di aggiornamento all'immagine Ambiente ripristino Windows.
Dism /Add-Package /Image:C:\mount\ /PackagePath:"c:\downloadedupdate\update.msu"
or
Dism /Add-Package /Image:C:\mount\ /PackagePath:"c:\downloadedupdate\dynamicupdate.cab"
Se è stato aggiunto un pacchetto di aggiornamento dinamico, verificare che il pacchetto aggiunto sia presente nell'immagine:
Dism /Image:C:\mount\ /Get-Packages
Controllare l'elenco per il pacchetto di aggiornamento appena aggiunto. Il pacchetto deve includere il numero kb e mostrerà
State
comeInstalled
se fosse stato aggiunto correttamente:Package Identity : Package_for_KB5021041~31bf3856ad364e35~amd64~~22621.815.1.0 State : Installed Release Type : Update
Pulire l'immagine di ripristino e reimpostare la base di tutti i componenti sostituiti:
dism /image:C:\mount /cleanup-image /StartComponentCleanup /ResetBase
Smontare l'immagine di ripristino di Windows:
ReAgentC.exe /unmountre /path c:\mount /commit
Se il disco del PC è protetto da BitLocker o crittografia del dispositivo: usare
ReagentC
per disabilitare e quindi riabilitare Ambiente ripristino Windows. In questo modo si garantisce che l'immagine Ambiente ripristino Windows aggiornata sia attivata e configurata correttamente per l'installazione di Windows:reagentc /disable reagentc /enable
L'immagine Ambiente ripristino Windows sul PC in esecuzione è ora aggiornata.
Controllare la versione dell'immagine WinRE
È possibile controllare il numero di versione dell'immagine WinRE nelle installazioni online e offline di Windows. Questo può essere utile per controllare la versione di WinRE prima di aggiungere un aggiornamento e quindi dopo aver applicato un aggiornamento per verificare che l'aggiornamento sia stato aggiunto correttamente.
Nota
Il numero di versione winRE cambierà solo dopo l'aggiunta di un LCU. Se si aggiunge un pacchetto DU, usare DISM /get-packages come descritto nei passaggi precedenti per assicurarsi che il pacchetto sia stato aggiunto all'immagine.
Convalidare la versione Ambiente ripristino Windows in un sistema operativo Windows online
Usare La ClasseC per trovare il percorso dell'immagine WinRE installata eseguendo il comando seguente:
reagentc /info
Questo comando restituisce il percorso Ambiente ripristino Windows simile all'esempio seguente:
\\?\GLOBALROOT\device\harddisk0\partition4\Recovery\WindowsRE
Usare Gestione e manutenzione immagini distribuzione per ottenere informazioni sulla versione dell'immagine winre.wim che si trova nel percorso restituito da Eseguic nel passaggio precedente. Assicurarsi di aggiungere il nome dell'immagine WinRE e il numero di indice dell'immagine al percorso quando si esegue il comando :
Dism /Get-ImageInfo /ImageFile:\\?\GLOBALROOT\device\harddisk0\partition4\Recovery\WindowsRE\winre.wim /index:1
Si noti la versione segnalata. Ad esempio:
Version : 10.0.22621 ServicePack Build : 1 ServicePack Level : 0
Assicurarsi che sia
ServicePackBuild
maggiore o uguale a UBR per l'aggiornamento aggiunto. Ad esempio, per Windows 11 versione 22H2, l'aggiornamento della sicurezza di novembre viene visualizzato819
come , poiché ilSerivcePack Build
numero di versione completo per tale aggiornamento è 22621.819.- Se la versione segnalata è una versione precedente, indica che l'immagine Ambiente ripristino Windows non è aggiornata.
- Se la versione segnalata è la stessa o una versione successiva, non è necessaria alcuna azione.
Convalidare la versione Ambiente ripristino Windows in un sistema operativo Windows offline
Montare l'immagine di Windows in una cartella locale, ad esempio C:\mount\windows:
mkdir C:\mount\windows Dism /Mount-Image /ImageFile:C:\mount\install.wim /Index:1 /MountDir:C:\mount\windows
Usare Gestione e manutenzione immagini distribuzione per ottenere informazioni sulla versione dell'immagine winre.wim che si trova nella
Windows\system32\recovery
cartella . Assicurarsi di specificare il numero di indice dell'immagine quando si esegue il comando :Dism /Get-ImageInfo /ImageFile:c:\mount\windows\windows\system32\recovery\winre.wim /index:1
Si noti la versione segnalata. Ad esempio:
Version : 10.0.22621 ServicePack Build : 1 ServicePack Level : 0
Assicurarsi che sia
ServicePackBuild
maggiore o uguale a UBR per l'aggiornamento aggiunto. Ad esempio, per Windows 11 versione 22H2, l'aggiornamento della sicurezza di novembre viene visualizzato819
come , poiché ilSerivcePack Build
numero di versione completo per tale aggiornamento è 22621.819.- Se la versione segnalata è una versione precedente, indica che l'immagine Ambiente ripristino Windows non è aggiornata.
- Se la versione segnalata è la stessa o una versione successiva, non è necessaria alcuna azione.
Estendere la partizione Ambiente ripristino Windows
Lo script di esempio seguente può essere usato per aumentare le dimensioni della partizione di ripristino per aggiornare correttamente Windows Recovery Environment (WinRE). È consigliabile disporre di 250 MB di spazio disponibile nella partizione di ripristino per l'installazione corretta degli aggiornamenti di WinRE. Nei dispositivi che potrebbero non avere spazio disponibile sufficiente nella partizione di ripristino, lo script di esempio seguente può essere usato per estendere la partizione di ripristino di 250 MB.
Riavviare il computer prima di eseguire lo script. Questa operazione è fondamentale perché potrebbero essere presenti operazioni di partizione in sospeso sul computer che dovranno essere finalizzate prima che lo script possa aumentare in modo sicuro le dimensioni della partizione WinRE. Dopo il riavvio del computer, aprire PowerShell come amministratore ed eseguire il percorso mkdir <alla nuova directory di backup per creare una directory> di backup che lo script può usare in caso di errore per ripristinare la partizione originale. Prendere nota del percorso di questa directory di backup perché lo script richiederà il percorso di backup. Se si esegue la distribuzione su larga scala, è possibile ignorare la richiesta di script usando i parametri
"<file> script -SkipConfirmation $true cartella -BackupFolder <per il backup>"
ad esempio:
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")