The Deployment Bunny

OS Deployment, Virtualization, Microsoft based Infrastructure…

  • Archives

  • Meta

Posts Tagged ‘BIOS’

OSD – BIOS upgrade during OS Deployment in MDT/ConfigMgr (v3)

Posted by Mikael Nystrom on July 20, 2016

This is the third version of the script solution; it is very simple. You detect make/model in any way you would like to, create a rule based on BIOS version, if the rule match, nothing happens, otherwise it runs any command you want. That said, you could use this for other task as well. Most common question is “does it work with any Make/Model”`No, there are some vendors that does not provide the ability to run a BIOS upgrade silently without reboot without control, that is, the darn thing reboots immediately and that usually breaks the Task Sequence. I have one thing for those vendors to say “Shame on you!”

here are older posts on the subject

https://deploymentbunny.com/2011/05/20/step-by-step-upgrading-bios-during-litetouch-deployment-for-dell-hewlett-packard-and-lenovo/

https://deploymentbunny.com/2013/12/16/step-by-step-upgrading-bios-during-litetouchzerotouch-deployment-for-dell-hewlett-packard-and-lenovo-v2/

Detect the Model

The detection in the script is actually whatever you want, it is just a “If-then”  here are two sample lines detection that you will find in the script

if($((Get-WmiObject Win32_ComputerSystem).model) -eq 'HP EliteBook 8560w'){}
if($ModelAlias -eq 'HP EliteBook 8460p'){}

Use the detection method for each model you like, very simple

Detect the BIOS version

This is also not that hard, here are 2 sample lines from the script

if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -ne '68SCF Ver. F.63'){}
if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -ne '786G1 v01.27'){}

Store the upgrade files

The upgrade files are stored with the model name, like this:

image

The Silent Command

You also need to figure out the command, not really hard, download the bios upgrade, read how to run it from a command line, update the script and you are done, here is a sample of one of those sections.

$Exe = 'hpqflash.exe'
$Location = "$SCRIPTDIR\Source\HP EliteBook 8460p"
$Executable = $Location + "\" + $exe
Set-Location -Path $Location
Invoke-Exe -Executable "$Executable" -Arguments "/s /f 68SCE.CAB" –Verbose

Run the script

in MDT you can import the folder with the script as a application and set this as the command line:

PowerShell.exe -ExecutionPolicy Bypass -File Install-BIOSUpgrade.ps1

In ConfigMgr you can import this as a Package and then run the command line the same way

It is also possible to run this outside of a task sequence if you like, it works as a stand alone script, however, you cannot use the integration with MDT of course.

If you want it is possible to add a custom property in customsettings.ini, something like “NeedReboot”, then you can add the following to happen if the BIOS has been upgraded

$tsenv.Value(“NeedReboot”) = “YES”

If you then in the step after this, set a condition on a reboot step, well then it will reboot when needed, otherwise not, you can read about that in one of my old postings here

https://deploymentbunny.com/2013/12/16/step-by-step-upgrading-bios-during-litetouchzerotouch-deployment-for-dell-hewlett-packard-and-lenovo-v2/

The result

BiosUpgradeResult
It was needed.

BiosUpgradeResultNotNeeded
It was not needed.

The Script


Function Import-SMSTSENV{
    try
    {
        $tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
        Write-Output "$ScriptName - tsenv is $tsenv "
        $MDTIntegration = "YES"
        
        #$tsenv.GetVariables() | % { Write-Output "$ScriptName - $_ = $($tsenv.Value($_))" }
    }
    catch
    {
        Write-Output "$ScriptName - Unable to load Microsoft.SMS.TSEnvironment"
        Write-Output "$ScriptName - Running in standalonemode"
        $MDTIntegration = "NO"
    }
    Finally
    {
    if ($MDTIntegration -eq "YES"){
        $Logpath = $tsenv.Value("LogPath")
        $LogFile = $Logpath + "\" + "$ScriptName.log"

    }
    Else{
        $Logpath = $env:TEMP
        $LogFile = $Logpath + "\" + "$ScriptName.log"
    }
    }
}
Function Start-Logging{
    start-transcript -path $LogFile -Force
}
Function Stop-Logging{
    Stop-Transcript
}
Function Invoke-Exe{
    [CmdletBinding(SupportsShouldProcess=$true)]
 
    param(
        [parameter(mandatory=$true,position=0)]
        [ValidateNotNullOrEmpty()]
        [string]
        $Executable,
 
        [parameter(mandatory=$false,position=1)]
        [string]
        $Arguments
    )
 
    if($Arguments -eq "")
    {
        Write-Verbose "Running $ReturnFromEXE = Start-Process -FilePath $Executable -ArgumentList $Arguments -NoNewWindow -Wait -Passthru"
        $ReturnFromEXE = Start-Process -FilePath $Executable -NoNewWindow -Wait -Passthru
    }else{
        Write-Verbose "Running $ReturnFromEXE = Start-Process -FilePath $Executable -ArgumentList $Arguments -NoNewWindow -Wait -Passthru"
        $ReturnFromEXE = Start-Process -FilePath $Executable -ArgumentList $Arguments -NoNewWindow -Wait -Passthru
    }
    Write-Verbose "Returncode is $($ReturnFromEXE.ExitCode)"
    Return $ReturnFromEXE.ExitCode
}

# Set vars
$SCRIPTDIR = split-path -parent $MyInvocation.MyCommand.Path
$SCRIPTNAME = split-path -leaf $MyInvocation.MyCommand.Path
$SOURCEROOT = "$SCRIPTDIR\Source"
$SettingsFile = $SCRIPTDIR + "\" + $SettingsName
$LANG = (Get-Culture).Name
$OSV = $Null
$ARCHITECTURE = $env:PROCESSOR_ARCHITECTURE

#Try to Import SMSTSEnv
. Import-SMSTSENV

# Set more vars
$Make = $tsenv.Value("Make")
$Model = $tsenv.Value("Model")
$ModelAlias = $tsenv.Value("ModelAlias")
$MakeAlias = $tsenv.Value("MakeAlias")

#Start Transcript Logging
. Start-Logging

#Output base info
Write-Output ""
Write-Output "$ScriptName - ScriptDir: $ScriptDir"
Write-Output "$ScriptName - SourceRoot: $SOURCEROOT"
Write-Output "$ScriptName - ScriptName: $ScriptName"
Write-Output "$ScriptName - Current Culture: $LANG"
Write-Output "$ScriptName - Integration with MDT(LTI/ZTI): $MDTIntegration"
Write-Output "$ScriptName - Log: $LogFile"
Write-Output "$ScriptName - Model (win32_computersystem): $((Get-WmiObject Win32_ComputerSystem).model)"
Write-Output "$ScriptName - Name (Win32_ComputerSystemProduct): $((Get-WmiObject Win32_ComputerSystemProduct).Name)"
Write-Output "$ScriptName - Version (Win32_ComputerSystemProduct): $((Get-WmiObject Win32_ComputerSystemProduct).Version)"
Write-Output "$ScriptName - Model (from TSENV): $Model"
Write-Output "$ScriptName - ModelAlias (from TSENV): $ModelAlias"

#Check Model
if($((Get-WmiObject Win32_ComputerSystem).model) -eq 'HP EliteBook 8560w'){
    Write-Output "Model is $((Get-WmiObject Win32_ComputerSystem).model)"
    Write-Output "Checking BIOS Version"
    Write-Output "Version is $((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion)"
    if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -ne '68SVD Ver. F.50'){
        Write-Output "Needs upgrade"
        $Exe = 'hpqflash.exe'
        $Location = "$SCRIPTDIR\Source\HP EliteBook 8560w"
        $Executable = $Location + "\" + $exe
        Set-Location -Path $Location
        Invoke-Exe -Executable "$Executable" -Arguments "/s /p LCadmin1.bin" -Verbose
    }
    else
    {
        Write-Output "No Need to upgrade"
    }
}
if($((Get-WmiObject Win32_ComputerSystem).model) -eq 'HP ProBook 6570b'){
    Write-Output "Model is $((Get-WmiObject Win32_ComputerSystem).model)"
    Write-Output "Checking BIOS Version"
    Write-Output "Version is $((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion)"
    if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -Like '*ICE*'){
        if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -ne '68ICE Ver. F.62'){
            Write-Output "Needs upgrade"
            $Exe = 'hpqflash.exe'
            $Location = "$SCRIPTDIR\Source\HP ProBook 6570b"
            $Executable = $Location + "\" + $exe
            Set-Location -Path $Location
            Invoke-Exe -Executable "$Executable" -Arguments "/s /f 68ICE.cab" -Verbose
        }
        else
        {
            Write-Output "No Need to upgrade"
        }
    }
    if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -Like '*ICF*'){
        if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -ne '68ICF Ver. F.62'){
            Write-Output "Needs upgrade"
            $Exe = 'hpqflash.exe'
            $Location = "$SCRIPTDIR\Source\HP ProBook 6570b"
            $Executable = $Location + "\" + $exe
            Set-Location -Path $Location
            Invoke-Exe -Executable "$Executable" -Arguments "/s /f 68ICF.cab" -Verbose
        }
        else
        {
            Write-Output "No Need to upgrade"
        }
    }
}
if($ModelAlias -eq 'HP EliteBook 8460p'){
    Write-Output "Model is $((Get-WmiObject Win32_ComputerSystem).model)"
    Write-Output "Checking BIOS Version"
    Write-Output "Version is $((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion)"
    if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -Like '*SCF*'){
        if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -ne '68SCF Ver. F.63'){
            Write-Output "Needs upgrade"
            $Exe = 'hpqflash.exe'
            $Location = "$SCRIPTDIR\Source\HP EliteBook 8460p"
            $Executable = $Location + "\" + $exe
            Set-Location -Path $Location
            Invoke-Exe -Executable "$Executable" -Arguments "/s /f 68SCF.CAB" -Verbose
            }
        else
            {
            Write-Output "No Need to upgrade"
        }
    }
    if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -Like '*SCE*'){
        if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -ne '68SCE Ver. F.63'){
            Write-Output "Needs upgrade"
            $Exe = 'hpqflash.exe'
            $Location = "$SCRIPTDIR\Source\HP EliteBook 8460p"
            $Executable = $Location + "\" + $exe
            Set-Location -Path $Location
            Invoke-Exe -Executable "$Executable" -Arguments "/s /f 68SCE.CAB" -Verbose
            }
        else
            {
            Write-Output "No Need to upgrade"
        }
    }
}
if($((Get-WmiObject Win32_ComputerSystem).model) -eq 'HP Compaq dc7900 Small Form Factor'){
    Write-Output "Model is $((Get-WmiObject Win32_ComputerSystem).model)"
    Write-Output "Checking BIOS Version"
    Write-Output "Version is $((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion)"
    if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -ne '786G1 v01.27'){
        Write-Output "Needs upgrade"
        $Exe = 'hpqflash.exe'
        $Location = "$SCRIPTDIR\Source\HP Compaq dc7900 Small Form Factor\HPQFlash"
        $Executable = $Location + "\" + $exe
        $SourceFile = $Location + "\" + "Password01.bin"
        $Destination = $env:TEMP
        $DestinationFile = $Destination + "\" + "Password01.bin"
        Copy-Item -Path $SourceFile -Destination $DestinationFile -Force -Verbose 
        Set-Location -Path $Location
        Invoke-Exe -Executable $Executable -Arguments "/s /p $DestinationFile"
    }
    else
    {
        Write-Output "No Need to upgrade"
    }
}

#Stop Logging
. Stop-Logging


/mike

Posted in BIOS, ConfigMgr, MDT, OS Deployment, OSD, PowerShell | Tagged: , , , , , | 5 Comments »

PowerShell is King – Read HP Bios Sensor data from WMI

Posted by Mikael Nystrom on March 16, 2016

I was bored in my hotel room and I ended up browsing WMI, found one cool/fun thing. I have a EliteBook 8570w and it turns out that HP uses WMI to store data and that makes it possible to read the data using PowerShell of course. Here is how:

Read HP Bios Sensor data from WMI using PowerShell

image

So, here is the actual code for you to copy:


#Read HP Bios Sensor data from WMI using PowerShell
$BIOSSensor = Get-WmiObject -Class HP_BIOSSensor -Namespace root\hp\instrumentedbios
$BIOSSensor | Select-Object Name,CurrentState,CurrentReading,Description

/Mike

Posted in BIOS, HP, PowerShell | Tagged: , , | Leave a Comment »

Working in the Datacenter – HP BIOS Cmdlets for Windows PowerShell (x64)

Posted by Mikael Nystrom on March 6, 2016

For customers running HP ProLiant servers in the datacenter (many of my customers do) it is now possible to modify the BIOS settings using PowerShell much easier then it used to be. The reason is that HP have released a PowerShell module that makes it possible to modify many of the settings, it actually also works remotely and even in WinPE. So, after it has been installed on a computer and you open up PowerShell and type Get-Help BIOS, you will get this:

image

Download from:

image

The little trick

It seems to be some confusion on how these CmdLets work, but it is very simple. The first command you need to execute is the Connect- CmdLet and that also applies when you run the command on the localhost and a connection does require name and password, this part actually sucks. it would have been so much smarter of HP to accept that commands that are executed locally did not ask for credentials, but that is how it works right now.

The Cool thing

It is possible to connect to multiple servers at the same time and then all commands will be executed in parallel

Connect to the BIOS

$ComputerName = "SRV01"
$UserName = "Administrator"
$Password = "P@ssw0rd"
$Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList "$COMPUTERNAME\$UserName", ($Password | ConvertTo-SecureString -AsPlainText -Force)
$Con = Connect-HPBIOS -IP $env:COMPUTERNAME -Credential $Credentials -ErrorAction Stop

Configure for Tree Hugging Mode

Set-HPBIOSPowerProfile -Profile Minimum_Power -Connection $Con
Set-HPBIOSPowerRegulator -Regulator Dynamic_Power_Savings -Connection $Con
Write-Output "$ScriptName - HP PowerProfile is set to $((Get-HPBIOSPowerProfile -Connection $Con).HPPowerProfile)"
Write-Output "$ScriptName - HP PowerRegulator is set to $((Get-HPBIOSPowerRegulator -Connection $Con).HPPowerRegulator)"

Configure for High Performance

Set-HPBIOSPowerProfile -Profile Maximum_Performance -Connection $Con
Set-HPBIOSPowerRegulator -Regulator Static_High_Performance -Connection $Con
Write-Output "$ScriptName - HP PowerProfile is set to $((Get-HPBIOSPowerProfile -Connection $Con).HPPowerProfile)"
Write-Output "$ScriptName - HP PowerRegulator is set to $((Get-HPBIOSPowerRegulator -Connection $Con).HPPowerRegulator)"

/mike

Posted in BIOS, HP, PowerShell | Tagged: , , | Leave a Comment »

Nice to Know–Getting Make and Model using CMD or PowerShell

Posted by Mikael Nystrom on December 19, 2013

Trust me, this is not a new thing, rather I get the question every time on a session (before or after) or when working on a customer site, how can I extract the Make and Model from the machine? So, as long as people are asking me, I think I should answer, right? :-)

Make and Model is commonly used in deployment solutions to figure out what drivers that needs to download to each machine during install. It is a part of the SMBBios information and can be accessed using WMI, in WMIC it is called Name and Vendor and in PowerShell it is called Manufacturer and Model. Now, lets take a look.

The Old WMI Method:

Execute wmic csproduct get name,vendor from a CMD prompt.

image

The New POSH Method:

Execute Get-WmiObject Win32_ComputerSystem | Select Model,Manufacturer from a PowerShell prompt.

image

/mike

Posted in Deployment, Drivers, MDT, PowerShell, SCCM, WMI | Tagged: , , , | 4 Comments »

Step-by-Step: Upgrading BIOS during LiteTouch Deployment, for Dell, Hewlett-Packard and Lenovo

Posted by Mikael Nystrom on May 20, 2011

Ok, so here is the short( not really sure this is going to be short by the way, well nothing is perfect) story, once again a customer (Thank you Bill for letting me test fun stuff in your environment!) asked me for a feature that I have done multiple times before, so the task was easy, just upgrade the BIOS when we deploy the machine, so I told them that
–Hey, this is the way to do it and the reply was.
–Sorry, It cannot be done as far as we know, since we have Lenovo and Lenovo does not allow you to run the BIOS firmware update in WinPE.
So it was time to start some thinking. We need to figure out how to create a solid solution and we to do an “all-night-long”. I did not just wanted to fix this customers issue, I want some kind of universal solution that will work on any hardware, client, type, vendor and so on. So I fired up my idea-engine and bang, there it was. I had a plan and a solution that would work, should only take a couple of minutes, kind of. At least that was the idea
(Just a quick note: I did not have the capability to test the Dell part of the script since I don’t have a Dell computer (For some reason most vendors are very polite and give me things to play with, but Dell obviously have an other agenda and I cannot afford to buy a Dell computer just to be able to write blog posts. Anyone has a used Dell that you are willing to give away for scientific experiments by the way? However, it should work, if it doesn’t, ping me)

Here is what we need:

  • It should work with any vendor in the same way
  • It should work with both servers and clients
  • It should do some serious logging
  • I should be able reuse some part of the code in other scenarios
  • It should work in WinPE

…Six hours later, Non-Stop “NCIS” at the hotel room, numerous reboots and massive amount of Coke and the solution was done and here is how it works.

We need information to make decisions!

We really need some variables to work with and it would be possible to use just one simple script to solve the problem, but then I started to think a bit, and.. It would be nice to do this  just a bit “Michael Niehaus / Keith Garner style”.

That way I could use these variables for other purposes then just this and I would in the long run have a nice UserExit Script that will collect all kinds of variables to make the deployment even more dynamically then it already is (Why?, Because I can of course…). Now it would be nice if all vendors use the same location in WMI to store information for the same thing, but that’s not going to happen, trust me, the British Empire will shift over to driving on the right side of the road and the US will start using the metric system before that happens, not very likely in other words. So we need to collect the following so that we later on can use BIOS information to determine what version we have and if it should be upgraded or not

  • From WIN32_BIOS we need SMBIOSBIOSVersion (this will be captured as SMBIOSBIOSVersion)
  • From WIN32_BIOS we need Version (this will be captured as BIOSVersion)
  • From Win32_ComputerSystemProduct we need Version (this will be captured as ProductVersion)

This way, we can use different ´properties and variables for different systems and that is pretty nice.

How will we use the different variables?

Well, by combing them differently we will be able to use them in different combinations to get what we need, here is how we will use them

  • Dell = SMBIOSBIOSVersion + Make + Model
  • Hewlett-Packard = BIOSVersion + Make + Model
  • LENOVO = SMBIOSBIOSVersion + Make + ProductVersion

Now, we can use these properties for this purpose, but you can also use these for other purposes, like driver handling, rules for applications and much more. There is also possible to combine this with the ModelAlias userexit script if you feel for it.

Using a user exit script is the solution to get this data

A user exit script is just a simple piece of VB script that runs as a part of the gather process when MDT reads the customsettings.ini file. So we need to create the ZTITheUserExit.vbs script and put that in the Scripts folder and then we need to update the CustomSettings.ini file so that it is used. You can put the execution of the user exit script basically anywhere in the priority, but I prefer to have a separate section called [Init] where I run everything instead of using default, since default in a production environment seems to be ending up as the last priority, time to stop writing and show you how it should look like:

[Settings]
Priority=Init, Default
Properties=BIOSVersion, SMBIOSBIOSVersion, ProductVersion

[Init]
SMBIOSBIOSVersion=#SetSMBIOSBIOSVersion()#
BIOSVersion=#SetBIOSVersion()#
ProductVersion=#SetProductVersion()#
UserExit=ZTITheUserExit.vbs

[Default]
OSInstall=Y

As you can see, the first thing that will happen when MDT starts reading the customsettings.ini file it finds the section init and it the jumps to that section in the file where it will discover that it needs to run ZTITheUserExit.vbs and that it will be three functions in the script that should return the values into BIOSVersion, SMBBIOSBIOSVersion and ProductVersion. After this has been executed you can now use for example  %BIOSVersion% in the same way as other properties such as %Make%, %Model% if you like. My guess right now is that you now would like to see the script, right? So, here it is, just copy the content and save as ZTITheUserExit.vbs in the scripts folder

ZTITheUserExit.vbs


Function UserExit(sType, sWhen, sDetail, bSkip)
    oLogging.CreateEntry “UserExit: Running Script: ” & sType & ” ” & sWhen & ” ” & sDetail, LogTypeInfo
    UserExit = Success
End Function

Function SetSMBIOSBIOSVersion()
    oLogging.CreateEntry “UserExit: Running Function SetSMBIOSBIOSVersion : ” & sType & ” ” & sWhen & ” ” & sDetail, LogTypeInfo
    Dim objWMI
    Dim objResults
    Dim objInstance
    Dim SMBIOSBIOSVersion
   
    Set objWMI = GetObject(“winmgmts:”)
    Set objResults = objWMI.ExecQuery(“SELECT * FROM Win32_BIOS”)
        If Err then
        oLogging.CreateEntry “Error querying Win32_BIOS: ” & Err.Description & ” (” & Err.Number & “)”, LogTypeError
    Else
        For each objInstance in objResults
            If Not IsNull(objInstance.SMBIOSBIOSVersion) Then
                    SMBIOSBIOSVersion = Trim(objInstance.SMBIOSBIOSVersion)
            End If
        Next
    End If
    SetSMBIOSBIOSVersion = SMBIOSBIOSVersion
    oLogging.CreateEntry “UserExit: Result: ” & SetSMBIOSBIOSVersion, LogTypeInfo
End Function

Function SetBIOSVersion()
    oLogging.CreateEntry “UserExit: Running Function SetBIOSVersion : ” & sType & ” ” & sWhen & ” ” & sDetail, LogTypeInfo
    Dim objWMI
    Dim objResults
    Dim objInstance
    Dim BIOSVersion
   
    Set objWMI = GetObject(“winmgmts:”)
    Set objResults = objWMI.ExecQuery(“SELECT * FROM Win32_BIOS”)
        If Err then
        oLogging.CreateEntry “Error querying Win32_BIOS: ” & Err.Description & ” (” & Err.Number & “)”, LogTypeError
    Else
        For each objInstance in objResults
            If Not IsNull(objInstance.Version) Then
                    BIOSVersion = Trim(objInstance.Version)
            End If
        Next
    End If
    SetBIOSVersion = BIOSVersion
    oLogging.CreateEntry “UserExit: Result: ” & SetBIOSVersion, LogTypeInfo
End Function

Function SetProductVersion()
    oLogging.CreateEntry “UserExit: Running Function SetProductVersion : ” & sType & ” ” & sWhen & ” ” & sDetail, LogTypeInfo
    Dim objWMI
    Dim objResults
    Dim objInstance
    Dim ProductVersion
   
    Set objWMI = GetObject(“winmgmts:”)
    Set objResults = objWMI.ExecQuery(“SELECT * FROM Win32_ComputerSystemProduct”)
        If Err then
        oLogging.CreateEntry “Error querying Win32_BIOS: ” & Err.Description & ” (” & Err.Number & “)”, LogTypeError
    Else
        For each objInstance in objResults
            If Not IsNull(objInstance.Version) Then
                    ProductVersion = Trim(objInstance.Version)
            End If
        Next
    End If
    SetProductVersion = ProductVersion
    oLogging.CreateEntry “UserExit: Result: ” & SetProductVersion, LogTypeInfo
End Function


If we run this script as a part of ZTIgather you should get something similar. So lets just look at the output that the userexit script will generate so that you have some kind of reference:

Determining the INI file to use.
Using COMMAND LINE ARG: Ini file = ..\Control\CustomSettings.ini
Finished determining the INI file to use.
Added new custom property MYCUSTOMPROPERTY
Added new custom property REFTYPE
Added new custom property BIOSVERSION
Added new custom property SMBIOSBIOSVERSION
Added new custom property PRODUCTVERSION
Using from [Settings]: Rule Priority = INIT, TASKSEQUENCEID, DEFAULT
—— Processing the [INIT] section ——
USEREXIT: Running Script: SECTION BEFORE INIT
User exit “C:\MDTLab\Scripts\ZTITheUserExit.vbs” called successfully, skip = False.
USEREXIT: Running Function SetBIOSVersion :
USEREXIT: Result: HPQOEM – f
Property BIOSVERSION is now = HPQOEM – f
Using from [INIT]: BIOSVERSION = HPQOEM – f
USEREXIT: Running Function SetSMBIOSBIOSVersion :
USEREXIT: Result: 68CVD Ver. F.0A
Property SMBIOSBIOSVERSION is now = 68CVD Ver. F.0A
Using from [INIT]: SMBIOSBIOSVERSION = 68CVD Ver. F.0A
USEREXIT: Running Function SetProductVersion :
USEREXIT: Result:
Property PRODUCTVERSION is now =
Using from [INIT]: PRODUCTVERSION =
USEREXIT: Running Script: SECTION AFTER INIT
User exit “C:\MDTLab\Scripts\ZTITheUserExit.vbs” called successfully, skip = False.

Now, lets take a quick look, these are the property values we will get in return on a HP Compaq 8540w (My portable datacenter)

Property BIOSVERSION is now = HPQOEM – f
Property SMBIOSBIOSVERSION is now = 68CVD Ver. F.0A
Property PRODUCTVERSION is now =

Seems to be working. Some explanations before we continue, one thing to notice is that the PRODUCTVERSION is blank and that BIOSVERSION does not give use anything useful, on HP Compaq it is the SMBIOSBIOSVERSION that is the real version of the BIOS, on LENOVO it is BIOSVERSION (You can use SMBIOSBIOSVERSION to, but it also contain “rubbish”. The only reason to use PRODUCTVERSION is that on Lenovo machines that will be the model name, not that nasty number that is extremely unique (so, on a LENOVO T410 it would give you “LENOVO T410” as result

Next step, create a script that can use these variables and then determine if the BIOS has the correct version or if it should be upgraded.

And that is a walk in the park, just create script file called ZTIBIOSUpgrade.wsf, save it the Scripts folder:
The format of the file is somewhat of a school example in the way that it contains extensive logging and contain routines for bailing out if things go bad (script has a certain habit of doing exactly that for some reason. It also have one really strange thing, it has a section for Microsoft Hardware which is Hyper-V, Virtual PC and Virtual Server and now, I’m not insane. I did create that section to verify that it works, since it is some much faster to do snapshots and flip back and forward without re-deploying a physical machine.


<job id=”ZTIBIOSUpgrade”>
<script language=”VBScript” src=”ZTIUtility.vbs”/>
<script language=”VBScript”>

‘//—————————————————————————-
‘// Solution: BIOS Upgrade
‘//
‘// The following values must be populated in the CustomSettings.ini
‘// using a userexit script (ZTITheUserExit.vbs
‘//         – BIOSVersion
‘//         – SMBIOSBIOSVersion
‘//         – ProductVersion
‘// To get these values you also need to execute a userexit script
‘// NOTE: The Section for “Microsoft” is only intended as a test/demo/play,
‘// since the BIOS cannot be updated from within the VM itself.
‘//
‘// Usage: cscript ZTIBIOSUpgrade.wsf[/debug:true]
‘// Version: 1.0 – 4 May 2011 – Mikael Nystrom
‘//
‘// This script is provided “AS IS” with no warranties, confers no rights and
‘// is not supported by the authors
‘//
‘//—————————————————————————-

‘//—————————————————————————-
‘// Global constant and variable declarations
‘//—————————————————————————-

‘//—————————————————————————-
‘//
‘// Global constant and variable declarations
‘//
‘//—————————————————————————-

Option Explicit

Dim iRetVal

‘//—————————————————————————-
‘// End declarations
‘//—————————————————————————-

‘//—————————————————————————-
‘// Main routine
‘//—————————————————————————-

‘On Error Resume Next
iRetVal = ZTIProcess
ProcessResults iRetVal
On Error Goto 0

‘//—————————————————————————
‘//
‘// Function: ZTIProcess()
‘//
‘// Input: None
‘//
‘// Return: Success – 0
‘// Failure – non-zero
‘//
‘// Purpose: Perform main ZTI processing
‘//
‘//—————————————————————————
Function ZTIProcess()

    Dim sMake
    Dim sModel
    Dim sSMBIOSBIOSVersion
    Dim sBIOSVersion
    Dim sExeToRun
    Dim sRefBiosVersion
    Dim sProduct
    Dim sProductVersion
    Dim sOSVersion
    Dim sDeployDrive
    Dim sDeployRoot
    Dim sExecuteCommand
   
    iRetVal = Success
    ZTIProcess = iRetval
   
    sMake = oEnvironment.Item(“Make”)
    sModel = oEnvironment.Item(“Model”)
    sSMBIOSBIOSVersion  = oEnvironment.Item(“SMBIOSBIOSVersion “)
    sBIOSVersion = oEnvironment.Item(“BIOSVersion”)
    sProduct = oEnvironment.Item(“Product”)
    sProductVersion = oEnvironment.Item(“ProductVersion”)
    sOSVersion = oEnvironment.Item(“OSVersion”)
    sDeployDrive = oEnvironment.Item(“DeployDrive”)
    sDeployRoot = oEnvironment.Item(“DeployRoot”)
   
   
    oLogging.CreateEntry “———————————————-“, LogTypeInfo
    oLogging.CreateEntry “Config-BIOSUpgrade – Runninng BIOS Upgrade:   “, LogTypeInfo
    oLogging.CreateEntry “Config-BIOSUpgrade – Make is:                 ” & sMake, LogTypeInfo
    oLogging.CreateEntry “Config-BIOSUpgrade – Model is:                ” & sModel, LogTypeInfo
    oLogging.CreateEntry “Config-BIOSUpgrade – Product is:              ” & sProduct, LogTypeInfo
    oLogging.CreateEntry “Config-BIOSUpgrade – ProductVersion is:       ” & sProductVersion, LogTypeInfo
    oLogging.CreateEntry “Config-BIOSUpgrade – SMBIOSBIOSVersion is:    ” & sSMBIOSBIOSVersion, LogTypeInfo
    oLogging.CreateEntry “Config-BIOSUpgrade – BIOSVersion is:          ” & sBIOSVersion, LogTypeInfo
    oLogging.CreateEntry “Config-BIOSUpgrade – OSVersion is:            ” & sOSVersion, LogTypeInfo
    oLogging.CreateEntry “Config-BIOSUpgrade – DeployDrive:             ” & sDeployDrive, LogTypeInfo
    oLogging.CreateEntry “Config-BIOSUpgrade – DeployRoot:              ” & sDeployRoot, LogTypeInfo
    oLogging.CreateEntry “———————————————-“, LogTypeInfo

    If sOSVersion = “WinPE” Then
    oLogging.CreateEntry “Config-BIOSUpgrade – Running WinPE…”, LogTypeInfo
    oLogging.CreateEntry “Config-BIOSUpgrade – Loading battery monitor…”, LogTypeInfo
    oUtility.RunWithHeartbeat(“drvload \Windows\inf\battery.inf”)
    oLogging.CreateEntry “Config-BIOSUpgrade – Loading battery monitor…Done”, LogTypeInfo’
    Else
    oLogging.CreateEntry “Config-BIOSUpgrade – Not running WinPE…”, LogTypeInfo
    oLogging.CreateEntry “Config-BIOSUpgrade – Not loading battery monitor …”, LogTypeInfo
    End If
   
    Select Case sMake
        Case “Dell Computer Corporation”, “Dell Inc.”, “Dell Computer Corp.”
            oLogging.CreateEntry “Config-BIOSUpgrade – ” & sMake & ” is selected”, LogTypeInfo
            oLogging.CreateEntry “Config-BIOSUpgrade – …searching for BIOS upgrades”, LogTypeInfo
            Select Case sModel
                Case “Latitude D420” : sExeToRun = “LatitudeD420.cmd ” : sRefBiosVersion=”A06″
                Case Else : sExeToRun = “NA”
            End Select
                If sExeToRun = “NA” Then
                    oLogging.CreateEntry “Config-BIOSUpgrade – No support for ” & sModel, LogTypeInfo
                Elseif sSMBIOSBIOSVersion = sRefBiosVersion Then
                    oLogging.CreateEntry “Config-BIOSUpgrade – No upgrade needed”, LogTypeInfo
                Else
                    oLogging.CreateEntry “Config-BIOSUpgrade – Correct version should be ” & sRefBiosVersion, LogTypeInfo
                    oLogging.CreateEntry “Config-BIOSUpgrade – Upgrading ” & sModel & ” from ” & sSMBIOSBIOSVersion & ” to ” & sRefBiosVersion, LogTypeInfo

                    sExecuteCommand = sDeployDrive & “\BIOSUpgrade\Dell\” & sExeToRun & sDeployDrive
                    oLogging.CreateEntry “Config-BIOSUpgrade – Command to execute ” & sExecuteCommand, LogTypeInfo

                    iRetVal = oUtility.RunWithHeartbeat(sExecuteCommand)
                    if (iRetVal = 0) or (iRetVal = 3010) then
                        ZTIProcess = Success
                    Else
                        ZTIProcess = Failure
                    End If
                End If
 
        Case “Microsoft Corporation”
            oLogging.CreateEntry “Config-BIOSUpgrade – ” & sMake & ” is selected”, LogTypeInfo
            oLogging.CreateEntry “Config-BIOSUpgrade – …searching for BIOS upgrades”, LogTypeInfo
            Select Case sModel
                Case “Virtual Machine” : sExeToRun = “VirtualMachine.cmd ” : sRefBiosVersion=”VRTUAL – 3000920″
                Case Else : sExeToRun = “NA”
            End Select
                If sExeToRun = “NA” Then
                    oLogging.CreateEntry “Config-BIOSUpgrade – No support for ” & sModel, LogTypeInfo
                Elseif sBIOSVersion = sRefBiosVersion Then
                    oLogging.CreateEntry “Config-BIOSUpgrade – No upgrade needed”, LogTypeInfo
                Else
                    oLogging.CreateEntry “Config-BIOSUpgrade – Correct version should be ” & sRefBiosVersion, LogTypeInfo
                    oLogging.CreateEntry “Config-BIOSUpgrade – Upgrading (Well, not really, but what the heck, lets try that…” & sModel & ” from ” & sSMBIOSBIOSVersion & ” to ” & sRefBiosVersion, LogTypeInfo

                    sExecuteCommand = sDeployDrive & “\BIOSUpgrade\Microsoft\” & sExeToRun & sDeployDrive
                    oLogging.CreateEntry “Config-BIOSUpgrade – Command to execute ” & sExecuteCommand, LogTypeInfo

                    iRetVal = oUtility.RunWithHeartbeat(sExecuteCommand)
                    if (iRetVal = 0) or (iRetVal = 3010) then
                        ZTIProcess = Success
                    Else
                        ZTIProcess = Failure
                    End If
                End If

        Case “IBM”, “LENOVO”
            oLogging.CreateEntry “Config-BIOSUpgrade – ” & sMake & ” is selected”, LogTypeInfo
            oLogging.CreateEntry “Config-BIOSUpgrade – …searching for BIOS upgrades”, LogTypeInfo
            Select Case sProductVersion
                Case “ThinkPad T410” : sExeToRun = “ThinkPadT410.cmd ” : sRefBiosVersion = “LENOVO – 1360”
                Case Else : sExeToRun = “NA”
            End Select
                If sExeToRun = “NA” Then
                    oLogging.CreateEntry “Config-BIOSUpgrade – No support for ” & sProductVersion, LogTypeInfo
                Elseif sBIOSVersion = sRefBiosVersion Then
                    oLogging.CreateEntry “Config-BIOSUpgrade – No upgrade needed”, LogTypeInfo
                Else
                    oLogging.CreateEntry “Config-BIOSUpgrade – Correct version for ” & sProductVersion & ” should be ” & sRefBiosVersion, LogTypeInfo
                    oLogging.CreateEntry “Config-BIOSUpgrade – Upgrading ” & sProductVersion & ” from ” & sBIOSVersion & ” to ” & sRefBiosVersion, LogTypeInfo

                    sExecuteCommand = sDeployDrive & “\BIOSUpgrade\Lenovo\” & sExeToRun & sDeployDrive
                    oLogging.CreateEntry “Config-BIOSUpgrade – Command to execute ” & sExecuteCommand, LogTypeInfo

                    iRetVal = oUtility.RunWithHeartbeat(sExecuteCommand)
                    if (iRetVal = 0) or (iRetVal = 1) or (iRetVal = 3010) then
                        ZTIProcess = Success
                    Else
                        ZTIProcess = Failure
                    End If
                End If
       
        Case “Hewlett-Packard”
            oLogging.CreateEntry “Config-BIOSUpgrade – ” & sMake & ” is selected”, LogTypeInfo
            oLogging.CreateEntry “Config-BIOSUpgrade – …searching for BIOS upgrades”, LogTypeInfo
            Select Case sModel
                Case “HP EliteBook 8540w” : sExeToRun = “HPEliteBook8540w.cmd ” : sRefBiosVersion = “68CVD Ver. F.0A”
                Case Else : sExeToRun = “NA”
            End Select
                If sExeToRun = “NA” Then
                    oLogging.CreateEntry “Config-BIOSUpgrade – No support for ” & sModel, LogTypeInfo
                Elseif sSMBIOSBIOSVersion = sRefBiosVersion Then
                    oLogging.CreateEntry “Config-BIOSUpgrade – No upgrade needed”, LogTypeInfo
                Else
                    oLogging.CreateEntry “Config-BIOSUpgrade – Correct version should be ” & sRefBiosVersion, LogTypeInfo
                    oLogging.CreateEntry “Config-BIOSUpgrade – Upgrading ” & sModel & ” from ” & sSMBIOSBIOSVersion & ” to ” & sRefBiosVersion, LogTypeInfo

                    sExecuteCommand = sDeployDrive & “\BIOSUpgrade\Hewlett-Packard\” & sExeToRun & sDeployDrive
                    oLogging.CreateEntry “Config-BIOSUpgrade – Command to execute ” & sExecuteCommand, LogTypeInfo

                    iRetVal = oUtility.RunWithHeartbeat(sExecuteCommand)
                    if (iRetVal = 0) or (iRetVal = 3010) then
                        ZTIProcess = Success
                    Else
                        ZTIProcess = Failure
                    End If
                End If
        Case Else
            oLogging.CreateEntry “Config-BIOSUpgrade – ” & sMake & ” Hey, that’s a brand I have never herd of, interesting…”, LogTypeInfo
    End Select
    oLogging.CreateEntry “———————————————-“, LogTypeInfo
End Function
</script>
</job>


So, now when we have the script created maybe I should try to explain what it actually is doing, I mean you might want to do some modification to it and then it is kind of nice to know where to poke around, So here is the short story.

  • First we make a bunch of Dim’s and the reason is simple and it is called “Option Explicit”. That is set globally in MDT and that means that it will blow up if you try to use a variable that is NOT declared (you might have seen a Error 500: Variable is undefined in MDT.
  • Next I dump all these variables to the bdd.log file, this is mainly need when you trouble shoot things and when you like to look at log files
  • Next up is, well here is the trick to make Lenovo machines run firmware updates in WinPE. The reason they does not work is because the utility looks at the state of power. They do that for one reason, to verify that the machine are running with the power cord connect to a power source and not running on battery (make sense). The secret source is to run this command:
  • oUtility.RunWithHeartbeat(“drvload \Windows\inf\battery.inf”)
  • The oUtility.RunWithHeartbeat is part of a function that gets loaded when we load up the library that is called ZTIUtlity.VBS which is a part of MDT and here is a tip for you, you should always base your script in MDT on a template that will leverage the use of ZTIUtility.vbs. I also set one condition here and that is to only load the driver when we are running WinPE, there is no point in loading it when we run the full-blown OS, it will be loaded in that case.
  • The rest is kind of easy, what will happen is that we will use the %Make% variable in MDT to see in what section we should continue, then when we we find the correct one we will get the %model% in all cases besides when it is a LENOVO, in that case we will use ProductVersion instead and if we find something that is a match when the compare the RefBios value with the version of the BIOS in the machine, it it is the same we just bail out and we are done, otherwise we will find the command to run. My first attempt of creating this had a small “flaw” and it took a couple of “angry-management seconds) to find out why and how to fix it, and the trick is that I need to run many of these firmware updates utilities on a drive letter, some of the work using UNC, but far from all and this must work in all situations, so I need a drive letter, but I cannot trust on MDT to always use Z:, so by using a built in variable called  DeployDrive to deliver that to me and that is why we will build the command to execute based on a bunch of variables
  • So, what does this means, well. In the scripts folder you will have to create a folder structure called BiosUpgrade and in the folder you then create Subfolders for each and every Vendor you have and those folders you the create one folder for each and every model and in those folders you put the firmware. It also means that you need to update this script whenever you have new versions of vendors, models and new versions of BIOS and firmware (well, I could have spent yet one night more to make it one step more dynamically, but hey I need to sleep sometime)

The Batch file…

Now as you can see in the script I have one batch file for each model,

(Looks like this in the VB)
Case “ThinkPad T410” : sExeToRun = “ThinkPadT410.cmd ” :

that batch file need a header to work, the header will make sure that you will be “in” the folder where the executable is located, that will not be needed every time, but most likely it will be needed most of the time and that batch file should look like this

%1
CD %0\..\
REM *** For testing only *** DIR > list.txt
REM Run your silent command here that will update the BIOS
REM Note: It MUST be silent and it should NOT restart the machine when it is done

Now, since you are (mots likely) a bit curios you will notice that the first line is a %1 and the reason behind that is kind of simple, %1 is the first parameter after the batch file it self, but hey, where did that variable come from??? Well, take a look at the line of execution, if you look really close you will see that we end that that line with a space in the end and the we use the DeployDrive variable and that will result in one thing. When the batch file runs it will first make sure it sets the working drive to the drive where the firmware updates are located and then we run the really old-school command

CD %0\..\

If %1 is the first parameter after the batch file, what the heck is the %0, well here is the fun thing. It’s the batch file name it self (you can test this by creating a batch file with just one line it it “Echo %0” and you will see that the result will be the name of the batch file name itself, the we just use \..\ which sets the working directory to the same location where the script is located and that is exactly what we need. Problem solved (using the MacGyver method)

The Folder Structure

Here is the folder structure that I have in the Scripts folder. In this folder structure I will store all the “Upgrades” plus the batch file. It should look like this to match the script.

image

So, in the scripts folder you will create Dell, Hewlett-Packard, LENOVO and so on, in the next level you create one folder for each model and that folder you store the upgrades,

Last step

The last thing you need to do is pretty easy. Open up your task sequence and add a Run Command that runs the ZTIBiosUpgrade.wsf. The run command should look like this:

cscript.exe “%SCRIPTROOT%\ZTIBiosUpgrade.wsf”

You can put the Run Command in the first section if you want to, there is were we did put it in the customer solution, something like this.

image

(Hey, if you ever wonder when I have time to write many of my postings it’s right now, somewhere over the Atlantic ocean flying at 10.000 feet or more with the headset filled with old-school rock, the flight attended just went pass me asking for more to drink and yes, she gave me a bunch of coke can’s. Thank you Swiss.)

A short note, this will of course work with servers too, just need to do some small adjustments

/Mike

Posted in Deployment, Windows 7, Windows Server 2008 R2 | Tagged: , , , , , , , | 54 Comments »