Dynamically Update BIOS on Think Products with SCCM

NOTE: What follows is a brief look at what is possible and not necessarily recommended for everyone.  Hopefully someone finds it useful.

Earlier at MMS this year, a fantastic session on modern driver management in OS deployments was presented by Kim Oppalfens and Tom Degreef.  This method and what it entails can be found here.

I was inspired by their session and wanted to see if this could work with Lenovo's BIOS updates in a similar manner.  The workflow is basically the same, with the key piece being the overridable task sequence variable in the Download Package Content step called

Here's the layout of the Task Sequence:

Creating the Package(s):


You'll need to download the latest BIOS for your model from Lenovo's support site and extract the contents to a source directory.  Here's the folder structure I use in my lab:

<Share>\OSD\BIOS\<first 4 characters of BIOS>\<version>



The BIOS used here is for a ThinkPad Yoga 370.  You can find the SMBiosBiosVersion of your systems by running the following PowerShell command:

(get-wmiobject win32_bios).smbiosbiosversion

You can also find this on the BIOS Update Utility page for your system, near the bottom under Previous Version.

Back in the ConfigMgr console, create a standard package (no program).  Here's my Yoga 370 example:

You can name these however you want as long as you have the 1st 4 characters of the BIOS in the Name field.  Also recommended to include the version of the BIOS and for easy access to future BIOS updates, I added the URL to the Update Utility page for the system in the Comment field.  Distribute the newly created Package to your distribution points.

Dynamic BIOS PowerShell Script (Get-BIOSPackages.ps1)

Generate the XML by running the following commands (on the Site Server):
$SiteCode = $(Get-WmiObject -ComputerName $ENV:COMPUTERNAME -Namespace root\SMS -Class SMS_ProviderLocation).SiteCode

Get-WmiObject -Class sms_package -Namespace root\sms\site_$SiteCode | Select-Object Name,PackageID,Version | Sort-Object -Property Name | Export-Clixml -Path "BIOSPackages.xml"

Create another Package named Get-BIOSPackages (or whatever you want).  This will contain the source path of the PowerShell script that will dynamically match the system's BIOS to the appropriate PackageID as well as the BIOSPackages.xml that was generated above.  Credit goes to Kim Oppalfens for the original script, which I tweaked for the BIOS part.  

(Note: If using PowerShell v2, replace Get-CimInstance with Get-WmiObject)

[xml]$Packages = Get-Content BIOSPackages.xml

# Environment variable call for task sequence only
    $tsenv = New-Object -ComObject Microsoft.SMS.TSEnvironment
    $BIOS = (Get-CimInstance -Namespace root\cimv2 -ClassName Win32_BIOS).SMBIOSBIOSVersion.Substring(0,4)

    $ns = New-Object Xml.XmlNamespaceManager $Packages.NameTable

    $ns.AddNamespace( "def", "http://schemas.microsoft.com/powershell/2004/04" )


    $Package = ($Packages.SelectNodes($xpathqry,$ns))

    $PackageID = $Package.SelectNodes('def:S[contains(@N,"PackageID")]',$ns)

    $tsenv.Value('OSDDownloadDownloadPackages') = $PackageID.InnerXML

Task Sequence

1) Run PowerShell Script step, calling the Get-BIOSPackages.ps1

2) Download Package Content step:  Choose any Package here as it will be overridden anyway.

Tick the box to save the path as a variable named BIOS.  What happens here is when there's a package match to download, it will be saved to the C:\_SMSTaskSequence\Packages directory while also setting the custom variable of BIOS01, which is the first package being downloaded.  Here's what it looks like in the smsts.log.

Notice the PackageID of PS100077.  This matches the Yoga 370 Package that was created earlier.

3) Run Command Line: Flash ThinkPad BIOS

(If you have a combination of Think products, add a second and/or third step with the appropriate WMI query. See screenshots)

The command line here is simply executing winuptp64.exe with the silent switch, which is the BIOS flash utility.  The 64-bit version of winuptp should be found in just about all BIOS Update Utility packages for systems dating back to the Haswell line.

In the "Start in:" field, enter %BIOS01% as this will tell winuptp64.exe to execute from the directory as explained above.

4) Task Sequence Variable to reboot system.  This will complete the flash operation.

To finish the Task Sequence cleanly, I'm using the SMSTSPostAction variable with the value being wpeutil reboot (if in WinPE).  If in FullOS, use the native restart computer step.

