Windows RE に更新プログラム パッケージを追加する
Windows RE イメージに更新プログラム (LCU または安全な OS 動的更新プログラム (DU)) を適用できます。 Windows RE イメージを更新する手順は、オフライン イメージを更新するか、実行中のシステムのイメージを更新するかによって異なります。
- LCU を追加する場合: 更新プログラムを追加する前だけでなく、更新プログラムを追加した後も、WinRE のバージョン番号を調べて、更新プログラムが正しく適用されたことを確認します。
- DU パッケージを追加する場合: パッケージを追加した後、イメージ内のパッケージの一覧を調べて、パッケージがイメージに正常に追加されたことを確認します。
オフライン イメージを更新する
次の手順では、更新されたパッケージをオフラインの Windows RE イメージに追加する方法について説明します。
Windows イメージをマウントする
Windows RE イメージ (winre.wim) は Windows イメージ (install.wim) に含まれており、最終的には対象の PC またはデバイスの 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 に追加する
回復イメージをマウントしたら、更新プログラムを追加して問題を解決できます。
必要な更新プログラム パッケージをダウンロードして、それを回復イメージに追加します。
Dism /Add-Package /Image:C:\mount\winre /PackagePath:"c:\downloadedupdate\update.msu"
または
Dism /Add-Package /Image:C:\mount\ /PackagePath:"c:\downloadedupdate\dynamicupdate.cab"
動的更新プログラム パッケージを追加した場合は、追加したパッケージがイメージ内にあることを確認します。
Dism /Image:C:\mount\ /Get-Packages
追加した更新プログラム パッケージの一覧を調べます。 パッケージには KB 番号が含まれている必要があり、正常に追加された場合は
State
がInstalled
と示されます。Package Identity : Package_for_KB5021041~31bf3856ad364e35~amd64~~22621.815.1.0 State : Installed Release Type : Update
回復イメージをクリーンアップし、置き換えられたコンポーネントのベースをリセットします。
dism /image:C:\mount /cleanup-image /StartComponentCleanup /ResetBase
イメージのマウントを解除する
ファイルエクスプローラーなど、イメージからファイルにアクセスしている可能性のあるすべてのアプリケーションを閉じます。
変更をコミットして Windows RE イメージのマウントを解除します。
Dism /Unmount-Image /MountDir:"C:\mount\winre" /Commit
このプロセスには数分かかることがあります。
変更をコミットして Windows イメージのマウントを解除します。
Dism /Unmount-Image /MountDir:"C:\mount\windows" /Commit
ここで、C は、イメージを含むドライブのドライブ文字です。 このプロセスには数分かかることがあります。
これにより Windows RE イメージが更新され、より大きな Windows イメージの一部になります。
実行中の PC に更新プログラムを適用する
実行中の PC 上の Windows 回復イメージに修正プログラムを適用できます。 次の手順では、Windows 回復イメージのマウント、更新プログラムの適用、変更の保存について説明します。
管理者としてコマンド プロンプトを開きます。
変更するために回復イメージをマウントできるディレクトリを作成します。
md c:\mount
REAgentC を使って回復イメージをマウントします。
ReAgentC.exe /mountre /path c:\mount
回復イメージをマウントしたら、更新プログラム パッケージをダウンロードして Windows RE イメージに追加できます。
Dism /Add-Package /Image:C:\mount\ /PackagePath:"c:\downloadedupdate\update.msu"
または
Dism /Add-Package /Image:C:\mount\ /PackagePath:"c:\downloadedupdate\dynamicupdate.cab"
動的更新プログラム パッケージを追加した場合は、追加したパッケージがイメージ内にあることを確認します。
Dism /Image:C:\mount\ /Get-Packages
追加した更新プログラム パッケージの一覧を調べます。 パッケージには KB 番号が含まれている必要があり、正常に追加された場合は
State
がInstalled
と示されます。Package Identity : Package_for_KB5021041~31bf3856ad364e35~amd64~~22621.815.1.0 State : Installed Release Type : Update
回復イメージをクリーンアップし、置き換えられたコンポーネントのベースをリセットします。
dism /image:C:\mount /cleanup-image /StartComponentCleanup /ResetBase
Windows 回復イメージのマウントを解除します。
ReAgentC.exe /unmountre /path c:\mount /commit
PC のディスクが BitLocker またはデバイスの暗号化によって保護されている場合:
ReagentC
を使って Windows RE を無効にしてから、再度有効にします。 これにより、更新された Windows RE イメージが有効になり、Windows インストール用に正しく構成されます。reagentc /disable reagentc /enable
これで、実行中の PC 上の Windows RE イメージが更新されました。
WinRE イメージのバージョンを確認する
WinRE イメージのバージョン番号は、オンラインとオフラインの両方の Windows インストールで確認できます。 これは、更新プログラムを追加する前に WinRE のバージョンを確認し、更新プログラムを適用した後で更新プログラムが正常に追加されたことを確認する場合に役立ちます。
Note
WinRE のバージョン番号は、LCU を追加した後でのみ変更されます。 DU パッケージを追加する場合は、上記の手順で説明したように DISM の /get-packages を使って、パッケージがイメージに追加されていることを確認します。
オンラインの Windows OS で Windows RE のバージョンを検証する
ReagentC で次のコマンドを実行して、インストールされている WinRE イメージの場所を見つけます。
reagentc /info
このコマンドからは、次の例のような Windows RE の場所が返されます。
\\?\GLOBALROOT\device\harddisk0\partition4\Recovery\WindowsRE
DISM を使って、前のステップで ReagentC によって返されたパスにある winre.wim イメージに関するバージョン情報を取得します。 コマンドを実行するときは、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 月のセキュリティ更新プログラムは、その更新プログラムの完全なバージョン番号が 22621.819 であるため、SerivcePack Build
として819
と表示されます。- 報告されたバージョンが以前のバージョンの場合は、Windows RE イメージが最新ではないことを示します。
- 報告されたバージョンが同じか、それより後のバージョンの場合、アクションは必要ありません。
オフラインの Windows OS で Windows RE のバージョンを検証する
ローカル フォルダー (C:\mount\windows など) に Windows イメージをマウントします。
mkdir C:\mount\windows Dism /Mount-Image /ImageFile:C:\mount\install.wim /Index:1 /MountDir:C:\mount\windows
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 月のセキュリティ更新プログラムは、その更新プログラムの完全なバージョン番号が 22621.819 であるため、SerivcePack Build
として819
と表示されます。- 報告されたバージョンが以前のバージョンの場合は、Windows RE イメージが最新ではないことを示します。
- 報告されたバージョンが同じか、それより後のバージョンの場合、アクションは必要ありません。
Windows RE のパーティションを拡張する
以下のサンプル スクリプトを使用して、回復パーティションのサイズを増やし、Windows 回復環境 (WinRE) を正常に更新できます。 WinRE 更新プログラムを正常にインストールするには、回復パーティションに 250MB の空き領域を確保することをお勧めします。 回復パーティションに十分な空き領域がない可能性があるデバイスでは、以下のサンプル スクリプトを使用して回復パーティションを 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")