Quantcast
Channel: MDT – The Deployment Bunny
Viewing all 70 articles
Browse latest View live

Incorporating KB2028749 Into Your Microsoft Deployment Toolkit Reference Image Build Process


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

$
0
0

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


Just for fun: – The MDT team has a humor

$
0
0

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>


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

$
0
0

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


Modifying the Lite Touch Wizard in MDT 2010 – Sample 2

$
0
0

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


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

$
0
0

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


Device drivers can make you feel “differently”…

$
0
0

Today’s story is about a driver, a driver that did not really wanted to be installed. I’ll guess you been in that situation before and I will give a tip on how to make those drives install like a charm. The driver of today’s topic is a Smartcard driver, so first of all we need to force the driver in to the deployment solution, which normally is not too advanced. You just down load the driver, unpack the driver and import the driver into the Deployment Workbench in MDT or as a driver package into SCCM, in MDT we need to create a selection profile so we can ignore PNP and just inject the driver and so I did. First test shows that, yes the driver does get into the driver store but it does not work. You can always see what driver you have in Windows 7 using DISM

DISM /Online /Get-Drivers /Format:Table

Ok, so now I need to read about this driver, so after a while it turns out that the driver can only be installed using “Right click on the INF file and select install” method, Well that then tells me that using the old Rundll32 trick should work, but no luck. Ok, ok let us try the Devcon trick the, nope sorry. Now at this time the customer is asking me if I have any problems and of course I don’t have any problems, it’s just a “bad” driver-day…

So, it works when right clicking, ok. But nothing else seems to work, hmm. There is one thing I haven’t tried yet and that is to use the IExpress trick, let us try that and 25 minutes later (re-deploy the machine) it worked like a charm. Now you may ask yourself. –What is the IExpress trick?

Package nasty drivers in a self-extracting and self-installing executable

Now, let us be very clear about one thing, all other methods are better than this (if they work) but sometimes I don’t have time to fly over to the developer with my baseball bat and explain how to do things…

1. Get the driver

In this case the driver is downloadable from the vendor and from http://catalog.update.microsoft.com. From the Vendor it’s a ZIP and from MS catalog it’s a CAB file. A nice thing about MS Catalog is that you can search for the PNP number, but in this case I know the name. A search on “HID C200” will give me “HID Global – Input – HID Crescendo C200”

2. Unpack the driver

ZIP files is, well just ZIP file. CAB files can be opened easily using the command Expand

Expand file.CAB –f:* C:\Driver

3. Pack the Driver using IExpress

What you might not know is that included in Windows 7 there is a packaging application called IExpress and in this case it is really useful.

So, here is the step by step:

clip_image001

Start IExpress by typing IEexpress in a CMD prompt and select to create a new package.

clip_image002

Select to “Extract and run an installation command”.

clip_image003

Give it a name.

clip_image004

Select no confirmation prompt.

clip_image005

Don’t display any license agreement.

clip_image006

Browse to the folder where you have unpacked the drivers and select them all.

clip_image007

Use the dropdown list and select the inf file, if you want to run something else like a batch file, just type the name and it will work.

clip_image008

Nope, no windows please…

clip_image009

Nope, don’t need any kind of messages…

clip_image010

Be sure to select “long names” if the driver have that".

clip_image011

Nope, no restart, we will fix that in the task sequences ourselves.

clip_image012

Save it.

clip_image013

Create the package.

clip_image014

Wait…

4. Deploy the package

Now you have an executable application that works in MDT (have not tested in SCCM, but it might work there too) that will deploy the “nasty” driver in a way that works…

/mike – aka the Deployment Bunny


Online Session – Microsoft Deployment Toolkit 2012

$
0
0

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



Modelalias User Exit for Microsoft Deployment Toolkit 2010/2012

$
0
0

No, I did not create this script, I think this has been around for a long time, somewhere around 2007 and correct me if I’m wrong but I believe it was Ben Hunter that started this back in the days. I have then seen this at the Deployment Guys and various other TechNet sites I did some updates to it since I do a lot of OS deployment in virtual environments, VirtualBox, VMware, Xen and of course Hyper-V. In MDT 2012 they spot most of this with the following information but in some cases you need a bit ore, and you need to be able to modify it to

So Credit goes to Microsoft, Ben Hunter and “The Deployment Guys” (and I’m sure Michael Niehaus has been involved too, so credits for him as well)

Using the Modelalias User Exit script in the Virtual World

In MDT 2012 they have bumped up the information you get from the ZTIGather script, below is the most important information we get from it. But sometimes we need more, but before we get into that, check out the list below. Notice the two last Hyper-V examples, we have the same info returned but that is not the same version of the Hypervisor.

What do you get directly from MDT 2012 s virtualization information?

Here is the result you get during the inventory when running on a VMWare ESXI or VMware Workstation

  • Property IsHypervisorRunning is now = True
  • Property IsVM is now = True
  • Property VMPlatform is now = VMware

Here is the result you get during the inventory when running on a VirtualBox

  • Property IsHypervisorRunning is now = False
  • Property IsVM is now = True
  • Property VMPlatform is now = VirtualBox

Here is the result you get during the inventory when running on a Xen

  • Property IsHypervisorRunning is now = True
  • Property IsVM is now = True
  • Property VMPlatform is now = Xen

Here is the result you get during the inventory when running on Hyper-V (2008 R2)

  • Property IsHypervisorRunning is now = True
  • Property IsVM is now = True
  • Property VMPlatform is now = Hyper-V

Here is the result you get during the inventory when running on Hyper-V (2012 BETA)

  • Property IsHypervisorRunning is now = True
  • Property IsVM is now = True
  • Property VMPlatform is now = Hyper-V

There are more info that we will get in MDT around virtualization, here is the complete information around virtualization for a Hyper-V guest OS

  • Property IsHypervisorRunning is now = True
  • Property SupportsVT is now = False
  • Property SupportsNX is now = True
  • Property Supports64Bit is now = True
  • Property SupportsHyperVRole is now = False
  • Property VMHost is now = IBL04.tslab.net
  • Property VMName is now = TESTHV20
  • Property IsVM is now = True
  • Property VMPlatform is now = Hyper-V

As you can see we also get the hostname and VMname, but only if the IC’s are loaded and they are not loaded by default in WinPE, but a friend of mine banged his head against the keyboard for a while and here is the answer…

Is this ok?

