Deploy Lenovo ThinkCentre, ThinkPad, and ThinkStation BIOS by Custom WinPE

In this blog post, we are updating a previous post that only covered ThinkPad.  We have included updated scripting and information to cover ThinkCentre and ThinkStation as well.

Upgrading BIOS versions and getting consistency in an environment can provide unique challenges across an organization.  This blog post will lay out a possible process for putting together a custom WinPE boot WIM file to deploy a BIOS upgrades to current ThinkCentre, ThinkPad, and ThinkStation products.

Overview of the solution:

  1. Setup the server side folder structure
    • Folders
    • Logs
    • BIOS Folders
      • BIOS update files
    • Powershell script
  2. Configure the WinPE.wim file
    • Add necessary optional components
    • Add necessary drivers to the boot image
    • Edit the StartNet.cmd file in the WinPE.wim file.

Setup the server side folder structure

Beginning with the server side folder structure, create a new share (or use an existing share with appropriate permissions) on a server.  In that share, create a folder called BIOSVersions.  Inside BIOSVersions, create a folder called Logs and then create a folder with the first 4 digits of the SMBIOSBIOSVersion of each model computer with a BIOS to upgrade.




The folders seen above are for the X1 Carbon 4th (N1FE) and X1 Carbon 3rd (N14E).  The contents of each folder are made up of the source files from the Windows installable version of the BIOS from https:\\support.lenovo.com.  Once each BIOS has been downloaded and extracted, copy it to the coordinating folder.  Be sure to include all files and sub-folders from the extracted location.

Once the folder structure has been created and populated, create a blank Powershell file called BIOSUpdater.ps1 and copy the following lines of code to the file and save it.



#Define Variables
$exeName = ""
$srcDir = "T:\BIOSVersions\"
$localBiosFolder = "X:\bios"
$csproduct = Get-WmiObject -Class Win32_ComputerSystemProduct -Namespace root\cimv2
$deviceID = $csproduct.Name + '-' + $csproduct.IdentifyingNumber
$type = $csproduct.Version.Split()[0]
$model = $csproduct.Version.Split(' ', 2)[1]
$osArc = (Get-WmiObject -Class Win32_OperatingSystem -Namespace root\cimv2).OSArchitecture
$BiosCode = (Get-WmiObject -Class Win32_BIOS -Namespace root\cimv2).SMBIOSBIOSVersion.Substring(0,4)
$log = $srcDir + 'logs\' + $deviceID + '.log'

#Locate and Copy BIOS Folder
Write-Host "Locating BIOS folder"
$folder = Get-ChildItem -Path $srcDir | ? {$_.Name -eq $BiosCode}
if($folder -eq $null)
{
    "Could not find folder for $deviceID. Looking for $BiosCode" | out-file $log
    Write-Host "Could not locate BIOS folder"
    Write-Host "Examine log file on the share for more information"
    return
}
Write-Host "Located BIOS folder"

Write-Host "Begin BIOS Files Copy"
Copy-Item ($srcDir + $folder + '\*') $localBiosFolder -Recurse
Write-Host "Completed BIOS Files Copy"

#Execute BIOS Flash and Reboot
Write-Host "Executing BIOS Flash"
If($type -eq "ThinkPad")
{
    $exeName = if($osArc -eq "32-bit") {"WINUPTP.EXE"} else {"WINUPTP64.EXE"}
    $arg1 = "-s"
       
    & .\$exeName $arg1 | Out-Null
    
    If (Test-Path $localBiosFolder\winuptp.log)
    {
        Copy-Item $localBiosFolder\winuptp.log $log       # Copy the log file for this device to the network share for auditing purposes.
    } 
    Else 
    {
        "Could not find log file for $deviceID" | out-file $log
        Write-Host "Could not locate Winuptp.log file"
    }
    Write-Host "Completing BIOS Flash..."
    Write-Host "..."
    Write-Host "Rebooting"    
    & "wpeutil" reboot
}
ElseIf($type -eq "ThinkCentre" -or ($type -eq "ThinkStation" -and $model -like "P3*"))
{
    & ".\Flash.cmd" /ign /sccm /quiet | Out-File $log # Check the readme.txt to ensure that each WFlash2.exe supports the /SCCM (Reboot Suppress) switch.
    Write-Host "Completing BIOS Flash..."
    Write-Host "..."
    Write-Host "Rebooting"
    & "wpeutil" shutdown      # This needs to be a shutdown command, as the ThinkCentre BIOS documentation states 
                              # that the computer needs to reach an S5 power state to complete the update of the 
                              # BIOS.  Computer will actually reboot.
}
ElseIf($type -eq "ThinkStation")
{
    $exeName = if($osArc -eq "32-bit") {"AFUWIN.EXE"} else {"AFUWINx64.EXE"}
    $ROMName = Get-ChildItem -Path $localBiosFolder -Include "*.ROM" -Name
    & .\$exeName $ROMName /P /B /N /R /SP /RTB /FIT | Out-File $log
    Write-Host "Completing BIOS Flash..."
    Write-Host "..."
    Write-Host "Rebooting"
    & "wpeutil" reboot
}
Else
{
    "Unable to determine type of machine for $deviceID" | out-file $log
    Write-Host "Unable to determine type of machine for $deviceID"
}

BIOSUpdater.ps1


Configure the WinPE.wim file

The next item is to configure the WinPE.wim file with all of the pertinent optional components, drivers, and script updates.

