My Search and Apply .WIM Image files script with recovery partition creation.

By | September 25, 2013
Share

Once powershell was supported in WinPE, I converted my .VBS search and apply script over.  I add this script into my startnet.cmd, so it is started after initializing WinPE.

Here are the steps of the script:

  1. Prompts the user asking them to verify that they want to run recovery.
  2. Prompts for recovery password if “$sRecoveryPassword” variable is set.
  3. Verifies that it sees a local disk (>100gb).
  4. Searches through each disk and pulls the latest .WIM file that is over 1gb.
  5. Creates a recovery partition and stages the .WIM along with WinPE in recovery partition.
  6. Applies .WIM file from Recovery Partition to System Drive.
    Preps the MBR and BCD file.
  7. Shuts down the system.

Script Source:

https://github.com/brianfgonzalez/Scripts/blob/master/SearchAndApplyWRecovery.ps1

$sRecoveryPassword = $null

Function fMain {
trap {"Error found: $_" | Out-File "x:\SearchAndApply.log"}

#Clear content in command window
Clear-Host

#Maximize Command Window
<# #Doesn't Work........... $sig = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);' Add-Type -MemberDefinition $sig -name NativeMethods -namespace Win32 $hwnd = @(Get-Process "*Windows Powershell*")[0].MainWindowHandle [Win32.NativeMethods]::ShowWindowAsync($hwnd, 3) #>

Write-Output "Beginning to search for .WIM file..."
#Finds the LATEST >1G .WIM File in the root of Logical Disks
$oWimFiles = Get-WmiObject -Query "SELECT * From Win32_LogicalDisk WHERE NOT DeviceID LIKE 'A' AND Size > 0 AND NOT DriveType LIKE '4'" | `
#Commented out on 9/6/2013 DriveType 5 is for CDr/DVDr Types.
#Where-Object { $_.DriveType -ne "5" } | `
foreach { Get-ChildItem -Force -Path @($_.DeviceID + "\") } | `
Where-Object { ($_.FullName -Like "*.wim") -and ($_.Length -ge 1000000000) } | `
Sort-Object -Descending CreationTime
If ($oWimFiles -eq $null) {Write-Output "No .WIM files found..."; Exit}

#Grab Drive Object of where .WIM was located.
$oWimDrive = Get-WmiObject -Query ("SELECT * From Win32_LogicalDisk WHERE DeviceID LIKE '%" + $oWimFiles[0].PSDrive + "%'")

#If .WIM is in RECOVERY partition, then only a format on the OSDISK partition is required.
If ($oWimDrive.VolumeName -eq "RECOVERY") {

$sRecDrive = $oWimDrive.DeviceID
Write-Output "Latest WIM was found IN Recovery Partition($sRecDrive)..."
Write-Output @("Found the following image: " + $oWimFiles[0].FullName)

$oDrives = Get-WmiObject -Query "SELECT * FROM Win32_LogicalDisk WHERE DriveType LIKE 3" | `
Sort-Object -Descending Size

fCreateAnswerFiles
If (!(Test-Path("$env:temp\configHD2.txt"))) {
Write-Output "Could not access Temp Drive..."; Exit}
Write-Output "Formating OSDIsk Partition..."
Start-Process "x:\windows\system32\cmd.exe" @('/C diskpart.exe /s configHD2.txt"') -Wait -WorkingDirectory $env:temp -WindowStyle Minimized | Out-Null

}else{

#.WIM was NOT located in RECOVERY, so re-building all partitions.
$sRecDrive = "R:"
Write-Output "Latest WIM was found OUT of Recovery Partion."
Write-Output @("Found the following image: " + $oWimFiles[0].FullName)

#Checks if "Local Disk" found is over 100GB.
$Disk = Get-Disk -Number 0 | Where-Object { $_.Size -gt 100000000000 }
If ($Disk -eq $null) {Write-Output "100GB Local Disk is not found, exiting script..."; Exit}

#Call Function to create Diskpart answer files.
fCreateAnswerFiles
If ((!(Test-Path("$env:temp\configHD.txt"))) -and (!(Test-Path("$env:temp\configHD2.txt")))) {
Write-Output "Could not access Temp Drive..."; Exit}
Write-Output "Re-Partitioning Disk..."

#Re-partition the disk
Start-Process "x:\windows\system32\cmd.exe" @('/C diskpart.exe /s configHD.txt"') -Wait -WorkingDirectory $env:temp -WindowStyle Minimized | Out-Null

Write-Output "Prep Recovery Partition before applying WIM to OSDISK..."
#Copy-Item -Path ($oWimFiles[0].DirectoryName + "*") -Destination $sRecDrive -Recurse -Confirm:$false -Force
Start-Process "x:\windows\system32\cmd.exe" @('/C robocopy.exe "' + $oWimFiles[0].DirectoryName.SubString(0,2) + `
'" "' + $sRecDrive + '" /MIR /NJS /NJH /NP') -Wait -NoNewWindow | Out-Null
}
#Provide Status on what .WIM file will be applied.
Write-Output @('Begin applying image to OS partition...')
Start-Process "x:\windows\system32\cmd.exe" @('/C "imagex /apply "' + `
$sRecDrive + '\' + $oWimFiles[0].Name + '" 1 C:"') -Wait -NoNewWindow | Out-Null
Write-Output "Completed with applying image."

#Delete old BCD file
attrib C:\Boot\BcD -H -S
Remove-Item C:\Boot\BcD -Force

#Build a new one using bcd boot
Start-Process "x:\windows\system32\cmd.exe" @('/C bcdboot c:\windows /s c:') -Wait -WindowStyle Minimized | Out-Null

#Add Recovery WinPE boot option to BCD using BCDEdit script
fCreateBuildBCDFile
If (!(Test-Path("$env:temp\configBCD.bat"))) {
Write-Output "Could not access Temp Drive..."; Exit}
Start-Process "x:\windows\system32\cmd.exe" @('/C call configBCD.bat ' + $sRecDrive) -Wait -WorkingDirectory $env:temp -WindowStyle Minimized | Out-Null

Write-Output @("Boot sector and BCD is prepped.")
Sleep -Seconds 5
If (Test-Path("C:\Windows")) {
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.VisualBasic") | Out-Null
[Microsoft.VisualBasic.Interaction]::MsgBox("Image was recovered. Click OK to Shut Down the System.",'OKOnly,Information', "Process Complete") | Out-Null
Start-Process "x:\windows\system32\wpeutil.exe" @('"shutdown"')
} else {
Write-Output @("ImageX did not apply image successfully.... Shutting down in 5 seconds...")
"ImageX did not apply image successfully." | Out-File "x:\SearchAndApplyError.log"
Exit
}
}

Function fCreateAnswerFiles {
'select disk 0
clean
create partition primary size=25000
select partition 1
format fs=ntfs label="RECOVERY" quick
assign letter = R
create partition primary
select partition 2
format fs=ntfs label="OSDISK" quick
assign letter = C
active
exit' | Out-File "$env:temp\configHD.txt" -Encoding ascii

'select disk 0
select partition 2
format fs=ntfs label="OSDISK" quick
assign letter = C
exit' | Out-File "$env:temp\configHD2.txt" -Encoding ascii
}

Function fCreateBuildBCDFile {
'@echo off
setlocal

SET BCDEDIT=bcdedit.exe
SET BCDSTORE=C:\Boot\BCD
SET SDI_FILE=boot.sdi
SET WIM_File=boot.wim
SET RECDRV=%1

REM Replace 7 Bootmgr with 8 Bootmgr
attrib c:\bootmgr -H -S
del c:\bootmgr /F
copy %RECDRV%\bootmgr c:\bootmgr

REM Set Timeout value to 5
%BCDEDIT% /store %BCDSTORE% /timeout 5

echo.
echo Adding Ram Disk Options
echo ===========

for /f "Tokens=3" %%A in (''%BCDEDIT% /store %BCDSTORE% /create /device'') do set ramdisk=%%A

%BCDEDIT% /store %BCDSTORE% /set %ramdisk% ramdisksdidevice partition=%RECDRV%
%BCDEDIT% /store %BCDSTORE% /set %ramdisk% ramdisksdipath \boot\%SDI_FILE%
echo.

echo.
echo Adding Win PE
echo ===========
echo.

for /f "Tokens=3" %%A in (''%BCDEDIT% /store %BCDSTORE% /create /application osloader'') do set GUID=%%A

echo.
echo recovery guid=%GUID%
echo.

%BCDEDIT% /store %BCDSTORE% /set %GUID% systemroot \Windows
%BCDEDIT% /store %BCDSTORE% /set %GUID% detecthal Yes
%BCDEDIT% /store %BCDSTORE% /set %GUID% winpe Yes
%BCDEDIT% /store %BCDSTORE% /set %GUID% osdevice ramdisk=[%RECDRV%]\Sources\%WIM_File%,%ramdisk%
%BCDEDIT% /store %BCDSTORE% /set %GUID% device ramdisk=[%RECDRV%]\Sources\%WIM_File%,%ramdisk%
%BCDEDIT% /store %BCDSTORE% /set %GUID% description "Recovery"
%BCDEDIT% /store %BCDSTORE% /displayorder %guid% /addlast

echo.
echo.
endlocal' | Out-File "$env:temp\configBCD.bat" -Encoding ascii
}

#Prompt if they want to run Recovery
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.VisualBasic") | Out-Null
$Answer = [Microsoft.VisualBasic.Interaction]::MsgBox("Would you like to run the recovery routine?",'YesNo,Question', "Execute Recovery")
If ($Answer -ne "Yes") {Exit}

#Prompt for Password
If ($sRecoveryPassword -ne $null) {
$PasswordMatch = $False
Do {
$password = Read-Host -Prompt "Please enter the Recovery password" -AsSecureString
$marshal = [System.Runtime.InteropServices.Marshal]
$ptr = $marshal::SecureStringToBSTR($password)
$password = $marshal::PtrToStringBSTR($ptr)
If ($password -eq $sRecoveryPassword) {$PasswordMatch = $true}
} While ($PasswordMatch -eq $false)
}

#Begin Recovery Routine
fMain

 

 
/Brian G

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.