This is mostly ok and fine, but sometimes I really need to know what version of Hyper-V (or other platform) it is and at the same time I would like to support and handle the different naming standards that all vendors has and translate it all to one new property called ModelAlias. Then I can use ModelAlias instead of Model, since I can tweak, twist and bend whatever the OEM’s try to do I can translate it to something that is easy to handle. ModealAlias has been one of the easy ways to deal with Lenovo’s interesting model naming. They use 4+3 digits as model, the first 4 is the real model and the rest is the “unique” build, like unique keyboards and such (things that matters outside the OS deployment world), but for me the same driver is going to be installed even if the keyboard is in Swedish…

If you look at the last example, you will see that we get the same result for Hyper-V in all releases, well that’s “ok”, but the issue is that If I need to install the Integration Components I need to know what version to install to be supported and optimized. So by using the ModelAlias userexit script in MDT (Works in both LiteTouch and in ZeroTouch) the script will examine the bios version (and other information if you need to) and determine the version. So if we take a peek into the script it looks like this for the Hyper-V part.

As you can see BIOS version VRTUAL – 3000919 will give me ModelAlias=Hyperv2008R2 and BIOS version VRTUAL – 9001114 will give me ModelAlias Hyper-V2012BETA

Using the Modelalias User Exit script in the Physical World

Here is another example on how to use this, I was deploying servers not long ago and I was using MDT 2010 LiteTouch. I handle drivers using %make%\%model% in most cases but in this case that was kind of tricky. The reason, well IBM has some fancy characters in the model string (like -[]-), not really easy to use as a path. J

As you can see they have —[HS22]— as model name and after using the userexit script it will be converted into IBMHS22 and that is a bit easier to handle as part of a file path.

Here is one other example for a HP Compaq 8240. HP has a bunch of “different” 8240′s, but from my perspective it is just the same when it comes to drivers and apps, so we convert them into something more useful, like this

