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.
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.
(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
