Maintaining BIOS & Drivers Post Windows Deployment

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:

So you have deployed your machines with the latest and greatest drivers and BIOS updates. But then the questions of what to do to maintain your systems post deployment?, or do I upgrade the BIOS and drivers as part of an upgrade TS?

These are questions that I have had asked more than a few times of late. In answer to your question, there are several methods to maintain both the BIOS and drivers on the machines but most are vendor specific / developed.

The vendor utilities where available do a good job, the Dell Command Update utility is an excellent example of how to do things right. In some cases however, this means also maintaining a separate master repository for the machines to scan or allowing internet access. When you talk about allowing machines to maintain their driver and BIOS version over the internet, the lack of version control is something that most ConfigMgr admins will complain about. The complaints are justified though, as we all know that system stability can be greatly affected by drivers. So this got me thinking.

Maintaining the BIOS version through our Modern BIOS Management approach has been around for a little while now, so I thought I would extend this maintenance approach to cater for drivers. Below I will show you how you can wrap this up into a single task sequence and then deploy this to your client fleet. You can of course have it re-run as often as you wish within a maintenance window or on-demand for those mobile workers who are seldom in the office.

PowerShell + WebService FTW

Most of you who are familiar with our MDM & MBM solutions will know that we can dynamically determine/download the latest available versions of driver and BIOS packages from ConfigMgr. So I have extended the Invoke-CMApplyDriverPackage.ps1 script used to undertake driver matching and downloading in WinPE with an additional switch, that being the “OSMaintenance” switch. The new switch allows you to tell the script to perform some actions differently, the key action of course being to avoid the DISM step which we cannot undertake on an already deployed OS.

When run with a $true value for the optional OSMaintenance switch works to detect the currently installed version of Windows, this time however not based on the WIM being deployed but on the properties of the NTDLL.DLL. If a matching package is found, it is downloaded and then ready for the next step. Note: This does mean that your task sequence will require a reboot into WinPE for this process to complete, this is due to the method in which we leverage the OSDDownloadContent command.

Applying Drivers