Here you can see the real model name being “HP Compaq nw8240 (PY442EA#AK8)” and after a translation it will be just “HP Compaq nw8240″ instead, easier to handle, easier to have as a path in MDT

How do you use the UserExit script?

This is the easy part, just download it, unpack it and save it in the scripts folder in MDT. Then you modify the customsettings.ini to use the script like this:

[Settings]
Priority=SetModelAlias, ModelAlias, Default
Properties= ModelAlias

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

[Hyper-V2008R2]
MandatoryApplications001=<GUIDNumberOFApplicationInLTI>

[Hyper-V2012BETA]
MandatoryApplications001=<GUIDNumberOFApplicationInLTI>

(If you are using SCCM you will the use Packages or Application name, but it works the same)

When you run ZTIGather.wsf you can see the result like this on a Windows Server 2012 BETA

You can download the ModelAlias.vbs script here

Here is some links to older versions of the script:

The Deployment Guys

Ben Hunters Blog

/mike


Nice to Know: Remove the Windows 8 Animation during OS Deployment

$
0
0

Don’t get me wrong, I like to watch a god movie, it’s just that I don’t like to see the same movie twice. In Windows 8 there is a movie that is played for the first time logon and there is a Group Policy setting you can use to disable it. However, since I’m an OSD guy, I prefer to remove it long before that. So here you have a nice MDT Application you can download and install and put it into your task sequence for Windows 8 and you will never ever see it once more. Happy deployment!

(and thank you Jeremy Moskowitz for the idea on YouTube)

Download the zip file, extract it and create a new Application in MDT 2012 Update 1.

Select Application with Source Files

image

Give it a name

image

Select the location of your download

image

Give it a name

image

Type in the command

cscript Configure-Win8AnimAtFirst.wsf

image

Finish

image

Then you add it to your task sequence. Done

image

The script looks like this:


<job id="Configure-Win8AnimAtFirst">
<script language="VBScript" src="..\..\Scripts\ZTIUtility.vbs"/>
<script language="VBScript">

‘//—————————————————————————-
‘// Solution: Hydration
‘// Purpose: Used to turn off the animation in Windows at first logon
‘// Usage: cscript Configure-Win8AnimAtFirst.wsf [/debug:true]
‘// Version: 1.0 – Jan 02 2013 – Mikael Nystrom
‘//
‘// This script is provided "AS IS" with no warranties, confers no rights and
‘// is not supported by the authors or the Deployment Bunny.
‘//
‘//—————————————————————————-

‘//—————————————————————————-
‘// 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()

    oLogging.CreateEntry "Configure Animation in Windows 8: Starting", LogTypeInfo   

    oShell.RegWrite "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\EnableFirstLogonAnimation", "0", "REG_DWORD"

    oLogging.CreateEntry "Configure Animation in Windows 8: Done", LogTypeInfo   

End Function

</script>
</job>


 

/mike


Nice to Know – Dumping MDT Monitor data to a Webpage (using PowerShell)

$
0
0

(update – http://deploymentbunny.com/2013/12/13/nice-to-know-dumping-mdt-monitor-data-to-a-webpage-using-powershell-update/)

A customer asked me –Could you create like a web page that shows the same info as the MDT monitoring tab, so can see all the deployment all the time?, the answer is of course –Yes, of course you can!

Now, before you start barking at me and say “That could be done much easier using C#, Lisp, VB.Net” or something, this was the “My-flight-leaves-very-soon” kind of coding, so it jus a very simple PowerShell snip that runs on a 5 min schedule and create a new page and the result looks like this:

image

The script will read the data from the MDT monitoring feed, so the web server does not need to be on the server it self, it does not require anything at all, the script generates a HTML page and the we “modify” it on the fly and the save it in the inetpub folder, and here is the code:

image

And in text form:

$URL = "http://EDUDEPLOY09:9801/MDTMonitorData/Computers"

function GetMDTData { 
  $Data = Invoke-RestMethod $URL

  foreach($property in ($Data.content.properties) ) { 
    New-Object PSObject -Property @{ 
      Name = $($property.Name); 
      PercentComplete = $($property.PercentComplete.’#text’); 
      Warnings = $($property.Warnings.’#text’); 
      Errors = $($property.Errors.’#text’); 
      DeploymentStatus = $( 
        Switch ($property.DeploymentStatus.’#text’) { 
        1 { "Active/Running" } 
        2 { "Failed" } 
        3 { "Successfully completed" } 
        Default { "Unknown" } 
        } 
      ); 
      StartTime = $($property.StartTime.’#text’) -replace "T"," "; 
      EndTime = $($property.EndTime.’#text’) -replace "T"," "; 
    } 
  } 
} 

$Head = "<style>"
$Head = $Head + "BODY{background-color:peachpuff;}"
$Head = $Head + "TABLE{border-width: 2px;border-style: solid;border-color: black;border-collapse: collapse;}"
$Head = $Head + "TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:thistle}"
$Head = $Head + "TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black}"
$Head = $Head + "</style>"

$Title = "LabCenter Deployment Status"

GetMDTData | Select Name, DeploymentStatus, PercentComplete, Warnings, Errors, StartTime, EndTime | Sort -Property Name |
ConvertTo-Html  `
-Title $Title  `
-Head $Head  `
-Body (Get-Date -UFormat "%Y-%m-%d - %T ")  `
-PreContent "<H2>LabCenter Deployment Status for: $ENV:COMPUTERNAME </H2><P>Generated by Power of the Force</P>"  `
-PostContent "<P>For details, contact support@truesec.se.</P>"  `
-Property Name,DeploymentStatus,PercentComplete,Warnings,Errors,StartTime |
ForEach {
if($_ -like "*<td>Successfully completed</td>*"){$_ -replace "<tr>", "<tr bgcolor=green>"}
elseif($_ -like "*<td>Failed</td>*"){$_ -replace "<tr>", "<tr bgcolor=red>"}
else{$_}
} > C:\inetpub\wwwroot\default.htm 
#Invoke-Item $ENV:TEMP\Default.htm

And as a download of course http://sdrv.ms/J4ttVC

/mike


Nice to Know – Dumping MDT Monitor data to a Webpage (using PowerShell) – Update

$
0
0

A couple of days ago I published a simple PowerShell script that dumps the MDT monitoring data and convert it into a web page, the interest for that has been huge. The customer came back to me with one of those –Is it possible to…

They wanted to have the role that is assigned to the computer and that information is not in the MDT monitoring data output, but it is in the MDT database, so if I could read that using PowerShell and use the name from the MDT Monitoring as input, that should be doable. So I “sacrificed” the evening and now it is working, email the customer and the response was “Thank you!!”, so I thought maybe you would like to get the update to.

The new look! (including the Role information from the MDT database)

image

The new Script

image

The difference is:

Line 2 and 3:
  • I added the logic to connect to the DB
Line 11 – 15
  • I added logic to get the role from the DB
Line 42
  • I added Role in the select state
Line 49
  • I added Role in the select state

That’s all

/mike

Download the script: http://sdrv.ms/1hRSMZv

Read about the original post here: http://deploymentbunny.com/2013/12/09/nice-to-know-dumping-mdt-monitor-data-to-a-webpage-using-powershell/

Read about Sean O’Mahony’s ”branding/styling” here : http://mentalseepage.wordpress.com/2013/12/12/output-mdt-monitor-tab-to-webpage/

Read about getting the MDT Monitor to work in SCCM here: http://www.deploymentresearch.com/Research/tabid/62/EntryId/131/Adding-DaRT-8-1-from-MDOP-2013-R2-to-ConfigMgr-2012-R2.aspx

Read about the PowerShell module for MDT here: http://blogs.technet.com/b/mniehaus/archive/2009/07/09/3241504.aspx


PowerShell is King – Create a webpage containing LTI/ZTI Deployment issues with information and links to logs

$
0
0

Knowing is better than guessing, that is an indisputable fact as far as I know and since we try to automate more and more (someone wrote –automating the world, line by line and that is so darn correct) we now need to monitor much more. OS Deployment has been possible to automate for many years, but the level of monitoring to see if everything is working correctly is in place and there are many reasons for that, some solutions just takes forever to deploy and configure and some takes forever to understand how they work.

The Problem:

We need to be able to see if everything works as expect, we all work in the Service Sector, we are suppose to service our organizations and help our users so they can do whatever they are suppose to do (I know, working in IT is not that cool anymore). If you have MDT you could enable the monitoring feature, but it will only tell you ongoing deployments and if they went well or not, you cannot see the issues, only the number of issues. If you have SCCM it is far better, but, better could be better…

The Solution

In MDT there is a monitoring feature and what not so many know about is that it is actually writing to the event log.

$MDTevents = Get-EventLog -LogName Application -Source MDT_Monitor -EntryType Warning,Error
$MDTevents | Select Message

image
Output from running the commands above.

So, if we could create script that dumps that, split the message into 3 objects, machine name, type of error, and message, add the path to the logs for each machine we have a solution, right?

Issue Number one

The event log is fantastic, it has so many parameters to work with, but in this case it does not work, since all data is just a string in the event it self, so we need to extract that and “bend the rules a bit”, this is what we get if we don’t do anything at all

image
As you can see, it is all in the EventData, just as a dumb string.

With this little function we can now dump the data, turn the string into 3 objects, flip them around so that the computer name comes first (like to sort it on computer name), remove junk

image

Issue Number two

Converting to HTML with links to the logs, well that can be done rather easy using this part

image
Here you can see that we dump out the data running the Function Get-MDTIssues with a select statement that on the first position creates a new object called “link” and it will add a href tag on the computer name, so now we have a nice HTML page, well not really. there is another problem

Issue Number three

ConvertTo-HTML does not like HTML, it will of course convert everything to HTML, including HTML and the HTML we had is no HTML anymore…

But, Convertto-html is an object, so we can of course convert that on the fly using –replace and at the same time we can add the computer name correctly to the server we are running this on

image

Issue Number four

Now everything works, Yeah, well no, as soon as you have this “not-so-very-designed-web-page” you will be able to click the links and THAT works, you will end up in the log folders

image

So let us click one of them:

So far so good:

image

But you cannot click any of the links until you add a mime type for .log in IIS

image

Install and Configure

  • Download file from here: http://sdrv.ms/1h4WrD7
  • Store it locally on the MDT server (The server with the Deployment workbench, it is possible to run the script from an other machine, but then you need to modify the script to read the log from another computer)
  • Make sure that MDT Monitoring is enabled

image

  • Make sure that CustomSettings.ini is correctly configured to store the logs and to enable to send monitor data
    • SLShare=\\SRVMGT01\Logs$
    • EventService=http://SRVMGT01:9800
  • Add the IIS Feature
  • Add two Web Applications

image

  • Enable Directory Browsing for Logs and MDT (If you call the file default.htm or similar you don’t need that)
  • Schedule the script to run (You could a be smart, schedule a task based on the MDT_Monitor to run the script for warnings and errors

imageimage

  • Testing could be done in two ways, you could either deploy a machine and hope it fails or you could run this POSH command:

Write-EventLog -LogName Application -Source MDT_Monitor -EntryType Warning -EventId 2000 -Message "Error logged for computer TEST01: Application Install – HP Support Pack returned an unexpected return code: 1"

image

and if everything works correct, well you should be able to see that in the webpage

image

Happy “Warnings, errors and failures”

/mike


OS Deployment – Out Of Band install of Windows Server 2012 R2 Using MDT,WDS and PowerShell

$
0
0

PowerShell is amazing, it is now possible to do all those things I know would be possible, but did require compiled code or time I don’t have (Still working as an consultant in the real world you know). In my line of work besides automation, flexibility is one other keyword and that is very often used in conjuction with Windows Server deployment. Now, Windows Server is also amazing, it is a multipurpose operating system and multipurpose also means that while client deployment is pretty standard these days, server deployment is not even close to that. In SCCM we have great OS Deployment (even better with MDT integration), but in many cases I’m not allowed to use it. MDT is very flexible and many orgs are using MDT for server deployment and SCCM for clients and they have their reasons, but MDT lacks some of the features that SCCM/MDT does have. We also have an upcoming star and that is SCVMM, while SCVMM has some of the benefits that SCCM have but MDT does not have, well you get the point. But, if you could have bits and pieces from each and every one, and does not require an investment in System Center knowledge, what about having only Active Directory. Windows Deployment Services, DHCP/DNS, MDT and a PowerShell script? Wouldn’t that be nice?

The parts

It is not that hard to setup and configure, but still, there is a lot of moving parts and you need to understand them all, therefore it is dived in the following parts for more details
(note I’ll add the links as soon as I have written them, ok)

  • OS Deployment – Out Of Band install of Windows Server 2012 R2 Using MDT,WDS and PowerShell (Part 1–Getting the Hardware info)
  • OS Deployment – Out Of Band install of Windows Server 2012 R2 Using MDT,WDS and PowerShell (Part 2–Pre-stage device in AD)
  • OS Deployment – Out Of Band install of Windows Server 2012 R2 Using MDT,WDS and PowerShell  (Part 3–Pre-stage device in MDT)
  • OS Deployment – Out Of Band install of Windows Server 2012 R2 Using MDT,WDS and PowerShell (Part 4–Controlling Power remote)
  • OS Deployment – Out Of Band install of Windows Server 2012 R2 Using MDT,WDS and PowerShell (Part 5–Controlling Drivers)
  • OS Deployment – Out Of Band install of Windows Server 2012 R2 Using MDT,WDS and PowerShell (Part 6–Apps and Firmware)

The Script

If you know this stuff and just need the script, download it from here: http://sdrv.ms/JCo5bO

Run Import-Module .\ServerDeployment-v1.psm1 –Verbose to import the module

image

run Get-Module to verify

image

To see all the functions you now have, just run Get-Command – Module ServerDeployment-v1

image

to get all the command syntax, just type Get-Command -Module ServerDeployment-v1 –Syntax

image

There is builtin help with command samples, just use Get-Help Command to get the help

image

Note: The script will assume certain things:

There are just a few hardcoded paths, its for the  two modules (yes, there are others way to solve the problem)

Make sure the dependent POSH modules are located here:

  • Import-Module ‘C:\Program Files\Hewlett-Packard\PowerShell\Modules\HPiLOCmdlets’ -ErrorAction Stop
  • Import-Module ‘C:\Program Files\Microsoft Deployment Toolkit\MDTDB.psm1′ -ErrorAction Stop

One last thing, this is not for beginners, you really need to understand the bits and pieces this time.

/mike


PowerShell is King – Building a Reference Image Factory

$
0
0

In the world of deployment a reference image is where all begins, basically we take the ISO/WIM from the vendor, install it, tweak it, patch it and on the other side we now a have a customized reference image that is more suitable for our needs. This applies to both clients and servers. There are two ways of doing this, the correct way and the incorrect way. The correct way is repeatable and as automated as possible. This blog is about the correct way and how to automate it just a bit more then usual. You can of coarse modify the script so it will do more, for example upload the images to the correct destination.

Acknowledgement goes to:

What do I need to get this working?

Step 1: Set up Microsoft Deployment Toolkit 2013 on a server

Step 2: Import Operating Systems, applications and create your task sequences

Step 3: Install Windows Server 2012 R2 (or Windows 8.1) with Hyper-V as your “creator”

Step 4: Download the script and enjoy the show

Note:

  • The script is designed to run on the Hyper-V machine, but it is possible to run this remote either using Remote-Sessions or defining –Computer on every Commands that relates to Hyper-V
  • The Solution is tested on Windows Server 2012 R2 with MDT 2013 and ADK 8.1 BUT should work just fine on Windows 8.1

How does the script work?

image

The PowerShell module has a couple of functions

New-AutoGenRefImages

This function will connect to your MDT server, grab the boot ISO, read all TaskSequences from Task Sequences\REF

image

And for each of them build a VM with the same name as the task sequence. When they are all built it will power them on one by one, booting from the ISO and then run the task sequence that corresponds to the name of the the VM. So if you have a TS with the ID of RW81.x86, it will build a VM with that name and run the TS with that ID on that VM.

You might ask your self how that is done?. I’m not using the database, not using GUID number or Mac’s. The main reason is that I want a solution with as little dependencies as possible, so it will work anytime at any customer (almost). Instead I’ loading the drivers for KVP (Key Value Pair Exchange) in WinPE, I grab the name of the VM before the customsettings.ini is read using a userexit script in bootstrap.ini so I have a Property called VMNameAlias wich then is used to control the deployment process, a neat solution IMHO (more on that later)

Remove-AutoGenRefImages

This function will destroy and remove all VMs, it does this by getting all task sequence ID’s from the MDT server, and find corresponding VM’s and then destroy and clean up.

New-RefImage

This is a manual process, you now need to KNOW the Task Sequence ID, since that is a validation in the CMDLET

Remove-RefImage

Also a manual process, it will destroy/delete/cleanup whatever VMname you type in, note that there will be NO questions, it just deletes them, so don’t type in DC01 or something like that.

Get-RefTaskSequence

A simple CMDLET that lists all task sequences that are in the \REF folder in MDT

The Details

Download the Scripts from here: http://sdrv.ms/1hqoJIh

Download devcon.exe from here: http://support.microsoft.com/kb/311272/en-us

Modify ImageFactoryV2.xml

This is my sample XML file and you need to modify it so it will work in your environment.

<Settings>
<DeploymentShare>\\SRVHOST555\MDTBuildLab$</DeploymentShare>
<HyperVHost>SRVHOST555</HyperVHost>
<HyperVHostNetwork>UplinkSwitch</HyperVHostNetwork>
<HyperVStorage>E:\VMs</HyperVStorage>
<HyperVISOFolder>E:\ISO</HyperVISOFolder>
<HardwareProfile>MDT 2010 Profile</HardwareProfile>
<TaskSequenceFolder>MDT:\Task Sequences\REF</TaskSequenceFolder>
<StartUpRAM>2</StartUpRAM>
<VLANID>0</VLANID>
<VHDSize>60</VHDSize>
</Settings>

Modify bootstrap.ini

Bootstrap.ini needs some modification (besides being silent). You need to add the following:

image

In text:

[Settings]
Priority=Default

[Default]
DeployRoot=\\SRVHOST555\MDTBuildLab$
UserDomain=NETWORK
UserID=Administrator
UserPassword=Password02
SkipBDDWelcome=YES
SubSection=ISVM-%IsVM%

[ISVM-True]
UserExit=LoadKVPInWinPE.vbs

This will load a userexit script that installs the driver for KVP and create a fake services that will allow it to load.

Modify customsettings.ini

You need to modify customsettings.ini so it will read in the values from the KVP correctly

image

In text:

[Settings]
Priority=Init,Default
Properties=VMNameAlias

[Init]
UserExit=ReadKVPData.vbs
VMNameAlias=#SetVMNameAlias()#

[Default]
TaskSequenceID=%VMNameAlias%

You need to add the Property VMNameAlias under the Settings Section

You need to create a new Section called Init that runs the UserExit

You need to set the TaskSequenceID to match the returned value from the UserExit script

Modify the boot image:

You need to make sure that those two scripts are added correctly and we also need the driver for KVP. One easy way is to use the “Extra” folder feature in MDT, whatever you put in that folder will end up on the boot image.

My deployment share is located in

E:\MDTBuildLab

so I created a folder called

E:\MDTBuildLab\Extra

In that Folder I two folders, Deploy and KVP. In the folder Deploy I have a subfolder called Scripts.

Like this:

image

Content of the KVP folder:

In the KVP folder you need to add the driver for KVP, and that you can do by searching for VMGuest.iso on your Hyper-V host, it is in C:\Windows\System32, mount that is and extract the drivers.

The driver you need is in the support\x86\Windows6.x-HyperVIntegrationServices-x86.cab and the folder is namned x86_wvmic.inf_31bf3856ad364e35_6.3.9600.16385_none_968283a5680527fe

(read Keith Garners blog for details, Note: In Keith’s blog it is 64 bit, I’m using the 32 bit driver, since I boot from the x86 boot image. Therefore the name is different of course.)

You also need to store devcon.exe in that folder

When you got them, it should look like this in the folder

image

Content of the Deploy\Scripts folder

In this folder you store the LoadKVPinWinPE.vbs script

Like this:

image

Update the BootImage:

In the Boot Image setting for WinPE, for the setting called Extra directory to add, browse to your folder, apply, update boot image.

image

The Scripts:

LoadKVPInWinPE.vbs

Mainly “borrowed” from Keith’s blog, just modified to use devcon.exe instead the method suggested by Keith


option explicit

function UserExit(sType,Swhen,Sdetail,bSkip)
oLogging.CreateEntry “USEREXIT:ModelAliasExit.vbs started: ” & sType & ” ” & sWhen & ” ” & sDetail, LogTypeInfo

    If ucase(oEnvironment.Item(“ISVM”)) = “TRUE” and oEnvironment.Item(“OSVERSION”) = “WinPE” then

        oLogging.CreateEntry “Load the Integration Components”, LogTypeInfo
oUtility.RunWithConsoleLogging “\KVP\devcon.exe /r install \KVP\wvmic.inf vmbus\{242ff919-07db-4180-9c2e-b86cb68c8c55}”
CreateFakeService “TermService”, “Remote Desktop Service”, “FakeService.exe”
GetObject(“winmgmts:root\cimv2″).Get(“Win32_Service.Name=’vmickvpexchange’”).StartService()
oUtility.SafeSleep 10000
LoadVariablesFromHyperV

    End if

    ‘ Write back an unique number to the host to let them know that the variables have been loaded.
oUtility.RegWrite “HKLM\SOFTWARE\Microsoft\Virtual Machine\Auto\HydrationGuestStatus”,”eb471002-58aa-473a-850f-7b626613055f”

    Userexit=success

end function

‘ ———————————————————

Function CreateFakeService (sName,sDisplayName,sPathName )

    Dim objService
Dim objInParam

    ‘ Obtain the definition of the Win32_Service class.
Set objService = GetObject(“winmgmts:root\cimv2″).Get(“Win32_Service”)

    ‘ Obtain an InParameters object specific to the Win32_Service.Create method.
Set objInParam = objService.Methods_(“Create”).inParameters.SpawnInstance_()

    ‘ Add the input parameters.
objInParam.Properties_.item(“Name”) = sName
objInParam.Properties_.item(“DisplayName”) = sDisplayName
objInParam.Properties_.item(“PathName”) = sPathName
objInParam.Properties_.item(“ServiceType”) = 16
objInParam.Properties_.item(“ErrorControl”) = 0
objInParam.Properties_.item(“StartMode”) = “Manual”
objInParam.Properties_.item(“DesktopInteract”) = False

    ‘ Execute the method and obtain the return status.
CreateFakeService = objService.ExecMethod_(“Create”, objInParam).ReturnValue

End function

Function LoadVariablesFromHyperV

    Dim objReg
Dim aSubValues
Dim aValues
Dim SubVal

    oLogging.CreateEntry “Has MDT Environment Variables in Integration Components.”, LogTypeInfo
Set objReg=GetObject(“winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv”)
objReg.EnumValues &H80000002, “SOFTWARE\Microsoft\Virtual Machine\External”, aSubValues, aValues

    If isArray(aSubValues) then
For Each SubVal in aSubValues
oLogging.CreateEntry “Found Key: [" & SubVal & "]“, LogTypeInfo
oEnvironment.Item(SubVal) = oUtility.RegRead(“HKLM\SOFTWARE\Microsoft\Virtual Machine\External\” & SubVal)
Next
End if

End Function


ReadKVPData.vbs


‘//—————————————————————————-
‘// Version: 1.0 – Jan 04, 2013 – Mikael Nystrom
‘// Twitter @mikael_nystrom
‘// Blog
http://deploymentbunny.com
‘// This script is provided “AS IS” with no warranties, confers no rights and
‘// is not supported by the author
‘//—————————————————————————-
‘ //
‘ // Usage:     Modify CustomSettings.ini similar to this:
‘ //              [Settings]
‘ //              Priority=SetAlias, Default
‘ //              Properties=VMNameAlias
‘ //
‘ //              [SetAlias]
‘ //              VMNameAlias=#SetVMNameAlias()#
‘ // ***** End Header *****

Function UserExit(sType, sWhen, sDetail, bSkip)

    oLogging.CreateEntry “UserExit: started: ” & sType & ” ” & sWhen & ” ” & sDetail, LogTypeInfo
UserExit = Success

End Function

Function SetVMNameAlias()
oLogging.CreateEntry “UserExit: Running function SetVMNameAlias “, LogTypeInfo
SetVMNameAlias = “”
SetVMNameAlias = oShell.RegRead(“HKLM\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters\VirtualMachineName”)
oLogging.CreateEntry “UserExit: SetVMNameAlias has been set to ” & SetVMNameAlias, LogTypeInfo
oLogging.CreateEntry “UserExit: Departing…”, LogTypeInfo
End Function


ImageFactoryV2.psm1


<#
.Synopsis
Short description
.DESCRIPTION
Long description
.EXAMPLE
Example of how to use this cmdlet
.EXAMPLE
Another example of how to use this cmdlet
.INPUTS
Inputs to this cmdlet (if any)
.OUTPUTS
Output from this cmdlet (if any)
.NOTES
General notes
.COMPONENT
The component this cmdlet belongs to
.ROLE
The role this cmdlet belongs to
.FUNCTIONALITY
The functionality that best describes this cmdlet
#>
<#
.Synopsis
Short description
.DESCRIPTION
Long description
.EXAMPLE
Example of how to use this cmdlet
.EXAMPLE
Another example of how to use this cmdlet
#>
# Read Settings from XML
[xml]$Global:Settings = Get-Content .\ImageFactoryV2.xml
$Global:DeploymentShare = $Global:Settings.Settings.DeploymentShare
$Global:StartUpRAM = 1024*1024*1024*$Global:Settings.Settings.StartUpRAM
$Global:VHDSize = 1024*1024*1024*$Global:Settings.Settings.VHDSize
$Global:SWitchName = $Global:Settings.Settings.HyperVHostNetwork
$Global:VMLocation = $Global:Settings.Settings.HyperVStorage
$Global:HyperVISOFolder = $Global:Settings.Settings.HyperVISOFolder
$Global:TaskSequenceFolder = $Global:Settings.Settings.TaskSequenceFolder
$Global:VLANID = $Global:Settings.Settings.VLANID

function New-AutoGenRefImages{
Process
{

    #Connect to MDT:
Add-PSSnapIn Microsoft.BDD.PSSnapIn -ErrorAction Stop
Remove-PSDrive MDT -ErrorAction SilentlyContinue
$Null = New-PSDrive -Name MDT -PSProvider MDTProvider -Root $Global:DeploymentShare -Force
$MDTSettings = Get-ItemProperty MDT:
$ISO = $MDTSettings.’Boot.x86.LiteTouchISOName’

    #Check if ISO exists
$ISOFileExist = Test-Path “$($Global:DeploymentShare)\Boot\$($ISO)”  -ErrorAction SilentlyContinue
If($ISOFileExist -like ‘False’){
Write-Host “Unable to find ISO, exit”
BREAK
}

    #Create Folders
$Null = New-Item -Path $HyperVISOFolder -ItemType Directory -Force -ErrorAction SilentlyContinue

    #Copy the BootImage from MDTServer to Hyper-VHost
Copy-Item “$($Global:DeploymentShare)\Boot\$($ISO)” $Global:HyperVISOFolder\ -Container -Force -ErrorAction Stop

    #Check if ISO exists
$ISOFileExist = Test-Path ($Global:HyperVISOFolder + “\” + $ISO) -ErrorAction Stop
If($ISOFileExist -like ‘False’){
Write-Host “Unable to find ISO, exit”
BREAK
}

    #Check if VMSwitch on host exists
$VMSwitchExist = Get-VMSwitch -Name $Global:SWitchName -ErrorAction SilentlyContinue
If($VMSwitchExist.Name -ne $Global:SWitchName){
Write-Host “Unable to find VMSwitch, exit”
BREAK
}

    #Create the VMs
$RefTS = Get-ChildItem $Global:TaskSequenceFolder -Recurse
Foreach($TS in $RefTS){

        #Set VMName to ID
$VMName = $TS.ID

        #Check if VM exists
$VMexist = Get-VM -Name $VMName -ErrorAction SilentlyContinue
If($VMexist.Name -like $VMName){
Write-Host “VM already exist, exit”
BREAK
}

        $VM = New-VM –Name $VMname –MemoryStartupBytes $Global:StartUpRAM -SwitchName $Global:SWitchName -NewVHDPath “$Global:VMLocation\$VMName\Virtual Hard Disks\$VMName.vhdx” -NewVHDSizeBytes $Global:VHDSize -Path $Global:VMLocation
Add-VMDvdDrive -VM $VM -Path ($Global:HyperVISOFolder + “\” + $ISO)

        #Set
Get-VM -Name $VMName | Set-VMProcessor -CompatibilityForMigrationEnabled $True
Get-VM -Name $VMName | Set-VMProcessor -Count 2
If($Global:VLANID -notlike “0″){
Get-VM -Name $VMName | Get-VMNetworkAdapter | Set-VMNetworkAdapterVlan -Access -VlanId $VLANID
}
}
Foreach($TS in $RefTS){
#Set VMName to ID
$VMName = $TS.ID
$VM = Get-VM -Name $VMName
$VM | Start-VM
Start-Sleep “10″
while($VM.State -like “Running”){
Write-Output “Waiting for $VMName to finish.”
Start-Sleep “120″}
Write-Output “$VMName is done, checking for more”
}
}
}
function Remove-AutoGenRefImages{
Process
{

    #Connect to MDT:
$Null = Add-PSSnapIn Microsoft.BDD.PSSnapIn -ErrorAction SilentlyContinue
Remove-PSDrive MDT -ErrorAction SilentlyContinue
$Null = New-PSDrive -Name MDT -PSProvider MDTProvider -Root $Global:DeploymentShare -Force
$MDTSettings = Get-ItemProperty MDT:
$ISO = $MDTSettings.’Boot.x86.LiteTouchISOName’

        #Remove the VMs
$RefTS = Get-ChildItem $Global:TaskSequenceFolder -Recurse
Foreach($TS in $RefTS){

            #Set VMName to ID
$VMName = $TS.ID

            #Check if VM exists
$VMexist = Get-VM -Name $VMName -ErrorAction SilentlyContinue
If($VMexist.Name -like $VMName){
Write-Host “Removing $VMName”
$VMToRemove = Get-VM -Name $VMName
$FolderPath = $VMToRemove.path
if($VMToRemove.state -like “Running”){Stop-VM $VMToRemove -Force}
$VMToRemove | Remove-VM -Force
$FolderPath | Remove-Item -Force -Recurse
}
}
}
}
function New-RefImage{
[CmdletBinding()]
[OutputType([int])]
Param
(
[Parameter(Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ValueFromRemainingArguments=$false,
Position=0)]
[String]
$TaskSequenceID
)

Process
{

    #Connect to MDT:
Add-PSSnapIn Microsoft.BDD.PSSnapIn -ErrorAction Stop
Remove-PSDrive MDT -ErrorAction SilentlyContinue
$Null = New-PSDrive -Name MDT -PSProvider MDTProvider -Root $Global:DeploymentShare -Force
$MDTSettings = Get-ItemProperty MDT:
$ISO = $MDTSettings.’Boot.x86.LiteTouchISOName’

    #Check if ISO exists
$ISOFileExist = Test-Path “$($Global:DeploymentShare)\Boot\$($ISO)”  -ErrorAction SilentlyContinue
If($ISOFileExist -like ‘False’){
Write-Host “Unable to find ISO, exit”
BREAK
}

    #Create Folders
$null = New-Item -Path $HyperVISOFolder -ItemType Directory -Force -ErrorAction SilentlyContinue

    #Copy the BootImage from MDTServer to Hyper-VHost
Copy-Item “$($Global:DeploymentShare)\Boot\$($ISO)” $Global:HyperVISOFolder\ -Container -Force -ErrorAction Stop

    #Check if ISO exists
$ISOFileExist = Test-Path ($Global:HyperVISOFolder + “\” + $ISO) -ErrorAction Stop
If($ISOFileExist -like ‘False’){
Write-Host “Unable to find ISO, exit”
BREAK
}

    #Check if VMSwitch on host exists
$VMSwitchExist = Get-VMSwitch -Name $Global:SWitchName -ErrorAction SilentlyContinue
If($VMSwitchExist.Name -ne $Global:SWitchName){
Write-Host “Unable to find VMSwitch, exit”
BREAK
}

    #Check if VM exists
$VMexist = Get-VM -Name $VMName -ErrorAction SilentlyContinue
If($VMexist.Name -like $VMName){
Write-Host “VM already exist, exit”
BREAK
}

    $VM = New-VM –Name $TaskSequenceID –MemoryStartupBytes $Global:StartUpRAM -SwitchName $Global:SWitchName -NewVHDPath “$Global:VMLocation\$TaskSequenceID\Virtual Hard Disks\$TaskSequenceID.vhdx” -NewVHDSizeBytes $Global:VHDSize -Path $Global:VMLocation
Add-VMDvdDrive -VM $VM -Path ($Global:HyperVISOFolder + “\” + $ISO)

    #Set
Get-VM -Name $TaskSequenceID | Set-VMProcessor -CompatibilityForMigrationEnabled $True -VM $VM

    #Set
Get-VM -Name $TaskSequenceID | Set-VMProcessor -Count 2

    #Set
If($VLANID -notlike “0″){
Get-VM -Name $TaskSequenceID | Get-VMNetworkAdapter | Set-VMNetworkAdapterVlan -Access -VlanId $VLANID
}

    }

}
function Remove-RefImage{
[CmdletBinding()]
[OutputType([int])]
Param
(
[Parameter(Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ValueFromRemainingArguments=$false,
Position=0)]
[String]
$VMName
)
Process
{

    #Check if VM exists
$VMexist = Get-VM -Name $VMName -ErrorAction SilentlyContinue
If($VMexist.Name -like $VMName){
Write-Host “Removing $VMName”
$VMToRemove = Get-VM -Name $VMName
$FolderPath = $VMToRemove.path
if($VMToRemove.state -like “Running”){Stop-VM $VMToRemove -Force}
$VMToRemove | Remove-VM -Force
$FolderPath | Remove-Item -Force -Recurse
}
}
}
function Get-RefTaskSequence{
Process
{

    #Connect to MDT:
Add-PSSnapIn Microsoft.BDD.PSSnapIn -ErrorAction Stop
Remove-PSDrive MDT -ErrorAction SilentlyContinue
$Null = New-PSDrive -Name MDT -PSProvider MDTProvider -Root $Global:DeploymentShare -Force
$MDTSettings = Get-ItemProperty MDT:
$ISO = $MDTSettings.’Boot.x86.LiteTouchISOName’

        #Get TS
$RefTS = Get-ChildItem $Global:TaskSequenceFolder -Recurse
Foreach($TS in $RefTS){
New-Object PSObject -Property @{
TaskSequenceID = $TS.ID
Name = $TS.Name
Comments = $TS.Comments
Version = $TS.Version
Enabled = $TS.enable
LastModified = $TS.LastModifiedTime
}
}
}
}

Export-ModuleMember -function *


/mike



OS Deployment – Out Of Band install of Windows Server 2012 R2 Using MDT,WDS and PowerShell (Part 1–Getting the Hardware info)

$
0
0

This is post refers to this post http://deploymentbunny.com/2013/12/29/os-deployment-oob-install-of-windows-server-2012-r2-using-mdtwds-and-powershell/

Out of Band or Bare Metal installation requires information regarding the hardware, that is no surprise. We need to to be able to define settings that can be retried from the hardware. In many/most client deployment scenarios I see people using the MAC Address or, Serial Number but I use the GUID number. When it comes to server they don’t really have one NIC and when it comes to Hyper-V that MAC address will be more or less removed since the machine in most cases is turning the NICs into switches and then virtual NICs will be on top of that, so GUID number is better. All “normal” brands have that, at least with new server hardware. In this case I’m deploying HP Servers and they have iLO which is basically an other name for IPMI. In the case of iLO it is rather easy to access that information, you don’t even need to be authenticated, all the information we need is there (http://deploymentbunny.com/2013/12/18/nice-to-know-getting-hardware-infoilo-data-using-native-powershell-and-no-need-for-credentials/)

By reading the XML data in turn it into an object it is rather easy to use the data in PowerShell.

Below you can see the part we use to grab that data.

image

/mike


Nice to Know – Switch from ImageX to DISM in MDT

$
0
0

Be default the capture process in MDT 2013 uses ImageX to capture the image, there is nothing wrong with that, well, it takes time since Imagex takes about 15 minutes or more just to scan the file system before it starts to capture the image and maybe you would like to get rid of that time. That is possible by doing some modification to one of the scripts in MDT so that it starts to use DISM.exe instead

The script that needs to be modified is ZTIBackup.wsf and you can download the updated version here. (Please make sure you have a copy of the previous version so that you can go back for any reason.)

(Important note: I have updated the script since I missed to include settings that will honor the wimscript.ini file, without that the image will not be cleanup from junk and therefore larger. So, if you did download the script and used it, download it once more, since it is now updated)

As a bonus this also fixes the problem to append the wim file to an existing wim file.

How-to?

  1. Download the file from here: http://1drv.ms/1gZICln
  2. Rename the Scripts\ZTIBackup.wsf to ZTIBackup.old
  3. Clear the Internet download flag from the new ZTIBackup.wsf.
  4. Copy the new ZTIBackup.wsf to the Scripts folder.

Done.

/mike


Back to Basic – CustomSettings.ini – Sample 3 and a bunch more

$
0
0

Customsettings.ini is one of those text files in MDT/ConfigMgr that has a major impact on the solution, badly written the solution is a pain in the… correctly written and it works like magic…

A while back I created sample package, but I only published 2 of the samples in the package and now it is time for the rest of them:

  • Disable OSInstall.ini
  • Setting based on Computer type and location.ini
  • Settings based on Computer type.ini
  • Settings based on Default Gateway.ini
  • Settings based on MAC for servers.ini
  • Settings based on MAC.ini
  • Settings based on Model.ini
  • Settings based on TaskSequenceID.ini
  • Settings based on UserExit-Alias.ini
  • Settings based on VB Calculation.ini
  • Settings based on Virtual Machines.ini
  • Settings for UDI.ini
  • Using the SMSTSOrg.ini

To try them out in your environment you can just run:

cscript.exe “Path to your MDT folder”:\Scripts\ZTIGather.wsf /Inifile:”The Path to the .ini file you would like to test”

You can download the samples here: http://1drv.ms/1qPkg7l

(Note all these files has been made upon request from customers, so if you need one that I down have, ask me…)

/mike


Nice to Know – Get rid of all junk before Sysprep and Capture when creating a reference image in MDT

$
0
0

When you create a reference Image it will in most cases it will be updated with patches and some more patches and then some… That will make the image bigger and therefore the deployment of that image will take longer and consume more network resources. That can be corrected by getting rid of superseded patches, junk, temp files and much more. MDT does take care of much using the wimscript.ini during the capture process, but not all, not the old updates among other things.

The Solution

Since MDT is the preferred method to create reference images you can download the script, import it as an application and then run the application just before the Sysprep and Capture step. The Script works for the following versions of Windows:

  • Windows 7 SP1
  • Windows 8
  • Windows 8.1 Update
  • Windows Server 2008 2 SP1
  • Windows Server 2012
  • Windows Server 2012 R2

However, to make this work in Windows 7 and Windows Server 2008 R2 you need to add a hotfix to Packages in MDT. http://support.microsoft.com/kb/2852386

The script will use clenmgr.exe in all client versions of Windows. In Windows Server 2008 R2 it also uses clenmgr.exe, but it is never installed, instead it is copied from the SXS folder, that way we don’t need to install Desktop Experience. On Windows 8 and Server 2012 the script also runs the dism /online /clenup-image /startcomponentclenup and on 8.1 and server 2012 R2 the script adds the /Resetbase to make it impossible to remove patches.

Step By Step (kind of)

Download the script

Download the script from here http://1drv.ms/ThvLFE

Import it in MDT

Open the Deployment Workbench and browse to the Application node and import the folder you downloaded, giver it a name and as command line you type:

cscript.exe Action-CleanupBeforeSysprep.wsf 

image

 

Modify the Task Sequence

Open your task sequence and before the Sysprep and capture step, something like this works fine.

image

 

Add the HotFix (only for Windows 7 SP1 and Windows Server 2008 R2)

You need to add the patches in the deployment workbench. If you would like the deployment of the reference image to a bit faster, create three folders put the correct patch in each folder and then create corresponding Selection Profiles and modify the Task Sequence to use them. You download the update here http://support.microsoft.com/kb/2852386

Here you can see the patches imported in the Deployment Workbench.

image
The patches you need.

 

Here you can see the Selection Profiles and the selection in one of them.

image
The Selection Profiles.

Here you can see how the modification in the Task Sequence.

image
The Task Sequence modification to inject the the correct patch to the correct OS.

/mike


OSD–Using ZTISendMail to send email in a LTI/ZTI task sequence

$
0
0

Long time ago I had a need to send email an email in the end of the task sequence to notify the technician that the OS deployment was done, therefore creating a script which then ended up as a blog post at Deployment Research about two years ago. This week I’m running a Mastering Windows 7 and 8.1 OS Deployment using Lite Touch and Zero Touch in Minnesota and there where some requests on the subject so I decided to create a new version of the script and this time it is a PowerShell script instead. One of the request was to be able to send and email to the administrator that does the deployment (in Lite Touch) using the login name, so that need to to be taken under considerations to.

The script is tested in MDT 2013 but should work perfect in MDT 2012 Update 1 as well and it works when deploying Windows 8 and above.

Lite Touch

First you need to download the script and sample customsettings.ini  from here http://1drv.ms/1kvmobn and store the PowerShell it in the MDT Scripts folder.

Option Number One: Using the UserID directly

Update the CustomSettings like this. (you can copy and paste from the sample customsettings.ini files)

The name used to login to the LTI Wizard is defined as UserID and that is then used as a part of the email address to send it to.

image

Option Number Two: Using the UserID with translation.

In this case we create a section for every user account that should have an email an can logon. As an example, if you login as Administrator (don’t use that account!) an email would be sent to administartor@viamonstra.com, but you can have any other setting for that userID if you liketo.

Update the CustomSettings like this. (you can copy and paste from the sample customsettings.ini files)

image

Add a step in the TaskSequence.

image

Zero Touch

First you need to download the script and sample customsettings.ini  from here http://1drv.ms/1kvmobn and store the PowerShell it in the MDT Package Scripts folder.

In the ZTI we don’t really have a UserID and therefore we just send the email to a predefined email address and cc to an other.

Update the CustomSettings like this. (you can copy and paste from the sample customsettings.ini files)

image

Add a step in the Task Sequence like this.

image

Update the settings package and the MDT Package.

If you need a SMTP server to test against, read this http://deploymentbunny.com/2014/06/12/nice-to-knowa-simple-and-small-smtp-mailserver-fr-devlabtest-smtp4dev/

image

/mike


Viewing all 70 articles
Browse latest View live