Public/Functions/WinRE.ps1
|
function Copy-WinREWIM { <# .SYNOPSIS Copies the Windows Recovery Environment WIM to the specified DestinationDirectory .DESCRIPTION Copies the Windows Recovery Environment WIM to the specified DestinationDirectory This function must be run in Windows .LINK https://github.com/OSDeploy/OSD/tree/master/docs #> [CmdletBinding()] [OutputType([System.IO.FileInfo])] param ( [System.String] #Directory to save the Windows Recovery Environment WIM #Default: $env:Temp\sources $DestinationDirectory = "$env:Temp\sources", [System.String] #File Name of the Windows Recovery WIM #Default: winre.wim $DestinationFileName = 'winre.wim' ) #================================================= # Block #================================================= Block-WinPE $CurrentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent() $CurrentPrincipal = [Security.Principal.WindowsPrincipal]::new($CurrentIdentity) if (-not $CurrentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { Write-Warning "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Administrative rights are required" return } Block-WindowsVersionNe10 Block-PowerShellVersionLt5 #================================================= # GetPartitionWinRE #================================================= $GetPartitionWinRE = Get-WinREPartition -ErrorAction Stop #$GetPartitionWinRE | Select-Object -Property * | Format-List if ($GetPartitionWinRE) { #================================================= # Get WinrePartitionDriveLetter #================================================= if ($GetPartitionWinRE.DriveLetter) { $CreateNewDriveLetter = $false $WinrePartitionDriveLetter = $GetPartitionWinRE.DriveLetter } else { $CreateNewDriveLetter = $true $WinrePartitionDriveLetter = (68..90 | ForEach-Object {$L=[char]$_; if ((Get-PSDrive).Name -notContains $L) {$L}})[0] Get-WinREPartition | Set-Partition -NewDriveLetter $WinrePartitionDriveLetter -Verbose } Write-Verbose "WinrePartitionDriveLetter: $WinrePartitionDriveLetter" #================================================= # Get WinreLocationPath #================================================= $WinreLocationPath = (Get-ReAgentXml).WinreLocationPath Write-Verbose "WinreLocationPath: $WinreLocationPath" #================================================= # Get WinreDirectory #================================================= $WinreDirectory = Join-Path "$($WinrePartitionDriveLetter):" -ChildPath $WinreLocationPath Write-Verbose "WinreDirectory: $WinreDirectory" if (!(Test-Path $DestinationDirectory)) { $null = New-Item -Path $DestinationDirectory -ItemType Directory -Force -ErrorAction SilentlyContinue } if (Test-Path "$WinreDirectory" -PathType Container -ErrorAction Ignore) { $WinreSource = Join-Path $WinreDirectory -ChildPath 'winre.wim' Write-Verbose "WinreSource: $WinreSource" robocopy "$WinreDirectory" "$DestinationDirectory" winre.wim /np /ndl /nfl /njh /njs } $WinreDestination = Join-Path $DestinationDirectory -ChildPath $DestinationFileName if ($DestinationFileName -ne 'winre.wim') { if (Test-Path $WinreDestination) { Remove-Item -Path $WinreDestination -Force -Verbose } Rename-Item -Path (Join-Path $DestinationDirectory -ChildPath 'winre.wim') -NewName $DestinationFileName -Verbose } #================================================= # Remove Drive Letter #================================================= if ($CreateNewDriveLetter) { Remove-PartitionAccessPath -DiskNumber $GetPartitionWinRE.DiskNumber -PartitionNumber $GetPartitionWinRE.PartitionNumber -AccessPath "$($WinrePartitionDriveLetter):" } #================================================= # Return WinreDestination Get-Item #================================================= if (Test-Path $WinreDestination -ErrorAction Ignore) { (Get-Item -Path $WinreDestination -Force).Attributes = 'Archive' Get-Item -Path $WinreDestination } } } function Get-ReAgentXml { <# .SYNOPSIS Returns information from the Windows Recovery Agent XML file .DESCRIPTION Reads and parses the Reagent.xml file to extract Windows Recovery Environment configuration and status information. This function must be run in Windows. .EXAMPLE Get-ReAgentXml Returns ReAgent.xml configuration details .NOTES Author: David Segura - Recast Software 2026-07-10 - Updated help to follow OSD standard .LINK https://github.com/OSDeploy/OSD/tree/master/docs #> [CmdletBinding()] param () #================================================= # Block #================================================= Block-WinPE $CurrentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent() $CurrentPrincipal = [Security.Principal.WindowsPrincipal]::new($CurrentIdentity) if (-not $CurrentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { Write-Warning "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Administrative rights are required" return } Block-WindowsVersionNe10 Block-PowerShellVersionLt5 #================================================= # ReAgent.xml #================================================= if (-NOT (Test-Path "$env:SystemRoot\System32\Recovery\ReAgent.xml")) { Write-Warning "Unable to find $env:SystemRoot\System32\Recovery\ReAgent.xml" } else { [xml]$XmlDocument = Get-content -Path "$env:SystemRoot\System32\Recovery\ReAgent.xml" -Raw $XmlDocument.SelectNodes('WindowsRE') | ForEach-Object { $WinreLocationGuid = $_.WinreLocation.guid $WinreLocationId = $_.WinreLocation.id $WinreLocationOffset = $_.WinreLocation.offset $WinreLocationPath = $_.WinreLocation.path if ($WinreLocationId -gt 1000) { $WinreLocationPartition = (Get-Disk | Where-Object {$_.Signature -eq $WinreLocationId} | Get-Partition | Where-Object {$_.Offset -eq $WinreLocationOffset}).PartitionNumber } else { $WinreLocationPartition = (Get-Disk -Number $WinreLocationId | Get-Partition | Where-Object {$_.Offset -eq $WinreLocationOffset}).PartitionNumber } $WinreBCD = $_.WinreBCD.id -replace ('{','') -replace ('}','') $ReAgentInfo = [PSCustomObject]@{ CustomImageAvailable = $_.CustomImageAvailable.state DownlevelWinreLocationGuid = $_.DownlevelWinreLocation.guid DownlevelWinreLocationId = $_.DownlevelWinreLocation.id DownlevelWinreLocationOffset = $_.DownlevelWinreLocation.offset DownlevelWinreLocationPath = $_.DownlevelWinreLocation.path ImageLocationGuid = $_.ImageLocation.guid ImageLocationId = $_.ImageLocation.id ImageLocationOffset = $_.ImageLocation.offset ImageLocationPath = $_.ImageLocation.path InstallState = $_.InstallState.state IsAutoRepairOn = $_.IsAutoRepairOn.state IsServer = $_.IsServer.state IsWimBoot = $_.IsWimBoot.state NarratorScheduled = $_.NarratorScheduled.state OemTool = $_.OemTool.state OperationParam = $_.OperationParam.path OperationPermanent = $_.OperationPermanent.state OsBuildVersion = $_.OsBuildVersion.path OsInstallAvailable = $_.OsInstallAvailable.state PBRCustomImageLocationGuid = $_.PBRCustomImageLocation.guid PBRCustomImageLocationId = $_.PBRCustomImageLocation.id PBRCustomImageLocationOffset = $_.PBRCustomImageLocation.offset PBRCustomImageLocationPath = $_.PBRCustomImageLocation.path PBRImageLocationGuid = $_.PBRImageLocation.guid PBRImageLocationId = $_.PBRImageLocation.id PBRImageLocationOffset = $_.PBRImageLocation.offset PBRImageLocationPath = $_.PBRImageLocation.path ScheduledOperation = $_.ScheduledOperation.state WinREStaged = $_.WinREStaged.state WinreBCD = $_.WinreBCD.id WinreLocationGuid = $WinreLocationGuid WinreLocationId = $WinreLocationId WinreLocationOffset = $WinreLocationOffset WinreLocationPath = $WinreLocationPath WindowsRElocation = '\\?\GLOBALROOT\device\harddisk' + $WinreLocationId + '\partition' + $WinreLocationPartition + $WinreLocationPath BootConfigurationDataBCD = $WinreBCD } } $ReAgentInfo } } function Get-WinREPartition { <# .SYNOPSIS Retrieves the Windows Recovery Environment partition information .DESCRIPTION Returns the partition information for the Windows Recovery Environment (WinRE) WIM file. This function must be run in Windows. .EXAMPLE Get-WinREPartition Returns the WinRE partition information .NOTES Author: David Segura - Recast Software 2026-07-10 - Updated help to follow OSD standard .LINK https://github.com/OSDeploy/OSD/tree/master/docs #> [CmdletBinding()] [OutputType([Microsoft.Management.Infrastructure.CimInstance])] [OutputType('Microsoft.Management.Infrastructure.CimInstance#ROOT/Microsoft/Windows/Storage/MSFT_Partition')] param () $WinrePartitionOffset = (Get-ReAgentXml).WinreLocationOffset $Results = Get-Partition | Where-Object {$_.Offset -match $WinrePartitionOffset} $Results[0] } |