Updating Dell BIOS with PowerShell (Updated)

Some of you may be familiar from my earlier article “Dell BIOS Updates with PowerShell” and hopefully you have gotten some good use out of it.  There have been a few comments on that article and over time I’ve also had some issues with that version of the script brought to my attention.

Some of these issues are:

  1. 1. Dell OptiPlex 745 updates don’t work because of the naming convention
  2. 2. Bios updates are overriding newer versions that come from the factory
  3. Still not updating to the latest available version due to supersedence rules for the BIOS updates (i.e. Needing A05, then A08, then finally A12).

So with that I fired up PowerGUI and started analyzing the entire flow of the script.  And more importantly kept in mind the overall process needed when multiple versions of a BIOS Update may be required (from A01 to Axx).  With this new script, I’ve introduced some new “features”

  1. Added a loop to parse multiple available BIOS update files
  2. Added a switch condition to allow for “oddly-named” BIOS file versions (read: OptiPlex 745)
  3. Added BIOS Release Date information (Universal Time Format) to check for BIOS “Patches” (i.e. P02 on Latitude E6410/E6510)
  4. Added OSD-Specific tasks (separate script)
  5. Embedded function for actually invoking the BIOS Update process itself with custom parameters.
  6. Removed dependency on Dell OMCI for BIOS identification (using Win32_BIOS now)

Dell_BIOSUpdates.zip

Using this with OSD/MDT

I’m not going to go over the script in its entirety here, however I will put out a few things specifically for using the “OSD” version of the script.  This additional script will connect to the Microsoft.SMS.TSEnvironment in order to interact with and create a new Task Sequence Variable.

When using this with OSD/MDT, you’ll want to have the script run multiple times in order to fully update the BIOS to the latest possible revision in the case that multiple executions are necessary.  Below I’ve documented the process that I have implemented to do just this.


Task Sequence Structure:

shot_662012_104220_amAs you can see here, we have multiple nested groups that will run the Dell BIOS Update script and enforce a reboot after the update has been staged.  One thing to point out here is that after the first run (which I’m calling as a regular Package/Program) is the word “Local”.  That’s right, the OSD script is copying the model-specific BIOS Updates locally (if there is more than one) so we don’t re-download the whole package again.

Update BIOS Group Condition:

shot_662012_105011_am

Update Dell BIOS Run Commandline:
powershell.exe -NoProfile -NonInteractive -File
“C:\Temp\Dell_BIOS_Updates\Invoke-DellBIOSUpdate-OSD.ps1”

Dell_BIOSUpdates.zip

Advertisements

Author: dhedges

I'm a Senior Client Systems Engineer specializing in OS Deployments and Automation using VBScript, PowerShell, MDT and SCCM. I enjoy working with technology and bending it to my will.