Flash command lines and SMSTSPostAction values for ThinkCentre and ThinkStations are as follows:


Flash command line = flash64.cmd /ign /sccm /quiet

SMSTSPostAction (If in WinPE) = wpeutil shutdown 
     (If in FullOS) = cmd.exe /c shutdown -s -t 0 -f

(This will not shut down the system to the point of having to physically push the power button to turn back on.  This just instructs the BIOS update to proceed to phase 2 of the flash process. The system will reboot and finish out the update.)


Flash command line =  flashx64.cmd

SMSTSPostAction (If in WinPE) = wpeutil reboot 
     (If in FullOS) =  use native restart computer step

Other things to take into consideration 

Depending on your scenario, if updating BIOS from full OS, don't forget to disable BitLocker (if applicable) prior to continuing and re-enable post flash.

Consider the following "gotcha" scenario:

Windows 7 is installed on a ThinkCentre, which is encrypted with BitLocker.  The protectors will not automatically enable after the flash completes and the system has rebooted as opposed to Windows 10, leaving the system unprotected.  This is because of the required shutdown in order to finish the flash.  A possible workaround is to add a Run Command Line step to add a RunOnce reg key to enable protectors before the shutdown.  Here's the command line:

reg add HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce /v EnableBitLocker /t REG_SZ /d "cmd.exe /c manage-bde -protectors -enable c:"

Further Reading:

Download Package Content

Return codes for WINUPTP


  1. So when a new Version comes out how does it know that it has to update that ?

    1. Hi Vinod

      If a new BIOS is released, you'll just need to point the Package source location to the directory containing the contents of the new BIOS and update the Package on your distribution points.

  2. Hey, got this working - only thing I would recommend is to make a notation in the "Dynamic BIOS PowerShell Script (Get-BIOSPackages.ps1)" section, at the top, that the first Powershell script is supposed to be run on the SCCM site server.

    Also, it is updating the BIOS fine, but it does it no matter what, if the BIOS needs to be updated or not. Do you have any scripts or WMI queries that could detect if the BIOS is outdated?

    1. Hey Jason

      Glad you got this working. The BIOS update should not occur if the system has the same revision. Winuptp evaluates the BIOS version before attempting to update, which you can see in the smsts.log (or winuptp.log). It will simply skip the flash if the same version is installed. Is that not the case for you?

      Thanks for the feedback and will update the post!

  3. How do we account for an admin password being set in the BIOS and with the Thinkpads, is it necessary to have the battery inf? We are not updating the BIOS on new machines but rather machines that are already in the environment.

    1. Hi George

      Updating the BIOS doesn't require an admin password be entered, only if you're changing BIOS settings. If the systems are encrypted, remember to suspend protection before the update. Hope this helps.

  4. Can this be paired with the ThinkBiosConfig tool to set settings?

    1. Hi Nigel,

      Yes, this method can be paired with the TBCT to set settings.

  5. To integrate ThinkCentre BIOS update into a full SCCM task sequence, read this: http://www.osd-couture.com/2018/07/sccm-cb-make-your-task-sequence.html

    1. Hi Nicolas,

      Thanks for sharing your work. Very helpful!

  6. Very useful indeed. Thanks a lot.

  7. Phil, thanks for your work!
    In my case, it is failing when flashing BIOS, it appears to be a problem with the powershell.

    The message says:

    Method invocation failed because [System.Xml.XPathNodeList] does not contain a method
    named 'SelectNodes'.
    At line:1 char:1
    + $PackageID = $Package.SelectNodes('def:S[contains(@N,"PackageID")]',$ ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

    Do you know why it is happening?

    1. Hi, there's a note above regarding the version of PowerShell when using the Get-CimInstance cmdlet. Perhaps this could be your issue?

  8. Hey there Phil! Thanks so much for the walk through. I am new to SCCM and am following your process. When my machine begins to image I'm seeing all of the steps fly across the screen but it isn't actually getting around to the BIOS update before starting our regular Windows 10 deployment.

    You wouldn't happen to have an export of this job I could use to compare mine to. I've been over the steps several times, but it appears I must be missing something.

    Thank you!

    1. Hi Michael,

      Which models are you working with? Have you reviewed your smsts.log for any clues? Did you by any chance tick the "Continue on error" option on any of your steps? If so, you won't see the task sequence failure.

  9. Hi, does this still work for T490 etc?


Post a Comment