Having taken influence from an earlier post by Mikael Nystrom (, I have created an additional PowerShell script that leverages the fact we already have a process for downloading the latest available driver package from ConfigMgr. Using the PNPUtil command all we need to do is point the utility at the location to which we downloaded the driver package and your system will then detect and install the latest drivers contained within;

# Apply driver maintenance package
try {
	Write-CMLogEntry -Value "Starting driver installation process" -Severity 1
	Write-CMLogEntry -Value "Reading drivers from $DriverPackagePath" -Severity 1
	if ((Get-ChildItem -Path $DriverPackagePath -Filter *.inf -Recurse).count -gt 0) {
		Get-ChildItem -Path $DriverPackagePath -Filter *.inf -Recurse | ForEach-Object {
			pnputil /add-driver $_.FullName /install
		} | Out-File -FilePath (Join-Path -Path $LogFilePath -ChildPath DriverMaintenance.log) -Force
		Write-CMLogEntry -Value "Driver installation complete. Restart required" -Severity 1
	else {
		Write-CMLogEntry -Value "No driver inf files found in $DriverPackagePath." -Severity 3; exit 1
} catch [System.Exception] {
	Write-CMLogEntry -Value "An error occurred while attempting to apply the driver maintenance package. Error message: $($_.Exception.Message)" -Severity 3; exit 1

The Task Sequence

In the sequence below there are 8 key steps with others being optional. This will ensure that your machine is kept up to date at all times. Remember this requires no client software and you can tailor logging values to suit your environment.

Lets step through the process
  1. Suspend your disk encryption protection to allow for the BIOS to be updated
  2. Restart the computer into WinPE
  3. Run the Invoke-CMDownloadBiosPackage.ps1 PowerShell script.
  4. Run the vendor specific BIOS update script, in this example we are using the Invoke-DellBIOSUpdate.ps1 for Dell system. Restart to apply BIOS. (You can create a group for the BIOS update process and apply a WMI filter using a variable check for NewBIOSAvailable equals “True”. This will prevent the system attempting to flash the BIOS and restart if the version if current)
  5. Run the Invoke-CMApplyDriverPackage.ps1 PowerShell script with the following switches:
    -URI “https://%YOURSERVERNAME%/ConfigMgrWebService/ConfigMgr.asmx” -SecretKey “%YOURSECRETKEY” -Filter “Drivers” -OSMaintenance
  6. Restart the computer into the full OS
  7. Run the Invoke-CMDriverMaintenance.ps1 script to apply drivers
  8. Restart the computer to commit the driver updates


In the below example we have a Dell Optiplex 7040. Looking at Dell’s SCCM driver site, we can determine that we should be expecting at least the following drivers to be updated as part of the maintenance TS.

ArchCategoryDevice DescriptionPrevious CABCurrent CABStatus
x64audioRealtek High-Definition Audio DriverReleaseID: DDG39
DellVersion: A06
ReleaseID: RT1XX
DellVersion: A07
x64storageIntel Rapid Storage Technology Driver and Management ConsoleReleaseID: 02RN8
DellVersion: A05
ReleaseID: CRRKJ
DellVersion: A07
x64videoIntel HD, 500, P500 series Graphics DriverReleaseID: WNF3C
DellVersion: A10
ReleaseID: TDP4X
DellVersion: A11

Driver Package A09 – Source:

Intel Storage Driver

PowerShell Script Sources

The PowerShell scripts referenced are available on GitHub – Here you will also find an optional script for applying a maintenance notice and background (as pictured in the task sequence) –


Maintaining drivers and BIOS versions can easily be automated with this method. Now set up your task sequences, deploy and keep your environment current.

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.


  • No thanks, not anymore 😉

    I ran the script on a HP EliteBook 840 G5 having bios “Q78 ver 01.01.07”
    When the Invoke-CMDownloadBIOSPackage.ps1 ran it skipped the step “Invoke-HPBIOSUpdate.ps1” because bios was already the latest.

    Here is the ApplyBIOSPackage.log

    Also, can you tell me what is behind the step ‘Update Logon Message’?

  • Hello Maurice,

    I’m attempting to do the FullOS Driver and BIOS update again using the latest scripts you have to date. The task sequence works in downloading the BIOS and injecting the correct drivers all within the OS; no longer need to boot to WinPE. The TS requests a restart on the device. However, upon rebooting and manually logging back into the machine, SCCM shows that the TS failed with a code: 0x1010(4112)

    Is there something else that i’m missing in the TS besides running the scripts:

    Invoke-CMDownloadBIOSPackage (using switch -DeploymentType DriverUpdate)
    Invoke-CMApplyDriverPackage (using switch -DeploymentType DriverUpdate)

    I’d figure each one of these scripts would write a regkey in the OS to let the TS know its compliant/successful or maybe a TS variable .


  • If that is the case, I’m wondering if I can format this whole process into an application package using PADTK that I can deploy to my workstations instead of using the task SCCM sequence engine. The only reason I suggested this was so that I can use registry key branding to detect if there are new Dell BIOS and packs available for install.

    This would be a sweet deal so that it gives customers to update their machines when they want and would let them know that there is an updated available for their model.

    Thanks again and as always….”big ups!” for creating such a cool tool and process.


  • With the latest “Invoke-CMApplyDriverPackage” Powershell script (version 2.0.5), what is the task sequence restart process look like when applying updates to an existing FullOS; using the -DeploymentType DriverUpdate command?

    Do we still need to reboot the host computer into WinPE? and then run the “Invoke-CMApplyDriverPackag.ps1” -DeploymentType DriverUpdate?


    • Hi Dean,

      The process is to simply call the script in a task sequence with the DeploymentType set to DriverUpdate. The script will then download the drivers and use the PNPutil command to update the drivers. There is no need to reboot into WinPE using this method.


  • Maurice,

    Can the Bios and Drivers be updated outside of WinPE? I’m trying to update Bios and Drivers on computers that are on VPN and they would have to do everything within it’s session and reboot just to finish installing the bios.

    • Hi Bruce,

      The BIOS and Drivers can indeed be updated outside of WinPE. If you view the solutions pages you will see the switches for running the updates in the Full OS.


  • Trying to setup a new TS with all the newest script, i get in DellBIOSUpdate.log that it is unable to locate the flash64w utility..

    its part of the bios package that is downloadeed with the driver automation tool, so uncertain where the fault lies?

    • Hi Thomas,

      If you look in the log you will see an entry to confirm that the Flash64w utility has been downloaded. You can also check this in the repository path you specified. Assuming that there have been no issues downloading and extracting the exe from the zip file containing the Flash64w, then I suggest you use content explorer to ensure that your DP has both files in the package.


      • The file has been downloaded, together with the correct bios file, it sets the package with a custom variable of OSDBIOSPacakge01. It when running the invoke-DELLBIOSUpdate script it fails with incorrect function, as if the file itself is missing, or looking at the wrong place.

        I have verified that the TS has the -Path “%OSDBIOSPackage01%” in itself. Running v1.05 of the Dell BIOSUupdate script.

        smsts.log shows the following:
        Resolved source to ‘C:\_SMSTaskSequence\Packages\UMV00295’
        Command line for extension .exe is “%1” %*
        Set command line: Run Powershell script
        Working dir ‘C:\_SMSTaskSequence\Packages\UMV00295’
        Executing command line: Run Powershell script
        Process completed with exit code 1
        Command line returned 1

      • What does the contents of the Invoke-DellBIOSUpdate log file look like?

      • 3 Simple lines.

        Initiating script to determine flashing capabilities for Dell BIOS updates
        Attempting to use flash utility:
        Unable to locate the Flash64W.exe utility

        The funny thing, is that it did actually update it aswell this last time, for unknown reasons.

      • Can you drop me a mail with a screenshot of the Run PowerShell step used for the Invoke-DellBIOSUpdate?

  • having an issue where the Invoke-CMDownloadBIOSPackage.ps1 will correctly query BIOS packages, and return a number of packages that match the filter, but then it doesn’t go any further.

    BIOS download package process initiated 1/1/1601 12:00:00 AM 0 (0x0000)
    Manufacturer determined as: Hewlett-Packard 1/1/1601 12:00:00 AM 0 (0x0000)
    Computer model determined as: HP Z440 Workstation 1/1/1601 12:00:00 AM 0 (0x0000)
    Current BIOS version determined as: M60 v02.39 1/1/1601 12:00:00 AM 0 (0x0000)
    Retrieved a total of 11 BIOS packages from web service 1/1/1601 12:00:00 AM 0 (0x0000)
    Setting task sequence variable OSDDownloadDownloadPackages to a blank value 1/1/1601 12:00:00 AM 0 (0x0000)
    Setting task sequence variable OSDDownloadDestinationLocationType to a blank value 1/1/1601 12:00:00 AM 0 (0x0000)
    Setting task sequence variable OSDDownloadDestinationVariable to a blank value 1/1/1601 12:00:00 AM 0 (0x0000)
    Setting task sequence variable OSDDownloadDestinationPath to a blank value 1/1/1601 12:00:00 AM 0 (0x0000)

      • Just after spotting this reply. Can you please upgrade to v1.5.0 of the web service and if you could also change the manufacture on the HP BIOS packages to “Hewlett-Packard” as historically “HP” was used.

    • Hi Kevin,

      What version of the Invoke script and web service are you running?.


  • I’m in the process of trying to update the BIOS using ConfigMgr WebServices with the Invoke-CMDownloadBIOSPackage.ps1 and the Invoke-LenovoBIOSUpdate.ps1 scripts. I followed the steps in your directions but I keep getting the following error in the smsts.log file. The BIOSPackageDownload.log file is never created.

    Executing command line: Run Powershell script RunPowerShellScript 12/7/2017 1:56:09 PM 1500 (0x05DC)
    C:\_SMSTaskSequence\Packages\GCS0012D\Invoke-CMDownloadBIOSPackage.ps1 : A positional parameter cannot be found that RunPowerShellScript 12/7/2017 1:56:13 PM 1500 (0x05DC)
    accepts argument ‘Update’. RunPowerShellScript 12/7/2017 1:56:13 PM 1500 (0x05DC)
    At line:1 char:1 RunPowerShellScript 12/7/2017 1:56:13 PM 1500 (0x05DC)
    + & ‘C:\_SMSTaskSequence\Packages\GCS0012D\Invoke-CMDownloadBIOSPackage … RunPowerShellScript 12/7/2017 1:56:13 PM 1500 (0x05DC)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RunPowerShellScript 12/7/2017 1:56:13 PM 1500 (0x05DC)
    + CategoryInfo : InvalidArgument: (:) [Invoke-CMDownloadBIOSPackage.ps1], ParameterBindingException RunPowerShellScript 12/7/2017 1:56:13 PM 1500 (0x05DC)
    + FullyQualifiedErrorId : PositionalParameterNotFound,Invoke-CMDownloadBIOSPackage.ps1 RunPowerShellScript 12/7/2017 1:56:13 PM 1500 (0x05DC)

    Any help would be appreciated.

      • Also, the Modern BIOS Management is a package that contains the Invoke-CMDownloadBIOSPackagd.ps1 and the Invoke-LenovoBIOSUpdate.ps1 PowerShell scripts.

      • Hi Keith,

        What version of the Invoke-CMDownloadBIOSPackage script are you running?. The current version is 1.0.6.


      • I changed the task sequence filter to “BIOS” instead of “BIOS Update” and the scripts are now running. I’ve verified that I’m on version 1.0.6 as well.

        I’m attempting to update the bios on a Lenovo machine but I keep getting this error “wflash2.exe is valid, but is for a machine type other than the current machine”. I believe the script should be using wflash2x64.exe instead of the 32 bit version.

        Looking over the Invoke-LenovoBIOSUpdate.ps1 it appears it’s calling flash.cmd instead of flash64.cmd. Debating on whether to edit the flash.cmd to point to wflash2x64.exe or to edit the Inovke-LenovoBIOSUpdate.ps1 to point to flash64.cmd

    • Also make sure that your filter is “BIOS” not “BIOS Update”, as listed in line 17.

      • Hi Jeremy,

        You can use either in fact. As long as the packages were created by the driver automation tool, their naming structure will be “BIOS Update – %MAKE% %MODEL%”, so using BIOS or BIOS Update as the starting wildcard / matching value is fine.


      • Interesting, as I received the same error as Keith when I tried to do the multiple word filter (BIOS Update) and it was solved by following the directions with the single word.

        It’s possible that the script has been updated to work with pilot updates and in doing so, it’s able to function with the multi-word filter and that Keith is on the same (or a similar) older version without that functionality.

        But I had experienced Keith’s same issue and did not report it as following directions strictly fixed it, making it a failure to read rather than a failure in the code. Our organization has not tried to deploy pilot updates, so I don’t know whether that would have worked or had the same issue.

      • Chalk up another person who had the same issue with specifying “BIOS Update” for the -Filter parameter.

        I was seeing an error “a positional parameter cannot be found that accepts argument ‘update'”

        I followed Keith’s suggestion and trimmed the filter down to just “BIOS”, and it then started working.

    • Hi Jonathan,

      It looks like the contents of that script was mixed up with another. I have just replaced it on GitHub.


  • Hi, I was using dynamic driver update Invoke-CMDownloadDriverPackage.ps1 for staging the driver package for my in-place upgrade from windows 7 to windows 10 1709 and am using “Upgrade Operating System Enterprise” option for the upgrade. Every time it is failing on “GetCMOSImageVersionForTaskSequence” action and it errors out “An error occured while calling ConfigMgr WebService to determine OS Image version. Error message”. Is there a limitation for 1709 OS since it has multiple index.?

  • So I added this to my In-place Upgrade TS for Windows 10, however it always fails when running the Invoke-CMApplyDriverPackage step. The error is:
    Get-Item : Cannot find drive. A drive with the name ‘C’ does not exist.
    At D:\_SMSTaskSequence\Packages\*packageNameRemoved*\Operating System Deployment\Drivers\Invoke-CMApplyDriverPackage.ps1:374 char:23

    I’ve made sure after upgrading the OS to reboot into WinPE. I’m also confused about why this caused the whole TS to fail as I have “Continue on Failure” checked for that step, but maybe I should apply that to the whole group instead of the individual step.

    So, what can I do about it not being able to find the C: drive? Or can I just not include this in this particular TS? Or because I am laying down a new OS, should I not be using the -OSMaintenance switch?

    Any insight would be appreciated!

  • How about a Powershell script that in the same matter that can compare and verify PC_BIOS hardware class, against specific model bios packages available, so one can find which models need to update their bios?

    all this info are in sccm, so it should be doable?

  • Hello Maurice,

    Your scripts are awesome and I am trying to get it working in my Lenovo environment. I noticed in my task sequence I am getting “PowerShell.exe does not exist at ‘X:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe’ when trying to run the Invoke-CMDownloadBIOSPackage.ps1 script.

    I am trying to replicate your task sequence by running the bios download and install steps right after the Apply Operating System step. I assume this is still in Windows PE? Any idea what my issue is here? I am a bit of a SCCM noob but your scripts and tools are making the upgrade to windows 10 for my fleet a great help! Thank you

    • Hey Chris,
      I think you are missing Powershell Features in WinPE
      You need to add that to your boot image. Right click on the boot image you use in that TS properties select Powershell Modules and Update Image to Dps.

      • Thanks for the reply, that sure was it! Now interestingly its able to find the bios in my package list, but I am getting a “You cannot call a method on a null-valued expression error” in my smsts log when running the download package command. Is it possible the %OSDBIOSPackage% variable is incorrect, or do i need to declare it before in my task sequence? I have seen it referenced a few different ways in the scripts here. Or is it possibly some other issue?

      • Hi Chris,

        The variable should be set to %OSDBIOSPackage01% when calling it in the vendor script.


    • Hi Chris – you’ll need to make sure you have the powershell components added to your boot wim that you’ve assigned to the task sequence.

  • Hi Maurice,

    i’m missing two things?
    1. Download BIOS Package
    2. Resume Bitlocker.

    Could i use “Enable Bitlocker” TS Step after the last reboot? or should i use Manage-Bde -Protectors -Enable C:?


    • Hi Ben,

      The download BIOS package is contained within the Invoke-CMDownloadBIOSPackage.ps1 script. In regards to Bitlocker, encryption will automatically resume post full OS restart.


  • First, a request. It was really nice back when the Invoke-CMDownloadDriverPackage.ps1 didn’t actually download the driver because then you could use it as an approved/included model detection. It would be great to have a script or parameter to replicate this functionality, either on the legacy Invoke-CMDownloadDriverPackage or the updated version, Invoke-CMApplyDriverPackage. For now, we’re sticking with the NickolajA v1.0.8 for its speed while keeping a task sequence prepped with the SCConfigMgr version for its eventual beneficial deployment.

    Second, some notes regarding shifts and changes between the NickolajA and SCConfigMgr scripts.
    1) The scripts moved from using the model name in the package title to the SKU in the description for its detection. If you have to add new drivers manually, set both the title as well as the description for your packages or they will fail to detect and apply.
    2) If using Windows Servicing\Invoke-CMDownloadDriverPackage v1.1.4: Remove the “Download Driver Package” task, and the “Apply Drivers via DISM” needs to be /Driver:%OSDDriverPackage01% not /Driver:%DriverPackage01%\ as in the step-by-step directions. If you leave the download task in, it will actually download whatever package is defined instead of your drivers. Also as noted above, remove the trailing \ as it’s now included in the variable and will fail when it tried to parse it again. Tested and this worked fine with those changes.
    3) Using the new Drivers\Invoke-CMApplyDriverPackage v1.1.5: Remove both the download and application tasks. It’s all self-contained now.

    Third, thanks. 🙂 Looking forward to when we get to see this working in production.

  • Are the driver packages referenced traditional ConfigMgr driver packages or standard packages used for drivers?

    As always, thank you for your contributions to the community.


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