31 thoughts on “Updating Dell BIOS with PowerShell (Updated)”

  1. Hi dhedges,

    Does this script work independently of OSD/MDT? If no, how can I modify it to not use any of Microsoft’s or Dell’s (I do have OMCI on the clients though) deployment tools.

    I want to use it interactively (manually running the script) or for it to run as a part of my imaging process automatically (preferred method).

    Thanks

  2. This can be used outside of any deployment tools (manually executing the script on a system) without any issues. I have 2 scripts available for download, one that is geared towards deploying via OSD/MDT and the other for general use.

  3. Hi Dustin,

    I am trying to get the OSD version of the script to work with MDT 2012 Update 1 but I get an error. Everything seems to work just fine until the update file is to be started. The error I get is:

    Failed: Exception calling “Start” with “2” argument(s): “The system cannot find the file specified”

    The BIOS Update File is: Microsoft.PowerShell.Core\FileSystem::\\MDT02\ClientDeployment$\Applications\Dell BIOS Updates\OptiPlex 380\O380-A04.EXE

    I can confirm that the file exist.

    The whole log can be found here: http://upload.congrex.com/files/Dell_BIOS_Update.txt

    Thanks

    1. I have seen that error message a couple of times, and its typically when Dell changes the command line options for the BIOS files. I personally noticed this on the latest BIOS update release for the Precision T5500’s where they dropped the ‘-forceit’ command. Check the command-line options for that BIOS update specifically and see if you can run it manually. That is likely the cause of your issue.

      -Dustin
      Twitter: dhedges01

  4. I have done some troubleshooting and I have come to the conclusion that it isn’t the command-line options which cause the error. It is actually how $PWD.Path is stored in $ScriptFolder. The text “Microsoft.PowerShell.Core\FileSystem::” is being added to the UNC.

    I changed “$ScriptFolder = $PWD.Path” to “$ScriptFolder = (get-location).providerpath” and now it works.

    -Fredrik

  5. The download URL appears to be dead… Wanted to see what you have in your new revision (I know it’s been out a while but I just got a notification about it).

    Thanks again for the time you put into it… still not up on PowerShell myself yet.

    1. Make sure you are using the “Hard Drive” installers and it will work. otherwise you may need to add in some extra code to provide the right commandline arguments for that update.

      1. Well, i´m using the hard drive installer. After reboot i get the messeage “Attempting BIOS update…” but also error says “could not find the firmware image in memory”
        How can the extra code look like, and where to put it in the script? (í´m no powershell guru)

  6. I’ve tried the command ” powershell.exe -ExecutionPolicy Unrestricted -NoProfile -NonInteractive -File “Invoke-DellBIOSUpdate-OSD.ps1″ ” and ” cmd.exe /c powershell.exe -ExecutionPolicy Unrestricted -NoProfile -NonInteractive -File “Invoke-DellBIOSUpdate-OSD.ps1” “, but still, the logfile online conains the following:

    **********************
    Windows PowerShell Transcript Start
    Start time: 20140108120136
    Username : CON\SYSTEM
    Machine : PC1234 (Microsoft Windows NT 6.1.7601 Service Pack 1)
    **********************
    **********************
    Windows PowerShell Transcript End
    End time: 20140108120146
    **********************
    **********************
    Windows PowerShell Transcript Start
    Start time: 20140108120437
    Username : CON\SYSTEM
    Machine : PC1234 (Microsoft Windows NT 6.1.7601 Service Pack 1)
    **********************
    **********************
    Windows PowerShell Transcript End
    End time: 20140108120437
    **********************

    Why are the Write-Host comments not in the logfile?

  7. Hi, thanks for this nice script.
    I’m using an MDT media to install some machine and test Task sequence.
    In my Task, I have a folder ‘Dell Bios’, with 3 subfolders for each update pass.
    I’m having a probleme using your script; the PC always restart after after applying the first BIOS Update.
    The Dell Bios Folder is in ‘State Restore’ phase, is it correct ? Any other idea ?
    Thanks
    Fabrice

    1. Make sure that the Task Sequence is initiating the restart and it should work. I have’t personally tested Standalone MDT but I see no reason why it wouldn’t work.

  8. These is exactly what i have been looking for, but what about for Dell servers? They have difference hooks to run silently, /s is silent and /c to check if the update can be applied to the system. I was going to try and use this method to update the BIOS on some servers we deploy.

  9. is their a step by step? the instructions on here are not very clear on how to implement this with MDT, and of all the BIOS update via MDT this seems like the best option i can find.

  10. Dustin,

    I am attempting to use your script with SCCM 2012 R2 and MDT 2013 integrated task sequence, running WinPE 5 of course. I am getting “class not registered” in the smsts logs when the script is executed, and the script does not run. Thoughts? If I need to reach you offline, are you willing to assist?

  11. This is a great script!

    I do have one concern with the script where it can flash an older version of a bios than the system currently has installed. I’m worried about this causing potential corruption in cases where systems arrive with a newer bios then currently within the folder before there is an opportunity to update it.

    Is there a simple error check that could be swapped out to check if the version is less then opposed to not matching?

    1. Get rid of the “-forceit” switch. I actually have an even newer version of the script that doesn’t hard-code all the options. Makes it a bit more flexible since Dell has started changing the command line switches used in the newer BIOS models. I’ll update this post with the new script after I scrub the script.

      1. Hi Dustin – we are using your script to update a fleet of over 2000 laptops during image refresh. Thank you for all your work.

        Any idea when the update of your script is going to be made public?

  12. Hi,

    Looks like the download link isn’t working anymore. Do you have an updated one? Also, you mentioned you have an updated version of this script? I would love to get my hands on that.

    Brooks

  13. So I went ahead and took his script and was able to get it working by querying Dell’s site and then download directly from there. The nice part about this is that you don’t have to manage or maintain your own repository. It’s also “self elevating” so people can just right click and “run with powershell” without having to load an elevated powershell prompt first.

    #BIOS updater tool
    #Created by Brooks Peppin
    #Contributing content – https://blogs.msdn.microsoft.com/virtual_pc_guy/2010/09/23/a-self-elevating-powershell-script/, https://deploymentramblings.wordpress.com/2011/08/17/dell-bios-updates-with-powershell/
    #UPdated 6/27/16

    # Get the ID and security principal of the current user account
    $myWindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent()
    $myWindowsPrincipal = new-object System.Security.Principal.WindowsPrincipal($myWindowsID)

    # Get the security principal for the Administrator role
    $adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator

    # Check to see if we are currently running “as Administrator”
    if ($myWindowsPrincipal.IsInRole($adminRole))
    {
    # We are running “as Administrator” – so change the title and background color to indicate this
    $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + “(Elevated)”
    #$Host.UI.RawUI.BackgroundColor = “DarkBlue”
    clear-host
    }
    else
    {
    # We are not running “as Administrator” – so relaunch as administrator

    # Create a new process object that starts PowerShell
    $newProcess = new-object System.Diagnostics.ProcessStartInfo “PowerShell”;

    # Specify the current script path and name as a parameter
    $newProcess.Arguments = $myInvocation.MyCommand.Definition;

    # Indicate that the process should be elevated
    $newProcess.Verb = “runas”;

    # Start the new process
    [System.Diagnostics.Process]::Start($newProcess);

    # Exit from the current, unelevated, process
    exit
    }

    # Run your code that needs to be elevated here
    #Write-Host -NoNewLine “Press any key to continue…”
    #$null = $Host.UI.RawUI.ReadKey(“NoEcho,IncludeKeyDown”)
    $Model = $((Get-WmiObject -Class Win32_ComputerSystem).Model).Trim()
    $BIOSVersion = ((Get-WMIObject -Class Win32_BIOS).SMBIOSBIOSVersion)
    Write-Host “Your current Model is: $Model” -ForegroundColor white
    Write-Host “Your current BIOS version is: $BIOSVersion`n” -ForegroundColor White
    Write-Host “Getting list of available $model BIOSes from downloads.dell.com…”
    #$Model = “Precision Tower T5810″
    $model_short = $model.split(” “)
    $url = “http://downloads.dell.com/published/pages/”
    $main_page = Invoke-WebRequest $url -UseBasicParsing
    $path = @(($main_page.links | ?{ $_.outerHTML -match $model_short[$model_short.length – 1] }).href)
    switch ($Model) {
    “Precision Tower T5810” {
    $url = $url + $path[1]
    $model_page = Invoke-WebRequest $url -UseBasicParsing
    $BIOSUpdateFile = @(($model_page.Links | ?{ $_.href -match $model_short[$model_short.length – 1] + “A” }).href)
    }
    “Precision 5510” {
    $url = $url + $path[1]
    $model_page = Invoke-WebRequest $url -UseBasicParsing
    $BIOSUpdateFile = @(($model_page.Links | ?{ $_.href -match “Precision_5510” }).href)
    }
    default {
    $url = $url + $path[0]
    $model_page = Invoke-WebRequest $url -UseBasicParsing
    $BIOSUpdateFile = @(($model_page.Links | ?{ $_.href -match $model_short[$model_short.length – 1] + “A” }).href)
    }
    }
    #$BIOSUpdateFile
    Try
    {
    Do
    {

    write-Host “Please select BIOS you would like to update to:” -ForegroundColor Yellow
    for ($i = 0; $i -lt $BIOSUpdateFile.length; $i++)
    {
    write-host $i”:” $BIOSUpdateFile[$i].split(“/”)[3] -ForegroundColor Yellow
    }
    $var = read-host
    Write-Host “You have entered: “$BIOSUpdateFile[$var].split(“/”)[3]”`nIs this correct? (y/n)” -foreground “yellow”
    $BIOS = $BIOSUpdateFile[$var]
    $confirmation = Read-Host
    }
    while ($confirmation -ne ‘y’)
    $BIOS = $BIOSUpdateFile[$var].split(“/”)[3]
    $BIOSUpdateFile = $BIOSUpdateFile[$var]
    #echo “http://eus-repo.vmware.com/windows/BIOS/$model/$BIOS”
    Write-Host “Downloading $BIOS to $env:temp” -ForegroundColor Yellow
    If ((Test-Path $env:TEMP\$BIOS) -eq $true)
    {
    Write-Host “BIOS already downloaded. Skipping…” -ForegroundColor Yellow
    }
    else
    {
    #Write-Host “http://downloads.dell.com$BIOS”
    #Write-Host “http://downloads.dell.com$BIOSUpdateFile”
    Start-BitsTransfer “http://downloads.dell.com$BIOSUpdateFile” $env:TEMP\

    }
    $en = (Get-BitLockerVolume -MountPoint C:).ProtectionStatus
    if ($en = “On”) { Write-Host “Bitlocker is enabled. Suspending to perform BIOS flash.” -ForegroundColor Yellow }
    Suspend-BitLocker -MountPoint “C:” -RebootCount 1

    #Invoke-Expression $env:TEMP\$BIOS ” /quiet”
    $objStartInfo = New-Object System.Diagnostics.ProcessStartInfo
    $objStartInfo.FileName = “$env:TEMP\$BIOS”
    #$objStartInfo.Arguments = “-noreboot -nopause -forceit”
    #$objStartInfo.CreateNoWindow = $true
    [System.Diagnostics.Process]::Start($objStartInfo) | Out-Null
    }
    Catch
    {
    [Exception]
    Write-Output “Failed: $_”
    pause
    }

    1. This is a fantastic iteration of the script! In general, this should work for the majority if people. Those that require proxy authentication or have no access to external internet of course would have issues.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s