Thursday, April 28, 2016

Lenovo BIOS Updates in the Task Sequence

The question popped up in a forum the other day about how people handle the upgrade of Lenovo BIOS in a Task Sequence.  There are several ways of course which can be handled, of variable sophistication.  Mikael Nystrom developed a solution for me several years back which I used for several years and enhanced on my own, in MDT Task Sequences.  However when my organization was shifting to SCCM Task Sequencing I was asked to develop something a bit lighter. The old solution kept all the BIOS update files in one very large (500MB+) package.  Clearly not the right solution in SCCM where every package used has to be downloaded from the DP during imaging. 

I moved to a much lighter solution for SCCM. 

Each BIOS revision is kept in its own container package (that's what I call them anyway, a package with no assigned program, just used to hold content for use by something else).  Its basically the same idea as an SCCM Toolkit package, or Settings package.

Creating the BIOS packages:

  1. Go out to Lenovo and download the BIOS for each model for which you want to perform an upgrade during imaging.
  2. Extract the BIOS packages into a structure on your Package content share similar to:
    \\servername\imagecontent$\BIOSpackages\Lenovo\T450-V1.45
    \\servername\imagecontent$\BIOSpackages\Lenovo\T440-V2.08
    \\servername\imagecontent$\BIOSpackages\Lenovo\T430-V2.65
  3. Use the Administrator Console to create one Legacy type package from each of these folders
    (using the example above you'll end up with 3 packages)
  4.  Distribute these packages


Task Sequence Changes:

  1. Someplace after the machine has booted into Windows for the first time place the steps to perform the BIOS upgrades.  Be sure that the you place them after the Use Toolkit and Gather steps. 
  2. Create a new TS Group for the BIOS Updates to nest under, it makes turning the BIOS updates off if needed easier and keeps the TS cleaner
  3. Under the BIOS Updates group create a Run Command Line step for Model to be upgraded
    • The command line in each case will be "Winuptp.exe /S" this is the BIOS update installer for all Lenovo Laptop models and is contained in every BIOS update.  The "/S" tells it to run quietly and automated with new GUI. It will also suppress rebooting. 
    • Add a condition on the step using a WMI query so this step will only run for the proper model
      select * from win32_computersystemproduct where version = "ThinkPad T430"
    • Add a reference to the proper BIOS Package for the model being updated buy this step.
      • I've found it easiest to create the step once the copy it for each model, updating the package reference and the name of the step to reflect the proper model
    • It s a good idea to place a reboot computer step soon after the BIOS updates complete.  Be sure to put Use Toolkit package and Gather steps immediately after the reboot.
    I have exported the BIOS Steps from my Production TS, you should be able to import this open the stub TS, then copy and paste the steps into your own TS.  The Package References will be broken, because I didn't export the content.  My packages have naming and paths in them that I'd prefer not to expose.  You will only need to create the proper packages and update the references if you start with my stub.

    BiosStub


    Tuesday, April 19, 2016

    ZTIOSDNotify.ps1

    Sometime ago I started using Mikael Nystrom's ZTISendmail.ps1.  It was a great script however what I wanted and needed to do in my environment grew over time and I have expanded the script.  I therefore present ZTIOSDNotify.ps1 with much thanks and Credit to Mikael for providing the jumping off point.  

    While nothing was wrong with Mikael's script there was a need to do some additional things.  I was asked to post my results of OSD deployments to Sharepoint, the original script didn't handle SCCM deployments and the generated log files in in a way I liked (didn't give me everything), and I was asked to also post the logs to a network share (this part is actually in the TS and not the script,  but they work together so I'm including all of it)

    I am including links to the Script itself and to an exported SCCM TS with component parts that need to be added to a TS to use the script one Section however requires the SCCM NAA account so I will point out where to add that and how to set it up, since I can't save and export that step without valid details.

    ZTIOSDNotify.ps1

    NotifyTS Parts


    I keep the script in my toolkit package, however it could be a package of its own as well so long as the toolkit package is also loaded since it depends on functionality from the Toolkit package.

    Using the script requires a number of TS Variables (either in CS.ini or the TaskSequence, I actually do some in both places) and some specific setup in the Task Sequence to use all of the functionality.  I will document everything below.

    Task Sequence Variables (Where and how to set):
    Set or create the following TS variables in the Customsettings.ini (or Task Sequence Initialization)


    [Settings]
    Priority=Sendmail, Default
    Properties=OSDSendMailFrom, OSDSendMailToPri, OSDSendMailToSec,  OSDSendMailSMTPServer, OSDSendMailIncludeBDDLog

    [SendMail]
    OSDSendMailFrom=ImagingTeam@domain.com
    OSDSendMailToPri=ImagingTeam@domain.com
    OSDSendMailToSec=OtherPartys@domain.com
    OSDSendMailSMTPServer=smtp1.domain.com


    or
    (if your organization has more than one SMTP Server and you want to route traffic regionally for example)

    [Settings]
    Priority=SetSMTP, Sendmail, Default
    Properties=OSDSendMailFrom, OSDSendMailToPri, OSDSendMailToSec,  OSDSendMailSMTPServer, OSDSendMailIncludeBDDLog

    [SendMail]
    [SendMail]
    OSDSendMailFrom=ImagingTeam@domain.com
    OSDSendMailToPri=ImagingTeam@domain.com
    ;this could be removed from CS.ini and populated in the gather phase to be generated some other way into a list of people to be notified, say the Local IT technicians for the office the machine is being imaged in.
    OSDSendMailToSec=OtherPartys@domain.com
    ;OSDSendMailSMTPServer=smtp1.domain.com

    [SetRegion]
    UserExit=RegionExit.vbs
    OSDRegion=#GetRegion()#


    [SetSMTP]
    ;You will need some sort of Userexit or other code which returns the OSDRegion similar to the reference to RegionExit.vbs above
    Subsection=SMTP-%OSDRegion%

    [SMTP-AMR]
    OSDSendMailSMTPServer=smtp1.domain.com
    [SMTP-EUR]
    OSDSendMailSMTPServer=smtp2.domain.com
    [SMTP-ASP]
    OSDSendMailSMTPServer=smtp3.domain.com

    Set or Create the Following Task Sequence Variables in the Task Sequence Initialization:

    TSVersion  - This is a custom variable I use in my environment which stamps a version of the TS in the log files so the script can reflect which TS and version of it.  My environment has a couple TS in deployment so its good to know which one generated the Logs, Email, SharePoint Post, etc  Its typically set to a Major and a Minor version xx.yy (ex 12.34, 14.22)

    OSDSendMailIncludeBDDLog - Custom Variable a YES/NO Value should the script Capture and send the OSD logs, for SCCM the will cause the SMSTSLOG folder to be zipped up and captured, since the BDD.log doesn't contain everything like MDT.  This Variable instead be set in the Success or Failure sections later to get more control over if the logs should be included or not depending on success or failure

    Logcapture - Custom Variable to indicate under what conditions the results should be emailed, copied to network, posted to sharepoint - Success/Failure/Both

    OSDPostToSharePoint - Custom Variable a YES/NO Value should the script attempt to post the OSD results to a sharepoint site defined in the script. This Variable could instead be set in the Success or Failure sections later to get more control over if the logs should be included or not depending on success or failure

    TestSettings - This has some extended use in my environment, but for the purpose of the script it indicates in the email and postings if the TS was in testing which is a quick reference to those seeing the results if the results should be followed up or not.  Is a YES/NO Value

    LaunchSUI - I use this to trigger the launching of the Service UI Command line for debugging purposes of an image

    Using the Script and Integrating with the TS:

    Two sections are added to the TS to handle success and failure notifications in the TS, they are substantially the same, but need to be located in different places, particularly the Failure sections so it will properly process the Task Sequence Error code.

    For a failed TS:
    By Default a Standard TS includes a section to handle errors, this section should be enhanced adding a number of steps between "Copy Logs" and "Error in the Task Sequence"



    Define the RunFailure Variable Set to YES in this section so the script will know it is handling a TS failure



    For a Successful TS:

    For a successful TS a very similar set of steps needs to be added someplace before your TS successfully exits, keeping in mind that the Toolkit package and Gather step must exist shortly before the Steps run to have all the required information available.  A good place to do this is just before the "Report Done" step, Add a toolkit package reference and Gather step then add the Success section.

    Define the RunFailure Variable set to NO so the Script and TS will know to handle the reporting of status as a Successful TS Run.



    Both Success and Failure require a connection to a network location by the SCCM NAA if the log file copying to a network share functionality will be used, this step is "Connect to Network SCCM Log Folder" it couldn't be exported without including valid account details for a NAA so, I will instead detail how to set it up:

    1. A "Connect to Network Folder" step to the Task Sequence and Name it "Connect to Network SCCM Log Folder"
    2. Create a share on a server in your environment which will receive the files, under that share create a "Failure" and "Success" subfolder
      ex:
      \\logsserver\logsdir$
      \\logsserver\logsdir$\Success
      \\logsserver\logsdir$\Failure
    3. The SCCM NAA Account should have at least "Modify" NTFS Permissions and Read/Write on the Share
    4. In the TS Step Input the path to logsdir$ on the server
    5. make it the "L:" drive
    6. In the Account property add the SCCM NAA and the valid password when prompted
    SharePoint Integration:

    If the TS Variable OSDPostToSharePoint is set to YES, then the functionality to post to SharePoint will be triggered.

    A SharePoint List must be setup to receive the posting information through WEBDAV.  The account the TS is running as needs to have modify permissions to the SharePoint list.

    I have included a screenshot of the Sharepoint list settings.  I'll enhance this section of documentation as needed and as I find time. 


    Basically a SharePoint list needs to be created with the above field names.  The SCCM NAA or MDT Deployment Account needs to have permissions to the list. 

    The URL to the list needs to be added to the ZTIOSDNotify.ps1 script at line 31:
    Replacing the information in the "<>"
    $TeamSiteURL = "http://<site>.<Replace Domain>.com/sites/<Sharepoint Sub Site>"

    Update the List name at line 33:

    $List = "OSD Results"


    Other Notes:

    In the ZTIOSDNotify.ps1 Script there are lines of code which picks up the MODEL TS Variable,  If you are using the ModelAliasExit script in your environment to get more sane and friendly Model Names especially for Lenovo models.  I advise replacing the lines of code in the script with a reference to the MODELALIAS TS variable created by that script to get a sane model name. 

    Line 67:
    Write-Progress -Activity "Sending email" -Status "Got Machine Model $TSEnv:Model" -PercentComplete 55 -Id 1
    Becomes:
    Write-Progress -Activity "Sending email" -Status "Got Machine Model $TSEnv:ModelAlias" -PercentComplete 55 -Id 1

    Line 104:
    Model: $TSEnv:Model<br/>
    Becomes:
    Model: $TSEnv:ModelAlias<br/>

    Line 124:
    Model: $TSEnv:Model<br/>
    Becomes:
    Model: $TSEnv:ModelAlias<br/>


    Monday, April 4, 2016

    ModelAlias Exit and Lenovo Machines

    Long time users of MDT will most likely be aware of the ModelAliasExit.vbs script. 

    The Deployment Bunny has several articles on the script and download links to the script:

    Deployment Bunny

    There have been several updates to the script in it's lifetime.  However it seems that the definitive version of the script has been frozen at 1.0.4 for a few years now.  However this version has a serious issue in IMHO when it comes to Lenovo Models.  Between the 1.0.3 and 1.0.4 versions of the script line 143 was commented out.  This has the effect of not pulling the friendly model name for Lenovo machines.  It more or less forces the user MDT Admin using it to have to create an aliasing table for Lenovo models by hand.  

    I am not one to generally second guess the creators of such scripts.  However I truly do not understand the logic of what was done.  However every time someone mentions the script I feel the need to make mention of the problem with Lenovo models. 

    So let this post serve two purposes:

    1. Give me someplace where I've already documented the problem to point people to when I see such mentions of the script.

    2. Provide a location they can get what I consider to be a corrected version of the script.
    ModelAliasExit 1.0.5


    Thursday, March 3, 2016

    Quick and Easy MDT DB Clean UP

    For a while now I've been searching for a way to cleanup the 30,000 or so records that I just didn't need in my MDT database. I finally realized that Michael Niehaus MDT PowerShell Module held the answer with a little use of some Piping:

    Import-Module M:\MDTDB\MDTDB.psm1...
    Get-MDTComputer | Select-Object -Property ID,OSInstall | Where OSInstall -eq NO | Remove-MDTComputer


    In our environment we control if a machine can be imaged or not by setting and looking for the OSInstall Value in the DB. We have a Web front end to enter machines into the DB, and if the machine is valid for imaging (we check against a few data sources to detiremine this, sepecial cases require my team to manualy flip the vlaue to YES after we do further validation)Therefore I know if a Machine is set to OSInstall = NO that it has already been imaged. Therefore I was able to find all the DB records for machines that are currently NO and delete them with the above commandline in Powershell after importing the module.

    The second selected property to detiremine what machines to select out and the pipe to Remove-MDTComputer can be any value contained in the record for that computer in the database.

    Tuesday, February 9, 2016

    Move the MDT Progress Bar out of the way

    Sometime ago I had a problem with a dialog I was creating in my Task Sequences being covered up  by the Task Sequence Progress bar.  Back then I was able to find a simple AutoIT script which would automatically move the Progress bar out of the way.

    Alas as with many things on the internet it has disappeared from the Net, plenty of pointers to the script. However the location of the actual script no longer exists.  So having a copy I thought I'd do the world a favor and give it a new home.

    Progressmove.au3:

    #NoTrayIcon
    #Region ;**** Directives created by AutoIt3Wrapper_GUI ****
    #AutoIt3Wrapper_Compile_Both=y
    #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
    ;zCFG-MoveTaskWindow
    ;Version 2.0 March 2008
    ;Reruns itself and returns - only works when compiled
    If $CmdLine[0] = 0 Then
        ; Rerun ourself and let this copy return to the task sequencer
        Run('"' & @AutoItExe & '" rerun')
        Exit
    EndIf
    Sleep(5000)        ; Time for the first script to return
    If WinExists("Installation Progress") Then
        $size = WinGetPos("Installation Progress")
        Mousemove($size[0]+50, $size[1]+50)
        MouseClick("left")
        WinMove("Installation Progress", "", 0, 0)
        Exit
    Else
        Exit
    EndIf

    I claim no rights or authorship to the script, just trying to help out since the original location seems to have disappeared.

    Tuesday, October 20, 2015

    Branding Image Version in Registry using TASKSEQUENCEVERSION TS Variable

    For sometime now I have been branding my image versions into the registry by leveraging the TASKSEQUENCEVERSION Task Sequence Variable.  This variable contains the value set as the Task Sequence Version in the Task Sequence Properties in the MDT Workbench.  I also setup a registry entry which will display the Image Version in the right click context menu when any folder on a deployed machine with that image is clicked.  It popped up in a forum today that a fellow Imaging architect was looking to do something similar here is my solution.
     
    First here is a link to my script to do the work:
     
    The script was created using ZTITemplate.wsf so functions as a standard script in MDT generating entries in BDD.Log and in its own log.  It was originally created in BDD 2007 and has continued to work through all versions up to and including MDT 2013 Update 1.
     
    The script does a number of things for me beyond the image version stamping however here are the relevant things to do to get the image version functionality:
     
    1. Place in the "Scripts" directory of the MDT Deployment share you use to build the image
    2. Edit the script Define the "MyCompany" variable on line 81
    3. Set the Task Sequence Version to whatever is Sensible for your Environment in the Task Sequence Properties for the Task Sequence that builds the Image in the MDT Workbench (see Screenshot1 and Screenshot2)
    4. Add a Run Commandline Step to the Task Sequence to Call the Script to be run as part of the build Task Sequence the Logical place for this is under "Custom Tasks" (See Screenshot3)
    5. Build Your Image
     
    Further Explanation:
     
    1. Line 79 of the script gets the value of the Task Sequence variable "TASKSEQUENCEVERSION" and stores it in the VBScript Variable "buildversion" for later use
    2. The code block at line 100 makes use the "buildversion" variable to build a registry entry which adds the Image Version String defined as the Task Sequence Version to the context menu when a Folder is right clicked (See Screenshot4) 
      Note: We call our Images the Standard Client, Thus the SC Notation prepended at line 102, its safe to take that out if you don't want that in your Image
    3. The code block at line 105 stamps the Version information into the registry in an easily collectable registry hive.  The location referenced existed at my company before I was hired and took over imaging so that is what we have continued to use as a standard location to collect image information, We put a lot more there.  The location predates the use of MDT at the company which I introduced when I arrived otherwise I'd have put all the info in "Deployment 4".  The referenced registry path (Line 106) could easily be updated to place the information in the standard location
      regPath = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Deployment 4\ImageVersion"
    4. Finally the Code Block at line 224 defines a Function which is used to perform each write to the registry so its done in a standard and logged manner

    Screenshots:
    Screenshot1

    Screenshot2

    Screenshot3

    Screenshot4







      
    




    


    Thursday, March 5, 2015

    Adding SCCM 2012 Client CU Patches, A Different Approach

    The Update of the Client in the TS is challenging....

    I've been working on the problem of how to patch the Configuration Manager Client Up to the Currnet CU level deployed in my infrastructure since we first rolled out SCCM 2012 RTM a couple years ago. In that time I have tried a couple of approaches and followed the various blogs which typically come down to the use of the PATCH public property of the Client .MSI.

    However this has met with varying degrees of success and several problems in my environment.

    I want to start by saying I have been informed by a couple of reliable sources that the PATCH property isn't actually recommended, supported, or really even reliably tested by Microsoft.  So I suppose any use of it is best effort, and if it works "lucky you".

    That said...I DON'T use it.

    Why?

    The PATCH property only "sort of" works.

    What does sort of mean:
    1. The pathing for it can be tricky, using variables in the path as some articles point out can be tricky, or just plain not work.
    2. I've seen problems with using it when deploying on machines with more than one drive. The system will throw the files on the secondary drive when it goes to apply the patch and then the Client install bombs out entirely because it can't find the patch files.
     So What do I do to get the Client Patched during OSD deployment:

    To get the Client Patched I've gone a bit "Old School" and approached it as a true patch install, I arrived here by sitting at my desk one day, and thinking "Well its .MSP" so shouldn't I be able to use it like any other .MSP and install it with "MSIEXEC /P"

    I removed the PATCH property from my Client install command line, and tried the patch install as a separate "Run Command" step and after a little trial and error got it working, I haven't looked back since.

    Up front warning, since I have personally chosen to avoid any use of variables my syntax assumes that the system drive and therefore the drive the Task Sequence is running from is C: if this isn't true of your OSD setup then YMMV.

    1. Create a new Copy of the Client Install package
    2. Put a Patch folder under this with an X86 and a X64 subfolder...basically the same as articles about using the PATCH property
    3. Put the SCCM Client patch or patches (CU3 needed a couple of hotfixes in addition to the one to patch things up to CU3)
    4. Set this up a Old Style Package in Config Manager, Mine ends up being package ID PS100540...distribute this.
    5. Make this package the package used by the client install step.
    6. After the Client Install Step in the TS add a reboot step
    7. Create a Run Command line step in the TS and apply the Client Patch for the current CU with a "MSIEXEC /P" command line.
      ex..."msiexec /p C:\_SMSTaskSequence\OSD\PS100540\Patch\x64\configmgr2012ac-r2-kb2994331-x64.msp /qn REBOOT=R"
    8. Add another Reboot Step
    9. Add similar patching steps followed by a reboot step for each Client Hotfix