In this example, we have the Windows 10 ADK installed to the default directory (C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment).  

Copy the winpe.wim file from amd64\en-us folder to a spot to work with it.  I am using D:\TestBIOS\WinPE.wim as the area that is copied to.

Load the the wim file into command window using the DISM Command to open the image.


Dism /Mount-Image /ImageFile:D:\TestBios\WinPE.wim /Index:1 /MountDir:D:\MountIt

Next we need to configure Optional Components.  Add the following Optional Components in this specific order, as order does matter for this installation:


1. HTA:


Dism /Image:D:\MountIt /Add-Package /PackagePath:"C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\WinPE-HTA.cab"
Dism /Image:D:\MountIt /Add-Package /PackagePath:"C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\en-us\WinPE-HTA_en-us.cab"

2. Scripting:


Dism /Image:D:\MountIt /Add-Package /PackagePath:"C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\WinPE-Scripting.cab"
Dism /Image:D:\MountIt /Add-Package /PackagePath:"C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\en-us\WinPE-Scripting_en-us.cab"

3. WMI:


Dism /Image:D:\MountIt /Add-Package /PackagePath:"C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\WinPE-WMI.cab"
Dism /Image:D:\MountIt /Add-Package /PackagePath:"C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\en-us\WinPE-WMI_en-us.cab"

4. .NET Framework (NetFX):


Dism /Image:D:\MountIt /Add-Package /PackagePath:"C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\WinPE-NetFX.cab"
Dism /Image:D:\MountIt /Add-Package /PackagePath:"C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\en-us\WinPE-NetFX_en-us.cab"

5. Powershell:


Dism /Image:D:\MountIt /Add-Package /PackagePath:"C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\WinPE-Powershell.cab"
Dism /Image:D:\MountIt /Add-Package /PackagePath:"C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\en-us\WinPE-Powershell_en-us.cab"

After loading those optional components, we need to add in a driver for interrogating the battery status on ThinkPads.


Dism /Image:D:\MountIt /Add-Driver /Driver:D:\MountIt\Windows\INF\Battery.inf

Next we load any networking drivers needed.  I suggest using the WinPE Boot Image Driver Packs.


Dism /Image:D:\MountIt /Add-Driver /Driver:<Path to extracted WinPE Drivers>

The last item is to edit the StartNet.cmd file located at
D:\MountIt\Windows\System32.  Add the following lines of code to the .cmd file after the "wpeinit" line. Change <Server>, <Share>, <password>, and <domain>\<user> to your appropriate values. Save and then close the file.



@echo OFF
echo Loading 3rd party PNP drivers
wpeinit
echo Completed 3rd party PNP driver load
echo Creating directory: X:\BIOS
mkdir X:\BIOS
cd X:\BIOS
echo Completed directory creation
echo Attempting conection to share.
@ipconfig > ipconfig.txt
@ping <SERVER> > ping.txt
@net use T: \\<SERVER>\<SHARE> <PASSWORD> /user:<DOMAIN>\<USER>
IF NOT %ErrorLevel% EQU 0 goto EndDrv
echo Copying powershell script file locally.
xcopy T:\BIOSVersions\BiosUpdater.ps1 /iqvy
Powershell -ExecutionPolicy UnRestricted -File X:\BIOS\BiosUpdater.ps1
:EndDrv
echo Connection to server\share not established.  Please reboot and try again.

Finally we use Dism to close up the WinPE.wim file.


Dism /Unmount-Image /MountDir:D:\MountIt /commit

Once the WinPE.wim file closes up completely, load it into WDS or your favorite PXE Service and update a BIOS.

When your ThinkCentre, ThinkPad, or ThinkStation client PXE boots this boot image, it will automatically launch the BiosUpdate.ps1 script.  The script will find the appropriate BIOS update source files on the network share and will execute the BIOS update silently.  The script will then reboot the system at which time the BIOS will be updated.  Once complete the system will reboot back to Windows.

Comments

  1. Thanks for a really good blog!

    Can the BIOSUpdater.ps1 script be used in a SCCM task sequence instead?

    ReplyDelete
    Replies
    1. In my opinion, it would be best to not try to incorporate this in to a Config Manager task sequence. It is best to allow Config Manager to control reboots. All of the logic needed is already designed into the task sequence. Using the options tab on an individual task to target an installation of an application or package will be the best way to go.

      Delete
  2. Where can I find a WFlash2.exe that supports the /SCCM switch?

    ReplyDelete
    Replies
    1. The flash tools are included in the current BIOS update for each particular model. Old models and those that are not M-Series may not support /sccm switch.

      Delete
    2. This comment has been removed by the author.

      Delete
    3. But can the newer version available with say an M900 work with the M82 or M83? And if not, then how can we suppress reboots when updating the M82 or M83?

      Delete
  3. for the thinkpad winuptp.exe -s how do we suppress the reboot and wait for the flash process to complete and pass a propper error code SCCM will understand? we need to control the reboot vit he task sequence. Rather than bloat our WinPe package with these applications

    ReplyDelete
    Replies
    1. This is designed to be a stand alone WinPE boot image. It is not intended to work inside of Config Manager, as Config Manager controls the WinPE images itself. The other point to clarify is that none of the applications (BIOS installers) are stored in the WinPE image, they are hosted on a network location. Only a few items are installed to WinPE ex. the Optional Components, the network drivers, and the batch file.

      Delete

Post a Comment