Adicionar um pacote de atualização ao Windows RE

Você pode aplicar uma atualização, seja uma LCU ou uma Atualização Dinâmica de Sistema Operacional Segura (DU) a uma imagem do Windows RE. As etapas para atualizar uma imagem do Windows RE são diferentes, dependendo de se você está atualizando uma imagem offline ou uma imagem em um sistema em execução.

  • Ao adicionar uma LCU: tanto antes quanto depois de adicionar uma atualização, verifique o número da versão do WinRE para se certificar de que a atualização foi aplicada corretamente.
  • Ao adicionar um pacote DU: depois de adicionar o pacote, verifique a lista de pacotes na imagem para se certificar de que o pacote foi adicionado à imagem com sucesso.

Atualizar uma imagem offline

As etapas abaixo explicam como adicionar um pacote atualizado a uma imagem offline do Windows RE.

Montar a imagem do Windows

A imagem do Windows RE (winre.wim) está incluída dentro da imagem do Windows (install.wim) e, eventualmente, é copiada para a partição de ferramentas do Windows RE no computador ou dispositivo de destino. Para modificar a imagem do WinRE, primeiro você precisa montar a imagem do Windows e, em seguida, montar a imagem do Windows RE. Após ambas as imagens terem sido montadas, você poderá fazer suas alterações, desmontar a imagem do WinRE e, a seguir, desmontar a imagem do Windows.

  • Crie um diretório de montagem e monte o install.wim:

    md C:\mount\windows
    Dism /Mount-Wim /WimFile:C:\images\install.wim /index:1 /MountDir:C:\mount\windows 
    

Montar a imagem do WinRE

  • Monte o arquivo de Imagem do Windows RE da sua imagem montada.

    Md c:\mount\winre 
    Dism /Mount-Wim /WimFile:C:\mount\windows\Windows\System32\Recovery\winre.wim /index:1 /MountDir:C:\mount\winre 
    

    Dica

    Se não for possível localizar o winre.wim no diretório especificado, use o seguinte comando para definir o arquivo visível:

    attrib -h -a -s C:\mount\windows\Windows\System32\Recovery\winre.wim
    

Adicionar um pacote de Atualização ao WinRE

Com sua imagem de recuperação montada, você pode adicionar a atualização para corrigir o problema.

  1. Baixe o pacote de atualização necessário e o adicione à sua imagem de recuperação.

    Dism /Add-Package /Image:C:\mount\winre /PackagePath:"c:\downloadedupdate\update.msu" 
    

    or

    Dism /Add-Package /Image:C:\mount\ /PackagePath:"c:\downloadedupdate\dynamicupdate.cab" 
    
  2. Se você adicionou um pacote de Atualização Dinâmica, valide se o pacote que você adicionou está na sua imagem:

     Dism /Image:C:\mount\ /Get-Packages
    

    Verifique a lista do pacote de atualização que você acabou de adicionar. O pacote deve incluir o número de KB e mostrar o State como Installed, se tiver sido adicionado com sucesso:

    Package Identity : Package_for_KB5021041~31bf3856ad364e35~amd64~~22621.815.1.0
    State : Installed
    Release Type : Update
    
  3. Limpe sua imagem de recuperação e restaure a base de todos os componentes substituídos:

    dism /image:C:\mount /cleanup-image /StartComponentCleanup /ResetBase 
    

Desmontar imagens

  1. Feche todos os aplicativos que possam estar acessando arquivos da imagem, incluindo o Explorador de Arquivos.

  2. Confirme as alterações e desmonte a imagem do Windows RE:

    Dism /Unmount-Image /MountDir:"C:\mount\winre" /Commit 
    

    Esse processo pode levar alguns minutos.

  3. Confirme as alterações e desmonte a imagem do Windows:

    Dism /Unmount-Image /MountDir:"C:\mount\windows" /Commit 
    

    Em que C é a letra da unidade que contém a imagem. Esse processo pode levar vários minutos.

A imagem do Windows RE agora está atualizada e faz parte da imagem maior do Windows.

Aplicar a atualização a um computador em execução

Você pode aplicar a correção à imagem de Recuperação do Windows em um computador em execução. As etapas a seguir orientam você ao longo da montagem de uma imagem de Recuperação do Windows, aplicando uma atualização e salvando as alterações:

  1. Abra um prompt de comando como administrador.

  2. Crie um diretório no qual você poderá montar a imagem de recuperação para fazer as alterações.

    md c:\mount 
    
  3. Monte sua imagem de recuperação com o REAgentC:

    ReAgentC.exe /mountre /path c:\mount 
    
  4. Com sua imagem de recuperação montada, você pode baixar e adicionar o pacote de atualização à imagem do Windows RE.

    Dism /Add-Package /Image:C:\mount\ /PackagePath:"c:\downloadedupdate\update.msu" 
    

    or

    Dism /Add-Package /Image:C:\mount\ /PackagePath:"c:\downloadedupdate\dynamicupdate.cab" 
    
  5. Se você adicionou um pacote de Atualização Dinâmica, valide se o pacote que você adicionou está na sua imagem:

     Dism /Image:C:\mount\ /Get-Packages
    

    Verifique a lista do pacote de atualização que você acabou de adicionar. O pacote deve incluir o número de KB e mostrar o State como Installed, se tiver sido adicionado com sucesso:

    Package Identity : Package_for_KB5021041~31bf3856ad364e35~amd64~~22621.815.1.0
    State : Installed
    Release Type : Update
    
  6. Limpe sua imagem de recuperação e restaure a base de todos os componentes substituídos:

    dism /image:C:\mount /cleanup-image /StartComponentCleanup /ResetBase 
    
  7. Desmonte a imagem de recuperação do Windows:

    ReAgentC.exe /unmountre /path c:\mount /commit 
    
  8. Se o disco do computador estiver protegido pelo BitLocker ou pela Criptografia de Dispositivo: use ReagentC para desabilitar e habilitar novamente o Windows RE. Isso garante que a imagem atualizada do Windows RE esteja ativada e configurada corretamente para a instalação do Windows:

    reagentc /disable
    reagentc /enable 
    

