The Deployment Bunny

OS Deployment, Virtualization, Microsoft based Infrastructure…

  • Archives

  • Meta

Posts Tagged ‘Microsoft Deployment Toolkit’

OS Deployment using MDT – Inside the Validation Step

Posted by Mikael Nystrom on September 30, 2015

So, you are about to deploy Windows (client or server) using Microsoft Deployment Toolkit. Before you do that, maybe you should change the Validate Action, why? Because the default values does not make sense to everyone, that’s why.

The Validate Action

The Validate Action is a step in the Task Sequence that verifies that the machine you are about to install are good enough to be deployed. the defaults are a bit “wrong” for most customers IMHO.

The Defaults:

  • Check if the Machine has at least 768 MB of RAM
  • Check that the minimum CPU speed is at least 800 MHz
  • Don’t check disk space
  • Check that if there is a Operating System installed, it is a Client OS

Consider this:

Ensure minimum memory

768 MB is just wrong, a Windows 10 machine will need at least 2 GB (x86) or 4 GB (x64), so that means you should set them to 2048 or 4096, no, not at all. You need to calculate on the GPU RAM as well, since that is most likely “stolen” from RAM. So a 4 GB machine is 4096 MB – 512 MB (GPU Memory = 3584, set it to 3500. A 2 GB machine is 2048 MB – 512 MB = 1536 MB, set it to 1530.

Ensure minimum processor speed (MHz)

This is a bit tricky, depending on power saving features and the fact the machine is virtual, this could block OS install, even if it is correct. But, there is very few machines with 4GB of ram with a slower CPU then 800 MHz anyway, so checking memory. should be fine.

Check to ensure specified image size will fit (MB)

This check does not happen unless you check it, and maybe you should, if you are using Multicast the image will first be copied to the disk and then it will perform the install, in that case you actually “need” space, consider to change that.

Ensure current OS to be refreshed is

This checks the OS on the disk before installing/refresh, well it make sense in most cases, however, when you are playing and testing you could have a laptop that is used for both client and server OS test, in that case you need to uncheck.

image
Below you can see the default values.

image
Modified values.

image
Here is the result if the validation fails, due to insufficient memory.

Check BIOS

One other fun thing is the Check BIOS action, when I ask around I usually get something like – Well it checks the bios, you know. Not really, it is a script that runs to gather information a bout the bios, that is correct. It then uses that information against a XML file to see if it is a match, it there is a match, it will then block OS install. But the question is, what does it really check?

When opening the VBscript it seems that it checks, Manufacturer, Model and date of Bios

image

and if it does find a match it will tell you the following…

image

and that’s very nice to know, if you are deploying Windows Vista…

ZTIBIOSCheck.xml

Let us see what it looks for…

image

Ok, hmm, If you have BIOS version XX ROM BIOS Version 1.23, the Vendor is Wyssyg Computers and the Model is WYSIWYG Super Cool Computer 2007 with a BIOS date of 20060801000000.000000+000 it will then block the install. Not sure that has ever happened, but hey, nothing is impossible…

What you could do is to add computers to the XML file to block installation if you know that a certain model/bios will not work correctly.

/mike

Posted in MDT, OS Deployment | Tagged: , , | 4 Comments »

My Sessions at Microsoft Ignite 2015

Posted by Mikael Nystrom on May 1, 2015

Banner for Ignite 2015

Hands-on Windows 10 Enterprise Deployment

Want to know how to prepare for Windows 10, or how to upgrade from Windows 7, 8, or 8.1 to Windows 10? Maybe you want to know how to build, customize, and deploy your own Windows 10 image? In this pre-day session we explore all of those areas, with hands-on labs to ensure that you’ll be ready for Windows 10 in your organization.

Sunday, May 3rd  – 9:00 am to 5:00 pm

Troubleshooting Windows 10 Deployment: Top 10 Tips and Tricks

Need help with troubleshooting Windows deployment issues? Johan and Mikael share lessons learned around handling device drivers in the deployment process, common deployment issues and their workarounds, parsing log files, WinPE and PXE troubleshooting, UEFI deployments. As a foundation, Microsoft Deployment Toolkit and Microsoft System Center Configuration Manager will be used. You can expect a lot of live demos, tips, and tricks in this session.

Wednesday, May 6th – 10:45 am to 12:00 pm

Expert-Level Windows 10 Deployment

Join us for a live demo on how to build a Windows deployment solution, based on Microsoft System Center Configuration Manager. In the session we are taking OS Deployment in Microsoft Deployment Toolkit and System Center Configuration Manager to its outer limits. Deployment tips, tricks, and hard core debugging in a single session. You can expect a lot of live demos in this session.

Thursday, May 7 7th – 9:00 pm to 10:15 pm

Windows 10 Deployment: Ask the Experts

Still have questions about Windows deployment, even after all the other sessions this week? For this session, we gather as many experts as we can find for a roundtable Q&A session, with plenty of “official” and “real-world” answers for everyone, troubleshooting and implementation advice, and probably a fair number of opinions and “it depends” answers as well.

Thursday, May 7 7th – 3:15 pm to 10:15 pm

Book signing in the Bookstore

If you for any reason would like to have a book written by me signed, I’ll be there and I will happily sign it for you:

Wednesday, May 6th – 12:30 pm

Posted in ConfigMgr, Deployment, Event, Ignite, MDT | Tagged: , , , , , , , | Leave a Comment »

Adding Configurations to the Applications Pane using AppDescriptors

Posted by Mikael Nystrom on September 3, 2011

The Deploymentguys has invented some new stuff, just check this out, this is really cool. Smile

AppDescriptorDemo

Read the complete story: http://blogs.technet.com/b/deploymentguys/archive/2011/09/02/adding-configurations-to-the-applications-pane-using-appdescriptors.aspx?utm_medium=twitter&utm_source=twitterfeed

Download the ZIP: AppDescriptors.zip

/mike

Posted in Deployment | Tagged: | Leave a Comment »

Online Session – Microsoft Deployment Toolkit 2012

Posted by Mikael Nystrom on August 24, 2011

Yes, it is true, there will be a new version of MDT

This session will cover the changes and updates we have in MDT 2012 BETA 1. A session full of demos. We will spend time on both the new features but we will also spend some time one advanced/fun scenarios. That means customsettings.ini, userexists, scripts and some tips and trix.

The session will be in the Swedish language and on the 1 September 2011

Download link for MDT 2012 BETA 1 https://connect.microsoft.com/site14

Link to the event : https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032490004&Culture=sv-SE

/mike

Posted in Deployment | Tagged: , , , , | Leave a Comment »

Nice to know: – Blocking OS install on unsupported models in Microsoft Deployment Toolkit (MDT)

Posted by Mikael Nystrom on June 4, 2011

A customer asked me:

– Is it possible to block an attempt to upgrade, refresh or install the Operating System if that model is not “certified?

– Yes, we can set the OSinstall property to N based on model, that will block any attempt

– But that will block that model from running any Task Sequence? That is not what I want…

Well, that is correct, so I needed a way to block that particular model on that particular Task Sequence, so I  would like something a bit more sophisticated, something like this:

For task sequence “Windows 7 Enterprise x86 – Basic” the following models are supported and for the task sequence “Windows Server 2008 R2 – Basic” the following models are supported (or something like that)  and here is how you do it:

(This has been tested on MDT 2010, MDT2010 update 1 and MDT2012)

Create a new group in your task sequence

  • Open up your deployment workbench
  • Open your task sequence
  • Add a new group called “Certified Hardware”

Like this:

image

Setting condition on the group

  • Select the group Certified Hardware
  • Select Options for that group
  • Add the following condition:

Task sequence variable “Model not equals HP ProBook 5310m” (if that is the model that you support for this Task sequence)

Like this:

image

Adding the “blocker”

  • Select the group
  • Add a “Set Task Sequence Variable”
  • Task Sequence Variable = OSInstall
  • Value = N

Like this:

image

Adding script that will write in the log and display “why” the OS install failed

Without this step it will just display a “failed”, but maybe, just maybe you would like to have it a bit more sophisticated. So let us add a script

The script should go into the Scripts folder and you can download it from my SkyDrive http://cid-8563304f134ddcb6.office.live.com/self.aspx/BlogFiles/ZTIUnSupportedHardware.zip

  • Download it
  • Extract it
  • Save it in the scripts folder
  • Add a run command before the Set Task Sequence Variable
  • Use this command : cscript.exe “%SCRIPTROOT%\ZTIUnSupportedHardware.wsf”

It should look like this:

image_thumb[3]_thumb[1]

Let us take a look in the BDD.log file

Here is how it looks in BDD.log

image_thumb[7]_thumb[1]

Next step

With this in place you can prohibit installations of Domain Controllers on Laptops, Hyper-V servers on Virtual Machines and people trying to refresh a Machine from XP to XP even if you have NO device drivers for that model, my guess is that this will solve a couple of “Ops, sorry”

If you want to you can add scripts and other logic to this, things that automatically runs a scripts that will collect the hardware information to a log so that you then can figure out what drivers are needed or something like that, or you could add the “Send Email” script so it will send an email to you saying that some “schmuck” tried to do something bad. You could also add the userexit script for ModelAlias and use that. You could also add other conditions, like Firmware, certain kind of hardware and so on. It would be for example possible to run a Web Services that checks if this computer is correctly added into the asset management database or something like that.

Yes, you can also use CustomSettings.ini to perform similar

And here is a couple of samples of that:

Sample No:1 – Blocking on Model

Here is the “easy” way, the only downside with this one is that it will only block based on Model and that could be perfectly ok in many situations.

[Settings]
Priority=Model, Default
Properties=MyCustomProperty

[Default]
OSInstall=N

[HP ProBook 5310m]

OSInstall=Y

[Virtual Machine]
OSInstall=Y

Sample No:2 – Blocking on Model + Task Sequence:

In this sample we create one property and two priority blocks. If we run this WHEN the task Sequence is known (That means that you need to re-run the gather process with “process rules”, ZTIGather will set the model + Task Sequence ID in to the property Model_TS in the [Init] section, it will then process the [CertifiedHardware] section and the use the Subsection to continue to the section that matches the Model+Task Sequence ID, in this case since my machine is a VM running on Hyper-V it will be “Virtual Machine” and if the Task Sequence is W7X64 it will process the [Virtual Machine_W7X64] section and OSinstall property will be set to Y.

[Settings]
Priority=Init, CertifiedHardware, Default
Properties=MyCustomProperty, Model_TS

[Init]
Model_TS=%Model%_%TaskSequenceID%

[Default]
OSInstall=N

[CertifiedHardware]
SubSection=%Model_TS%

[Virtual Machine_W7X64]
OSInstall=Y

More tips…

You can of course block OS install temporary, during maintenance could be a valid scenario. A good friend (And fellow MVP) Maik Koster created a solution for that (I tricked him into it) and you can read a bit more about it here. http://myitforum.com/cs2/blogs/maikkoster/archive/2011/04/05/implementing-a-very-simple-maintenance-mode-in-mdt-litetouch.aspx

And here are some more discussions on how to pick the info from the Database: http://social.technet.microsoft.com/Forums/en-US/mdt/thread/412e54d9-549f-4828-9d5d-d41d14df77e8

/mike aka the Deployment Bunny

Posted in Deployment, Drivers, TechEd, Windows 7, Windows Server 2008 R2 | Tagged: , , | 2 Comments »

Modifying the Lite Touch Wizard in MDT 2010 – Sample 2

Posted by Mikael Nystrom on May 26, 2011

This is the second part of a story around the MDT Wizard and the Wizard editor and the saga continues, but this time it’s going to be a bit more tricky since we need to add information to the wizard that does not exist by default in MDT. Last post was easy in the way that we just created a new page in the wizard that displays existing environment information, now the game has changed and my customer wants to have some hardware information, something like this:

image

The reason of having this page is to be sure that the machine has the correct hardware configuration, things like correct BIOS version, memory, CPU configuration but also to see that it has the Mac address that we “assume” it have. Also, we want to know if the model alias user exit script works correct and sets the correct model alias since we use that as a part of the driver group.

Now, most of the values can be collected directly from using Make, Model, Memory, Product, Architecture, AssetTag, SerialNumber, UUID, MacAddress. But for the rest we need to get them into the MDT environment somehow and the somehow in this case spells “UserExit”

UserExit is a way to extend MDT by writing some custom code (yes, that will be provided, hang on…), execute it and return the value into a custom property that can be used in rules or showed in the wizard page.

A user exit script is basically a VBscript with one or more functions and you can have them in one big userexit script or many, it is easier to have just one since that will be a bit cleaner and easier to manage. What we need is to get the name of the CPU, Hard drive, number of physical CPU’s and logical CPU’s and last but not least SMBiosversion. Well, I missed one, we also need to get the ModelAlias, but that user exit is already created by the deployment guys, so we just grab that and use it

But first of all, lets create the new Wizard page and here is how

Modifying the Wizard

Download the MDT Wizard editor from http://mdtwizardeditor.codeplex.com/

Fire it up and open the “DeployWiz_Definition_ENU.xml”. It is in the scripts folder (Make a backup of the file first). Then you add a new Wizard pane like this:

image

And then you add this HTML code into that page:


<h1>System information</h1>
<span style=”width: 95%;”>
<table border=”1″ cellspacing=”1″ cellpadding=”1″ width=”650″>
<tbody>
<tr>
<td width=”110″ align=”right”><em>Vendor</em></td>
<td align=”left”><input style=”width: 220px” name=Make readonly></td>
<td width=”110″ align=”right”><em>Model</em></td>
<td align=”left”><input style=”width: 220px” name=Model readonly></td>
</tr>
<tr>
<td width=”110″ align=”right”><em>Product</em></td>
<td align=”left”><input style=”width: 220px” name=Product readonly></td>
<td width=”110″ align=”right”><em>Memory(in Mb)</em></td>
<td align=”left”><input style=”width: 220px” name=Memory readonly></td>
</tr>
<tr>
<td width=”110″ align=”right”><em>CPU (in GHz)</em></td>
<td align=”left”><input style=”width: 220px” name=processorspeed readonly></td>
<td width=”110″ align=”right”><em>No: CPU\Cores</em></td>
<td align=”left”><input style=”width: 108px” name=ComputerSystemNumberOfProcessors readonly>\<input style=”width:108px” name=ComputerSystemNumberOfLogicalProcessors readonly></td>
</tr>
<tr>
<td width=”110″ align=”right”><em>Harddisk Info</em></td>
<td align=”left”><input style=”width: 220px” name=DiskDriveCaptation readonly></td>
<td width=”110″ align=”right”><em>Capable Architecture</em></td>
<td align=”left”><input style=”width: 220px” name=”CapableArchitecture” readonly></td>
</tr>
<tr>
<td width=”110″ align=”right”><em>Model Alias</em></td>
<td align=”left”><input style=”width: 220px” name=MODELALIAS readonly></td>
<td width=”110″ align=”right”><em>SMBIOSVERSION</em></td>
<td align=”left”><input style=”width: 220px” name=SMBIOSVERSION readonly></td>
</tr>

</tbody>
</table>

<table border=”1″ cellspacing=”1″ cellpadding=”1″ width=”650″>
<tbody>
<tr>
<td width=”150″ align=”right”><em>CPU</em></td>
<td><input style=”width: 490px” name=CPUName readonly></td>
</tr>
<tr>
<tr>
<td width=”150″ align=”right”><em>Serial Number</em></td>
<td><input style=”width: 490px” name=Serialnumber readonly></td>
</tr>
<tr>
<td width=”150″ align=”right”><em>UUID</em></td>
<td><input style=”width: 490px” name=UUID readonly></td>
</tr>
<tr>
<td width=”150″ align=”right”><em>Mac Address</em></td>
<td><input style=”width: 490px” name=MacAddress001 readonly></td>
</tr>
<tr>
<td width=”150″ align=”right”><em>Assettag</em></td>
<td><input style=”width: 490px” name=Assettag readonly></td>
</tr>
</tbody>
</table>
</span>


You also need to a “condition” to the page so that you can turn it on or off based on rules and that should look like this:

image

To be sure that you get it correct, here is the code in plain text


Ucase(Property(“SkipHardwareInfo”)) <> “YES”


Modifying CustomSettings.ini

So, we are done with the Wizard, but if we run it now it will not really work, now it is time to modify CustomSettings.ini and that should look like this:

[Settings]
Priority=Init, ModelAliasInit, Default
Properties=MyCustomProperty, SkipHardwareInfo, ComputerSystemNumberOfProcessors, ComputerSystemNumberOfLogicalProcessors, ComputerSystemProductIdentifyingNumber, SMBIOSVersion, CPUName, DiskDriveCaptation, ModelAlias

[Init]
ComputerSystemNumberOfProcessors=#GetComputerSystemNumberOfProcessors()#
ComputerSystemNumberOfLogicalProcessors=#GetComputerSystemNumberOfLogicalProcessors()#
ComputerSystemProductIdentifyingNumber=#GetComputerSystemProductIdentifyingNumber()#
SMBIOSVersion=#GetBIOSSMBIOSVersion()#
CPUName=#GetCPUName()#
DiskDriveCaptation=#GetDiskDriveCaptation()#
UserExit=HardwareInfo.vbs

[ModelAliasInit]
ModelAlias=#SetModelAlias()#
UserExit=ModelAliasExit.vbs


Adding the scripts

We need two scripts, one called hardwareinfo.vbs and the other is ModelAlias.vbs, you can get ModelAlias from http://blogs.technet.com/b/deploymentguys/archive/2009/09/10/using-and-extending-model-aliases-for-hardware-specific-application-installation.aspx. The VBScript hardwareinfo.vbs however you will find here:


‘ //***************************************************************************
‘ // ***** Script Header *****
‘ //
‘ // Solution:  Custom Script for use with the Microsoft Deployment Toolkit
‘ // File:      hardwareinfo.vbs
‘ //
‘ // Purpose:   User exit script to get and set properties to be able to display the HardwareInfo Wizardpane.
‘ //
‘ // Usage:     Modify CustomSettings.ini similar to this:
‘ //        [Settings]
‘ //        Priority=Init, Default
‘ //        Properties=MyCustomProperty, SkipHardwareInfo, ComputerSystemNumberOfProcessors, ComputerSystemNumberOfLogicalProcessors, ComputerSystemProductIdentifyingNumber, SMBIOSVersion, CPUName, DiskDriveCaptation, ModelAlias
‘ //
‘ //        [Init]
‘ //        ComputerSystemNumberOfProcessors=#SetComputerSystemNumberOfProcessors()#
‘ //        ComputerSystemNumberOfLogicalProcessors=#SetComputerSystemNumberOfLogicalProcessors()#
‘ //        ComputerSystemProductIdentifyingNumber=#SetComputerSystemProductIdentifyingNumber()#
‘ //        SMBIOSVersion=#SetBIOSSMBIOSVersion()#
‘ //        CPUName=#GetCPUName()#
‘ //        DiskDriveCaptation=#GetDiskDriveCaptation()#
‘ //
‘ // Version:   1.0
‘ // Author: Mikael Nystrom –
http://deploymentbunny.com
‘ //***************************************************************************

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

Function SetComputerSystemNumberOfProcessors()
oLogging.CreateEntry “UserExit:HardwareInfo.vbs – Getting ComputerSystemNumberOfProcessors”, LogTypeInfo
Dim objWMI
Dim objResults
Dim objInstance
Dim NumberOfProcessors
Dim ComputerSystemNumberOfProcessors

    Set objWMI = GetObject(“winmgmts:”)
Set objResults = objWMI.InstancesOf(“Win32_ComputerSystem”)
For each objInstance in objResults
If Not IsNull(objInstance.NumberOfProcessors) Then
NumberOfProcessors = Trim(objInstance.NumberOfProcessors)
End If
Next
If NumberOfProcessors = “” Then
NumberOfProcessors = “UNKNOWN”
End If
SetComputerSystemNumberOfProcessors = NumberOfProcessors
End Function

Function SetComputerSystemNumberOfLogicalProcessors()
oLogging.CreateEntry “UserExit:HardwareInfo.vbs – Getting ComputerSystemNumberOfLogicalProcessors”, LogTypeInfo
Dim objWMI
Dim objResults
Dim objInstance
Dim NumberOfLogicalProcessors

Set objWMI = GetObject(“winmgmts:”)
Set objResults = objWMI.InstancesOf(“Win32_ComputerSystem”)
If Err then
oLogging.CreateEntry “Error querying Win32_ComputerSystem: ” & Err.Description & ” (” & Err.Number & “)”, LogTypeError
Else
For each objInstance in objResults
If Not IsNull(objInstance.NumberOfLogicalProcessors) Then
NumberOfLogicalProcessors = Trim(objInstance.NumberOfLogicalProcessors)
End If
Next
End If
SetComputerSystemNumberOfLogicalProcessors = NumberOfLogicalProcessors
End Function

Function SetCPUName()
oLogging.CreateEntry “UserExit:HardwareInfo.vbs – Getting CPUName”, LogTypeInfo
Dim objWMI
Dim objResults
Dim objInstance
Dim Name
Dim CPUName

Set objWMI = GetObject(“winmgmts:”)
Set objResults = objWMI.ExecQuery(“SELECT * FROM Win32_Processor”)
If Err then
oLogging.CreateEntry “Error querying FROM Win32_Processor: ” & Err.Description & ” (” & Err.Number & “)”, LogTypeError
Else
For each objInstance in objResults
If Not IsNull(objInstance.Name) Then
CPUName = Trim(objInstance.Name)
End If
Next
End If
SetCPUName = CPUName
End Function

Function SetBIOSSMBIOSVersion()
oLogging.CreateEntry “UserExit:HardwareInfo.vbs – Getting BIOSSMBIOSVersion”, 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_ComputerSystem: ” & 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
SetBIOSSMBIOSVersion = SMBIOSBIOSVersion
End Function

Function SetDiskDriveCaptation()
oLogging.CreateEntry “UserExit:HardwareInfo.vbs – Getting DiskDriveCaptation”, LogTypeInfo
Dim objWMI
Dim objResults
Dim objInstance
Dim Caption

Set objWMI = GetObject(“winmgmts:”)
Set objResults = objWMI.ExecQuery(“SELECT * FROM Win32_DiskDrive where mediatype like ‘Fixed%hard disk%'”)
If Err then
oLogging.CreateEntry “Error querying Win32_DiskDrive: ” & Err.Description & ” (” & Err.Number & “)”, LogTypeError
Else
For each objInstance in objResults
If Not IsNull(objInstance.Caption) Then
Caption = Trim(objInstance.Caption)
End If
Next
End If
SetDiskDriveCaptation = Caption
End Function

Function SetComputerSystemProductIdentifyingNumber()
oLogging.CreateEntry “UserExit:HardwareInfo.vbs – Getting ComputerSystemProductIdentifyingNumber”, LogTypeInfo
Dim objWMI
Dim objResults
Dim objInstance
Dim IdentifyingNumber
Dim ComputerSystemProductIdentifyingNumber
Set objWMI = GetObject(“winmgmts:”)
Set objResults = objWMI.InstancesOf(“Win32_ComputerSystemProduct”)
For each objInstance in objResults
If Not IsNull(objInstance.IdentifyingNumber) Then
IdentifyingNumber = Trim(objInstance.IdentifyingNumber)
End If
Next
If IdentifyingNumber = “” Then
IdentifyingNumber = “UNKNOWN”
End If
SetComputerSystemProductIdentifyingNumber = IdentifyingNumber
End Function


Wrapping up

So, now you have a new Wizard pane that will give you some more information from the computer before you install the machine and if you don’t like to see that page the only thing you need to do is to add SkipHardwareInfo=YES in Customsettings.ini

/mike

Posted in Deployment | Tagged: , , | 11 Comments »

Things you should know: – Undocumented Properties in MDT 2010 Update 1

Posted by Mikael Nystrom on May 22, 2011

Once again, at 33000 feet over the Atlantic Ocean on my way back from TechEd NA in Atlanta I started to think about all the different properties in MDT 2010 Update 1 that I use which are not really documented, trust me there are “some”. Some of them is, well, not really so useful, but some of them I really use and so should you. So this post is solely made for the purpose of giving you the same “relaxed” life that I have. Hmm, that did not really came out right I think, anyway, You know what I mean, right…

Now, since I not work on that team, I just happen to know them a bit. This is NOT any kind of official description and/or documentation, hopefully someone@microsoft.com will update he documentation sometime around this, especially when virtualization is getting to be more of the standard.

Virtualization Information:

We are deploying more and more virtualization stuff and in MDT 2010 Update 1 we have a bunch of them that you can use:

Property Can be Read Only Description
IsHypervisorRunning True/False Yes Detects if the Microsoft Hypervisor is running on the OS

Can be used when you need to detect if the Hyper-V role is installed and running. In that vase you know that this really is a Hyper-V server and then scripts to enable core parking should run

SupportsVT True/False Yes Returns True if the hardware supports Intel-VT or AMD-V and it is enabled in BIOS

If true you know that this machine should be able to run Virtual PC (and MED-V) otherwise not)

SupportsNX True/False Yes Returns True if the hardware supports No Execute BIT and it is enabled in BIOS

There could be applications that require this to be disabled or the opposite around, anyway, here is a way of detecting this

Supports64Bit True/False Yes Returns True if the hardware supports 64 Bit OS

Pretty easy, you could use this to pick the correct Task Sequence for the OS install

SupportsHyperVRole True/False Yes Returns True if the hardware supports Microsoft Hyper-V

Also easy, if True, well then you can enable the Hyper-V role, otherwise, you cannot. You could use this flip OS install switch to NO and that will prohibit the install of the OS you Hyper-V is something you really need.

IsVM True/False Yes Returns True if we are running in a VM.

This one is really great, if set to True, well the you are running a VM and most common setting I use for this is

DoNotCreateExtraPartition=YES, since there are NO reason to create the extra bit locker partition in a VM; It is the opposite around, it is a pain in the neck to have the 300 mb partition in the end since that will prohibit the possibilities to extend the virtual hard drive if needed without spending some manual labor of rearrange the BCD

Some others

There are some others that I use from time to time and here you have them

Property Can be Read Only Description
Debug True/False No Returns True if you are running in debug mode, You can also run all scripts with the switch /Debug:True to increase the logging

If you just read the value, you can create a separate section in the customsettings,ini file that will set other parameters differently if you run in debug mode, as one example you could specify SLShareDynamicLogging if this is set to True

OSCurrentVersion 6.1.7601 Yes Will return the version number of the Operating System that we currently run on.
OSCurrentBuild 7601 Yes Will return the Build number which is a subset of the operating system version
IsUEFI True/False Yes Returns True if the boot using UEFI instead of BIOS
OSSKU ENTERPRISE Yes Returns the SKU name from the OS, it is the same name you can see in the WIM file
TaskSequenceVersion 1.0 Yes Returns the value for the Task Sequence version number that you set in the Workbench

Could be used to detect what version you run of the Sequence, if it is running a certain number then certain settings should be made, otherwise not

TaskSequenceName Windows 7 x86 Image Yes Returns the value of the name of the Task Sequence

Most common use I have for this is to set _SMSTSOrgName=Deploying %TaskSequenceName% on %OSDComputer%

/mike

Posted in Deployment | Tagged: , , | 7 Comments »

Just for fun: – The MDT team has a humor

Posted by Mikael Nystrom on May 22, 2011

There is a step in the Task Sequence that checks bios, but most people never check what really happens behind the scenes. Well it checks the BIOS, right. But my best guess is that you did not get this one! 

Verifying WYSIWYGComputers BIOS

I know many vendors, but I have never come across this one “WYSIWYGComputers”, I mean I heard about ACME but this one…

But here is the important takeaway, as long as they have fun, they will keep on creating great stuff.

/mike

<?xml version=”1.0″ encoding=”Windows-1252″?>
<DATABASE xsi:schemaLocation=”urn:schemas.microsoft.com/appx/2006/07/Dbu Driver.xsd” xmlns=”urn:schemas.microsoft.com/appx/2006/07/Dbu” xmlns:dc=”http://purl.org/dc/elements/1.1/&#8221; xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221; MAX_HTMLHELPID=”110033″>
<DRIVER>
<HISTORY>
<DESCRIPTION>
Insert your description here. This field will be written to the log if a match is found.
</DESCRIPTION>
</HISTORY>
<LOOKUP NAME=” _BIOS_DESCRIPTION_HERE_ “>
<DATA NAME=”Computer Manufacturer” VALUETYPE=”string” VALUE=” _COMPUTER_MFG_HERE_ “/>
<DATA NAME=”Model” VALUETYPE=”string” VALUE=” _COMPUTER_MODEL_HERE_”/>
<DATA NAME=”Date” VALUETYPE=”string” VALUE=” _DATE_TIME_HERE_ “/>
</LOOKUP>
</DRIVER>
<DRIVER>
<HISTORY>
<DESCRIPTION>
The WYSIWYG Super Cool Computer 2007 has a bug in version 1.23 of the BIOS that prevents Windows Vista from installing.
Version 1.24 fixes the problem, please update the BIOS. Check http://drivers.WYSIWYGComputers.com/
</DESCRIPTION>
</HISTORY>
<LOOKUP NAME=”XXX ROM BIOS Version 1.23″>
<DATA NAME=”Computer Manufacturer” VALUETYPE=”string” VALUE=”Wysiwyg Computers”/>
<DATA NAME=”Model” VALUETYPE=”string” VALUE=”WYSIWYG Super Cool Computer 2007″/>
<DATA NAME=”Date” VALUETYPE=”string” VALUE=”20060801000000.000000+000″/>
</LOOKUP>
</DRIVER>
</DATABASE>

Posted in Deployment | Tagged: , , | Leave a Comment »

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 »

LTIPause.vbs – Take a break in deployment

Posted by Mikael Nystrom on May 10, 2011

Ok, so I know there is a very nice script called LTISuspend.wsf that will suspend the deployment, kind of perfect when you need to stop the deployment at a certain point and then resume after you have “fixed” the things you need to do.

But that is not always perfect, especially when you are in to troubleshooting, of course that never happens for me since I always build everything perfect the first time, or not. So a good friend of mine once showed me a simple but very useful tip and that is to create a vbscript called LTIPause.vbs, save it in the scripts folder and then use the run command for every section that you would like the task sequence to take a break, when you have checked whatever you need to check you just hit ok and it will continue. The content of the script is very, very small and looks like this


MsgBox “ok”


Hey, it does not get easier then that as far as I see it. Well that works, but can it be improved? Yes, it can. Here is my story of improvement

  • Adding direct output of variables in the msgbox
  • Adding a way to “disable” all Pause commands in all Sequences

Let us start with adding environment variables, the only thing we need to do is to use the variables that are stored in the task sequence and the print out the information on the screen if everything is working it should look something like this when you run it:

image

the LTIPause.vbs should look like this:


Set env = CreateObject(“Microsoft.SMS.TSEnvironment”)
MsgBox “Pausing Task Sequence, click OK to continue…” & chr(13) & _
” ” & chr(13) & _
“Computername:” & chr(9) & chr(9) & env(“OSDComputername”) & chr(13) & _
“IPAddress001:” & chr(9) & chr(9) & env(“IPAddress001”) & chr(13) & _
“DefaultGateWay001:” & chr(9) & env(“DefaultGateway001”) & chr(13) & _
“Phase:” & chr(9) & chr(9) & chr(9) & env(“Phase”) & chr(13) & _
“Make:” & chr(9) & chr(9) & chr(9) & env(“Make”) & chr(13) & _
“Model:” & chr(9) & chr(9) & chr(9) & env(“Model”) & chr(13) & _
“VMPlatform:” & chr(9) & chr(9) & env(“VMPlatform”) & chr(13) & _
“TaskSequenceID:” & chr(9) & chr(9) & env(“TaskSequenceID”) & chr(13) & _
“TaskSequenceName:” & chr(9) & env(“TaskSequenceName”) & chr(13) & _
“TaskSequenceVersion:” & chr(9) & env(“TaskSequenceVersion”) & chr(13) & _
“ViaServerConfig:” & chr(9) & chr(9) & env(“ViaServerConfig”) & chr(13) & _
“ImageFlags:” & chr(9) & chr(9) & env(“ImageFlags”) & chr(13) & _
“ImageBuild:” & chr(9) & chr(9) & env(“ImageBuild”) & chr(13) & _
“SLShare:” & chr(9) & chr(9) & chr(9) & env(“SLShare”) & chr(13) & _
“SLShareDynamicLogging:” & chr(9) & env(“SLShareDynamicLogging”) & chr(13) & _
“DeployRoot:” & chr(9) & chr(9) & env(“DeployRoot”) & chr(13) & _
“DriverGroup001:” & chr(9) & chr(9) & env(“DriverGroup001”) & chr(13) & _
“DriverGroup002:” & chr(9) & chr(9) & env(“DriverGroup002”) & chr(13)_
, 0, “LTIPause”


Sorry for all the chr, that’s just VB formatting and not needed for functionality but it looks better this way. You can add all kind of variables and their corresponding values. (look for Properties in the help, that will get you some of them) So now you have the script, just save it as LTIPause.vbs in the scripts folder and add it to the step you would like the the Task Sequence to pause, like this:

image

Now, instead of removing the pauses in your task sequences you can keep them and just disable them or you can set a condition on these commands and that I do. I add the following to my CustomSettings.ini


[Settings]
Priority=Default
Properties=MyCustomProperty, TestMode

[Default]
OSInstall=Y
TestMode=ENABLE


and then in the task sequence you just set this as a condition to run the command like this:

image

as long as TestMode is set to Enable it will run the command LTIPause at the locations you have decided by putting in LTIPause.vbs script.

If you are testing your Task Sequence from a command line you can also add /TestMode:ENABLE so it would look like this:

\\server\share$\scripts\litetouch.vbs /TestMode:ENABLE

That would result in the same thing.

You might want to read a bit more on this subject:

/mike aka The Deployment Bunny

Posted in Deployment | Tagged: , , | 3 Comments »