将更新包添加到 Windows RE

可以应用更新(LCU 或安全 OS 动态更新 (DU))到 Windows RE 映像。 更新 Windows RE 映像的步骤有所不同,具体取决于是更新脱机映像还是正在运行的系统上的映像。

  • 添加 LCU 时:在添加更新之前以及添加更新后,请检查 WinRE 版本号以确保更新已正确应用。
  • 添加 DU 包时:添加包后,请检查映像中的包列表,以确保包已成功添加到映像中。

更新脱机映像

以下步骤介绍如何将更新的包添加到脱机 Windows RE 映像。

装载 Windows 映像

Windows RE 映像 (winre.wim) 包含在 Windows 映像 (install.wim) 中,最终将复制到目标电脑或设备上的 Windows RE 工具分区。 若要修改 WinRE 映像,必须先装载 Windows 映像,然后装载 Windows RE 映像。 装载这两个映像后,可以进行更改,卸载 WinRE 映像,然后卸载 Windows 映像。

  • 创建装载目录并装载 install.wim:

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

装载 WinRE 映像

  • 从已装载的映像装载 Windows RE 映像文件。

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

    提示

    如果在指定目录下看不到 winre.wim,请使用以下命令将该文件设置为可见:

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

将更新包添加到 WinRE

装载了恢复映像后,可以添加更新来解决此问题。

  1. 下载所需的更新包并将其添加到恢复映像。

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

    Dism /Add-Package /Image:C:\mount\ /PackagePath:"c:\downloadedupdate\dynamicupdate.cab" 
    
  2. 如果添加了动态更新包,请验证添加的包是否位于映像中:

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

    检查刚添加的更新包的列表。 如果包已成功添加,它应包含 KB 编号,并显示 StateInstalled

    Package Identity : Package_for_KB5021041~31bf3856ad364e35~amd64~~22621.815.1.0
    State : Installed
    Release Type : Update
    
  3. 清理恢复映像并重置任何被取代的组件的基:

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

卸载映像

  1. 关闭所有可能正在访问映像中文件的应用程序,包括文件资源管理器。

  2. 提交更改并卸载 Windows RE 映像:

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

    此流程可能需要几分钟的时间。

  3. 提交更改并卸载 Windows 映像:

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

    其中 C 是包含该映像的驱动器的驱动器号。 此过程可能需要数分钟。

Windows RE 映像现已更新,并且是较大的 Windows 映像的一部分。

将更新应用到正在运行的电脑

可以将修补程序应用于正在运行的电脑上的 Windows 恢复映像。 以下步骤将引导你装载 Windows 恢复映像、向其应用更新,然后保存更改:

  1. 以管理员身份打开命令提示符。

  2. 创建一个目录,你可在其中装载恢复映像以对其进行更改。

    md c:\mount 
    
  3. 使用 REAgentC装载恢复映像:

    ReAgentC.exe /mountre /path c:\mount 
    
  4. 装载了恢复映像后,可以下载更新包并将其添加到 Windows RE 映像。

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

    Dism /Add-Package /Image:C:\mount\ /PackagePath:"c:\downloadedupdate\dynamicupdate.cab" 
    
  5. 如果添加了动态更新包,请验证添加的包是否位于映像中:

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

    检查刚添加的更新包的列表。 如果包已成功添加,它应包含 KB 编号,并显示 StateInstalled

    Package Identity : Package_for_KB5021041~31bf3856ad364e35~amd64~~22621.815.1.0
    State : Installed
    Release Type : Update
    
  6. 清理恢复映像并重置任何被取代的组件的基:

    dism /image:C:\mount /cleanup-image /StartComponentCleanup /ResetBase 
    
  7. 卸载 Windows 恢复映像:

    ReAgentC.exe /unmountre /path c:\mount /commit 
    
  8. 如果电脑的磁盘受 BitLocker 或设备加密保护:使用 ReagentC 禁用,然后重新启用 Windows RE。 这可确保为 Windows 安装启用并正确配置更新的 Windows RE 映像:

    reagentc /disable
    reagentc /enable 
    

正在运行的电脑上的 Windows RE 映像现已更新。

检查 WinRE 映像版本

可以在联机和脱机 Windows 安装上检查 WinRE 映像的版本号。 这有助于在添加更新之前检查 WinRE 版本,然后在应用更新后验证是否已成功添加更新。

注意

只有在添加 LCU 后,WinRE 版本号才会更改。 如果添加 DU 包,请使用 DISM /get-packages,如上述步骤中所述,以确保包已添加到映像中。

在联机 Windows OS 中验证 Windows RE 版本

  1. 通过运行以下命令,使用 ModageC 查找已安装的 WinRE 映像的位置:

    reagentc /info
    

    此命令返回类似于以下示例的 Windows RE 位置:

    \\?\GLOBALROOT\device\harddisk0\partition4\Recovery\WindowsRE
    
  2. 使用 DISM 获取有关 winre.wim 映像的版本信息,该映像位于上一步骤中由 ReagentC 返回的路径中。 运行命令时,请确保将 WinRE 映像名称和映像索引号添加到路径:

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

    请注意报告的版本。 例如:

    Version : 10.0.22621
    ServicePack Build : 1
    ServicePack Level : 0
    

    请确保你添加的更新的 ServicePackBuild 大于或等于 UBR。 例如,对于 Windows 11 版本 22H2,11 月安全更新将显示 819SerivcePack Build,因为该更新的完整版本号为 22621.819。

    • 如果报告的版本是早期版本,则表示 Windows RE 映像不是最新的。
    • 如果报告的版本相同或是更高版本,则无需执行任何操作。

验证脱机 Windows OS 中的 Windows RE 版本

  1. 装载 Windows 映像到本地文件夹,例如 C:\mount\windows:

    mkdir C:\mount\windows
    Dism /Mount-Image /ImageFile:C:\mount\install.wim /Index:1 /MountDir:C:\mount\windows
    
  2. 使用 DISM 获取有关 Windows\system32\recovery 文件夹中的 winre.wim 映像的版本信息。 运行命令时,请务必指定映像的索引号:

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

    请注意报告的版本。 例如:

    Version : 10.0.22621
    ServicePack Build : 1
    ServicePack Level : 0
    

    请确保你添加的更新的 ServicePackBuild 大于或等于 UBR。 例如,对于 Windows 11 版本 22H2,11 月安全更新将显示 819SerivcePack Build,因为该更新的完整版本号为 22621.819。

    • 如果报告的版本是早期版本,则表示 Windows RE 映像不是最新的。
    • 如果报告的版本相同或是更高版本,则无需执行任何操作。

扩展 Windows RE 分区

下面的示例脚本可用于增加恢复分区的大小,以成功更新 Windows 恢复环境 (WinRE)。 建议在恢复分区中留有 250MB 的可用空间,以便 WinRE 更新能够成功安装。 在恢复分区可能没有足够可用空间的设备上,以下示例脚本可用于将恢复分区扩展 250 MB。

在运行脚本之前重启计算机。 这一点至关重要,因为计算机上可能有暂存挂起的分区操作需要先完成,然后脚本才能安全地增加 WinRE 分区大小。 计算机重新启动后,以管理员身份打开 Powershell,运行 mkdir <路径到新的备份目录>,以创建在还原原始分区失败时脚本可使用的备份目录。 请注意此备份目录的位置,因为脚本会要求提供备份路径。如果要大规模部署此脚本,则可使用参数来绕过脚本提示

" -SkipConfirmation $true -BackupFolder "

例如,

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