A imagem do Windows RE no computador em execução agora está atualizada.

Verificar a versão da imagem do WinRE

Você pode verificar o número de versão da imagem do WinRE tanto nas instalações online quanto offline do Windows. Isso pode ser útil para verificar a versão do WinRE antes de adicionar uma atualização e depois de aplicar uma atualização, para verificar se a atualização foi adicionada com sucesso.

Observação

O número de versão do WinRE só será alterado após você adicionar uma LCU. Se você adicionar um pacote DU, use o /get-packages do DISM conforme descrito nas etapas acima para se certificar de que o pacote tenha sido adicionado à imagem.

Validar a versão do Windows RE em um sistema operacional Windows online

  1. Use o ReagentC para encontrar o local da imagem do WinRE instalada executando o seguinte comando:

    reagentc /info
    

    Esse comando retorna o local do Windows RE, que se parece com o seguinte exemplo:

    \\?\GLOBALROOT\device\harddisk0\partition4\Recovery\WindowsRE
    
  2. Use o DISM para obter informações de versão da imagem winre.wim localizada no caminho retornado pelo ReagentC na etapa anterior. Certifique-se de adicionar o nome da imagem do WinRE e o número do índice da imagem ao caminho quando executar o comando:

    Dism /Get-ImageInfo /ImageFile:\\?\GLOBALROOT\device\harddisk0\partition4\Recovery\WindowsRE\winre.wim /index:1
    

    Veja qual é a versão reportada. Por exemplo:

    Version : 10.0.22621
    ServicePack Build : 1
    ServicePack Level : 0
    

    Certifique-se de que o ServicePackBuild seja maior ou igual à UBR da atualização que você adicionou. Por exemplo, para o Windows 11, versão 22H2, a atualização de segurança de novembro mostraria 819 como o SerivcePack Build, já que o número completo da versão dessa atualização é 22621.819.

    • Se a versão reportada for uma versão anterior, isso indica que a imagem do Windows RE não está atualizada.
    • Se a versão reportada for a mesma ou uma versão posterior, nenhuma ação é necessária.

Validar a versão do Windows RE em um sistema operacional Windows offline

  1. Monte a imagem do Windows em uma pasta local, como, por exemplo, C:\mount\windows:

    mkdir C:\mount\windows
    Dism /Mount-Image /ImageFile:C:\mount\install.wim /Index:1 /MountDir:C:\mount\windows
    
  2. Use o DISM para obter informações de versão da imagem winre.wim localizada na pasta Windows\system32\recovery. Certifique-se de especificar o número do índice da imagem quando executar o comando:

    Dism /Get-ImageInfo /ImageFile:c:\mount\windows\windows\system32\recovery\winre.wim /index:1
    

    Veja qual é a versão reportada. Por exemplo:

    Version : 10.0.22621
    ServicePack Build : 1
    ServicePack Level : 0
    

    Certifique-se de que o ServicePackBuild seja maior ou igual à UBR da atualização que você adicionou. Por exemplo, para o Windows 11, versão 22H2, a atualização de segurança de novembro mostraria 819 como o SerivcePack Build, já que o número completo da versão dessa atualização é 22621.819.

    • Se a versão reportada for uma versão anterior, isso indica que a imagem do Windows RE não está atualizada.
    • Se a versão reportada for a mesma ou uma versão posterior, nenhuma ação é necessária.

Ampliar a partição do Windows RE

O script de amostra abaixo pode ser usado para aumentar o tamanho da partição de recuperação para atualizar com sucesso o WinRE (Ambiente de Recuperação do Windows). É recomendável ter 250 MB de espaço livre na partição de recuperação para que as atualizações do WinRE sejam instaladas com sucesso. Em dispositivos que talvez não tenham espaço livre adequado na partição de recuperação, o script de amostra abaixo pode ser usado para ampliar a partição de recuperação em 250 MB.

Reinicialize seu computador antes de executar o script. Isso é fundamental, porque podem existir operações de partição pendentes no seu computador que precisarão ser finalizadas antes que o script possa aumentar o tamanho da partição do WinRE com segurança. Após o computador reinicializar, abra o PowerShell como administrador e execute o caminho mkdir< para o novo diretório de backup> para criar um diretório de backup que o script poderá usar em caso de falha para restaurar a partição original. Anote o local desse diretório de backup, pois o script solicitará o caminho de backup. Se você estiver implantando isso em escala, poderá ignorar o prompt de script usando os parâmetros

" -SkipConfirmation $true -BackupFolder "

Por exemplo,

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")