Modern BIOS Management – Lenovo Systems

PLEASE NOTE: Some of the details and features in this post have been superseded. Please review our Modern Driver Management and Modern BIOS Management solutions for up to date information.

Original Post:

This is a follow up post continuing from the Modern BIOS Management post in June ( which focused on Dell hardware.

Following the post we had numerous requests to apply the same logic for other manufacturers. So here is the first of which, the update being for Lenovo systems:

As my current environment is virtually all Dell, I had to reach out to come members of the ConfigMgr community to perform tests of modified scripts so I would like to thank Zeng Yinghua (aka Sandy – @sandy_tsang), Eugeny Korneev (@eugeny_korneev) and Lauri Kurvinen (@etsmii) for putting in long hours of testing on their Lenovo devices.

Note that I am not going to step through the entire process in this post, so please refer to the original post for set up instructions.

How Does It Work

The same process used in the original post linked at the top of this post is used, the process uses a web service and WMI queries in PowerShell to match available packages. To cater for Lenovo systems we have updated our BIOS Package Detection script so if you are already using this, please update the script.

BIOS Package Detection Script (At least version 1.0.4):

In order to cater for Lenovo systems we have created an update script which looks at the content of the downloaded package and determines the update method to apply. This was required as Lenovo have two different methods using either their WinUPTP or FlashCMD utilities. The script also takes into account whether the process is to be run in WinPE as this process is only supported by the 64 bit version of the WinUPTP utility.

BIOS Update Script (Lenovo):

Update In Action

In the below screenshot you can see the process of matching an available download to the model currently running the task sequence:

In this next screenshot you can see an output of the bios update log:

Lenovo Model Matching

Having had a lot of feedback recently from community members with Lenovo based client deployments it became clear that matching Lenovo models based on the Get-WmiObject -Class Win32_ComputerSystemProduct | Select-Object -ExpandProperty Version method was somewhat hit and miss for some Lenovo models.

To help cater for this the script has been updated to work in conjunction with an update for the Download Automation Tool (version 4.0.9) which now writes all product types associated with a model name into the package comments in ConfigMgr.

Below is an example of a BIOS package for a Lenovo ThinkPad T460

As you can see there are 10 distinct product type values which should provide a match for this package, so during the Invoke-CMDownloadBIOSPackage.ps1 stage we obtain a full list of packages which contain a match based on the first four digits of the Get-WmiObject -Class Win32_ComputerSystem | Select-Object -ExpandProperty Model value, which should coincide with the model types.

If multiple packages are found, we then try to match on the name of the package against the product name (obtained from Get-WmiObject -Class Win32_ComputerSystemProduct | Select-Object -ExpandProperty Version value). The reason for this is clear if we take the example of the ThinkPad T460 and the T460S, both similar but separately named models so you would imagine that the machines would distinct in their model type codes, however this is not the case;

T460 Model Types – 20FN 20FM 20FN 20FM 20FX 20FW 20FX 20FW 20FA 20F9

T460S Model Types – 20FA 20F9

You might ask then if that is the case then surely a single package would work for both, and where as you might be correct we found that the T460s BIOS download in this instance contained a subtle difference in the sub version relating to the embedded controller was different. In the case of the T460, the download included 09 of the embedded controller software, where as the T460S contained version 11.

Version Checking

Version checking for Lenovo models has also been overhauled as the value obtained from Get-WmiObject -Class Win32_BIOS | Select-Object -ExpandProperty SMBIOSBIOSVersion does not always fall into a sequence that can be easily compared. So for Lenovo hardware we are now comparing the BIOS release date, which again works in conjunction with details contained within the package contents.

Once a match has been found, the script sets a TS environment variable called “NewBIOSAvailable” with a value of “True“. This then enables you to filter your Download BIOS Package and Run BIOS Update Script actions based on a query to see if the value is equal to True. This saves you attempting to flash the bios with the same version during your task sequence.

Things To Note:

In order for the BIOS to apply the system will require a shutdown. For this purpose Lenovo recommend either using a command-line shutdown or setting the SMSTSPostAction variable set to use the “SMSTSPostAction” variable and the value set to “shutdown /s /t 0 /f”. More info at –

Nicke Källén also has a blog post with an alternative method for getting past the shutdown requirement –

BIOS Packages – Note that due to changes in the way in which the packages are named and the comments included, you will need to remove and replace your existing Lenovo BIOS packages created with this tool.


If you have any feedback on this please ping me an email at [email protected]

Nickolaj Andersen
Principal Consultant and Enterprise Mobility MVP. Nickolaj has been in the IT industry for the past 10 years specializing in Enterprise Mobility and Security, Windows deployments and Automation. In 2015 Nickolaj was awarded as PowerShell Hero by the community for his script and tools contributions. Author of ConfigMgr Prerequisites Tool, ConfigMgr OSD FrontEnd, ConfigMgr WebService and a frequent speaker at user groups.

Maurice Daly

Maurice has been working in the IT industry for the past 20 years and currently working in the role of Senior Cloud Architect with CloudWay. With a focus on OS deployment through SCCM/MDT, group policies, active directory, virtualisation and office 365, Maurice has been a Windows Server MCSE since 2008 and was awarded Enterprise Mobility MVP in March 2017. Most recently his focus has been on automation of deployment tasks, creating and sharing PowerShell scripts and other content to help others streamline their deployment processes.


  • We found out today that in some of the Lenovo models such as the ThinkCentre M900, they broke with their standard and included a Flash64.cmd rather than simply detecting the architecture inside Flash.cmd, which makes the current version (January 29 2018) fail to pick the right version of WFlash2, and the BIOS update fails.

    In our case, we’ve added the following line between 99 and 100 inside the 64-bit environment check:
    $FlashCMDUtility = Get-ChildItem -Path $Path -Filter “*.cmd” -Recurse | Where-Object { $_.Name -like “Flash64.cmd” } | Select-Object -ExpandProperty FullName

    We also contained line 107 inside an if-check to verify whether or not we are in a 64-bit environment with a Flash64.cmd, as follows:
    if ($FlashCMDUtility -eq $null)
    $FlashCMDUtility = Get-ChildItem -Path $Path -Filter “*.cmd” -Recurse | Where-Object { $_.Name -like “Flash.cmd” } | Select-Object -ExpandProperty FullName

    To summarize, if we’re in a 64-bit environment, check if there’s a Flash64.cmd. If there is, use it. If not (because we’re in a 32-bit environment or it doesn’t exist), check for a Flash.cmd. This allows line 122 to use the best available $FlashUtility rather than picking something which will break our Task Sequence even if it’s told to continue on error.

  • This is super amazing!

    The 5.1.5 version did indeed fix the issue I was experiencing where Lenovo download repository folders were showing up empty.

    Note: I think that “Lenovo Thinkpad Yoga 11e 2nd Gen” (machine type 20E7, 20E5) and “Lenovo Thinkpad 11e 2nd Gen” (machine type 20E6, 20E8) are missing from the Available Models list. Both of those use this driver package:

    Recipe card for Thinkpad Yoga 11e 2nd Gen:

    Recipe card for Thinkpad 11e 2nd Gen:

    • Unfortunately when it comes to models, the lists (XML files) provided are by the manufacturers so I don’t have control over this. There is a possibility that the models will be added in their future releases though.

  • So I am having an issue with updating the ThinkCentre’s and Thinkstations. I had to modified the script to get it to work with the flash64.cmd and rem out the Password. I also put in the wpeutil shutdown (ThinkCentre) and reboot (ThinkStation) in the task sequence. This is what’s happening, it do the Lenovo Bios Utility setup (writing the blocks, etc), then it reboots but it never goes into the 2nd Phase which Flashes the Bios. It seems to try, it looks like it will happen, but then reboots again into the OS. What is causing it not to do the 2nd Phase of Flashing the Bios?

  • Can this same method be used with a simple task sequence to update the bios without re-imaging the computer? Is it safe to use in the full windows environment as opposed to WinPE?

    This would be very useful for updating computers already in the field with the new wave of bios updates related to meltdown/spectre.

    • Steve,

      There will be updates to the BIOS and Driver scripts posted later today that allow for this and should solve the other issue you reported.


      • A couple of other questions – it looks like Invoke-CMDownloadBIOSPackage.ps1 is triggering the content download of the bios update. Is it still necessary to follow this script with a Download Package Content step that downloads a dummy package?
        Also, the script seems to be saving the bios update package in a folder named “BIOSPackage”, instead of “BIOS”, which was the folder name used in that Download Package Content step from the original article. If that step is still required, should the custom path setting be “%_SMSTSMDataPath%\BIOSPackage” instead of “%_SMSTSMDataPath%\BIOS” ?

    • Steve, I am working on this my company. I created a Task Sequence to deploy like a package. I had to create a Boot Image with HTA and Powershell, because it is needed to run the Bios scripts. So this TS Suspends Bitlocker, then downloads the Boot Image and reboots the machine to run the Bios Scripts. It works great on the Thinkpad’s but I am having issues with the ThinkCentre’s and ThinkStation. For some reason, these workstations do the bios in a 2 phase setup. It first does the phase 1 which does the Lenovo Setup Utility to write the blocks for the bios, then it should reboot and then 2nd phase to Flash the Bios. The problem is the 2nd phase seems to timeout and does not run. It then reboots again and back into the OS.

      • That makes sense. I’m hoping to do it without having to reboot into PE. These bios packages are designed to be run from within the full windows environment, so there should be no reason a reboot to PE is required. I think the changes Maurice made to the script today fixed the main issue there. I’ve got it working now on a couple of test computers, but not perfected yet.

        In fact, what I’d like to do is get this small ‘Update BIOS’ task sequence working smoothly, and then be able to call the same task sequence from within my OSD TS, so that there’s one bit of logic that is reused everywhere and only one place to go to update them all. We’ll see if I end up getting there or not. . .

  • When trying to get BIOS download only or package it appears that it is downloading the file it needs and extracting the files to the set repository, however there is no files in the BIOS folder where it should be. This is for Lenovo machines. Just wondering if I am doing something wrong. There are no errors in the log.

    • Hi Eric,

      Could you let me know a couple of things, such as the OS you are running the script in, are you running it locally or remotely and are you running this in an elevated PowerShell window?. If you could also let me know the model(s) you are trying to download the BIOS for?.


      • I’m experiencing the same thing as Eric. I’m trying this for the first time running DriverAutomationTool.exe version 5.1.3 . I’m trying just downloading for now and not linking to SCCM. I’m running locally on a 1703 sysem.

        Lenovo\Model\BIOS\version folders get created, but are empty. I’ve tried Lenovo ThinkPad Yoga 11e, Yoga 11e 3rd Gen, Yoga 11e 4th Gen, Yoga 12, Yoga 260 and Yoga 370 so far and the folders all end up empty. I also tried a Dell Latitude 7389, which worked.

        There have been a lot of BIOS updates lately addressing Meltdown and Spectre. Shot in the dark that something organizationally has changed with Lenovo after all that? I’m also running on a work computer where we have lots of web filtering and wondering if maybe I’m getting blocked on something- will try on my 1709 home computer and see if I have the same issue.

      • Hi,

        I have been made aware of thr issue and I’ll be putting out a fix following feedback from a test user. For the time being can you try running the PS1 directly as a work around.


  • So we used this to update BIOS on already deployed machines. We created a Task Sequence to Suspend BitLocker and then Restart Computer into WinPE. Run the Dynamic and Run Bios Scripts. We had issue with the WinUPTP64.exe missing the Oledlg.dll in the command. I solved it by copying the Oledlg.dll and oledlg.dll.mui into the Lenovo Bios Package. This worked, but did not want to update all Lenovo Packages, so I found if I created a Boot Image with Powershell, .NETfx and HTA, it updated the BIOS fine. I have a Restart in the TS that restarts it into the OS, the Bitlocker is turned back on automatically. Updated the BIOS without reimaging the machine.

  • Hi, firstly thank you for creating and publishing the Driver Automation Tool and all the guides to go with it!

    I’m trying to get it implemented so that I can finally make use of Modern BIOS management – already using Modern Driver Management although without the Automation Tool. My problem is that when I specify a network share location for the repository and package path I’m getting an error during BIOS download:

    Info: New BIOS download available DriverAutomationTool 22/11/2017 14:21:06 8688 (0x21F0)
    Info: BIOS update directory set to \\zz\zzzzzzzz\SCCM\SOURCES\OSD\DRIVER_REPOSITORY\Lenovo\ThinkCentre M900\BIOS\1.7F\ DriverAutomationTool 22/11/2017 14:21:06 8688 (0x21F0)
    Info: Downloading BIOS update file from DriverAutomationTool 22/11/2017 14:21:06 8688 (0x21F0)
    Error: The system cannot find the file specified. (Exception from HRESULT: 0x80070002) DriverAutomationTool 22/11/2017 14:21:08 8688 (0x21F0)
    Error: BIOS failed to download. Check log for more details DriverAutomationTool 22/11/2017 14:21:08 8688 (0x21F0)
    ======== ThinkCentre M900 BIOS PROCESSING FINISHED ======== DriverAutomationTool 22/11/2017 14:21:08 8688 (0x21F0)

    It downloads a .tmp file to the right location so I don’t think it’s a permission issue. There is an issue with my network share in that it can be slow, for example if I create a text file and immediately try to edit it, it says file not found. It takes 3-5 seconds after creating a new file for it to actually become available. I wonder if this could be the cause of my error? I attempted to add a Start-Sleep command into the PowerShell script but it hasn’t helped – probably not putting it in the right place assuming it would even fix my issue!

    Any help would be much appreciated, this tool will make life so much easier in managing BIOS updates.


    • Nevermind! I’ve answered my own question by running the Driver Automation Tool on the site server – this quite happily used the network share and works fully.

  • I’ve been testing this against systems where they BIOS was updated using the scripts supplied here, but subsequent TaskSequence runs still have the BIOS files downloading (even if the BIOS is matched). Has anyone had success with the NewBIOSAvailable TS Variable?

    • Hi Mario,

      It appears that in some instances the new version of the BIOS is not updating the release date. Can you confirm this is the case here?.


      • Hi Maurice. I will check tomorrow and respond with my findings.

      • Seems that you are correct. My two test systems (TP13 Gen 2 and X1 Carbon 3rd Gen) have mismatched dates. How is the release date being generated in the package comments section? Lenovo supplied xmls in the automated download tool?

  • Looks like line 169 needs to be commented out in the most recent version of Invoke-CMDownloadBIOSPackage.ps1.

  • Disregard – went through your BIOSDownload script a bit more and found some typos/misplaced hashtags (line 166 and 169). Working great now!

  • Thanks for these scripts and your effort to simplifying every CMAdmins job!

    I have been using your Driver Automation tool and driver scripts without fail. However, having a hard time getting the BIOS files to download. Checking the BIOSPackageDownload.log, it finds the number of BIOS packages I have, but does not enumerate the models available in the log. All Lenovo here so any help would be appreciated

  • Nice! I was actively working on this. I already had the ‘pick the bios package’ piece written, but I like your “Invoke-LenovoBIOSUpdate” better than mine. For the download piece though with Lenovo, what worked GREAT for me was is below. Because your bios/driver tools tosses in that 4 character Lenovo model, I’ve just been doing a substring match and getting great results. I just populate a $LenovoModel variable if the manufacturer is Lenovo.

    #this is all in my variable section
    $PC = Get-CimInstance -CimSession $CIMSession -ClassName win32_computersystemproduct -Namespace root\cimv2
    $Vendor = $PC.Vendor
    if ($Vendor -match “lenovo”)
    $Model = $PC.Version
    $LenovoModel = $PC.Name
    $Model = $PC.Name
    #this is all in my variable section

    #and this is part of my get-biospackage function
    if ($LenovoModel)
    Write-CMLogEntry -Value “Computer is $Vendor – Found BIOS Update packages, now checking for a match on $($LenovoModel.SubString(0, 4))”
    $CheckModel = $Results.where{ $_.PackageDescription -match $LenovoModel.SubString(0, 4) }
    Write-CMLogEntry -Value “Computer is $Vendor – Found BIOS Update packages, now checking for a match on $Model”
    $CheckModel = $Results.where{ $_.PackageName -match $Model }
    #and this is part of my get-biospackage function

    • Ignore my comment! I just went back through your code and it does exactly what mine does =) you check for the lenovo model, and then the “model” as a double check if needed.

  • Okay, new issue. Now I get a failure just after it runs Invoke-CMDownloadBiosPackage.ps1. I checked the logs and found an error that read:
    “Method invocation failed because [Selected.System.Management.ManagementObject] does not contain a method named SubString:
    At C;\_SMSTaskSequence\Packages\SS10006A\Invoke-CMDownloadBiosPackage.ps1:184 char:4

    • Try it now. I should have included -ExpandProperty, the script has been updated.


Categories use cookies to ensure that we give you the best experience on our website.