SCCM 2012 OSD Driver Management – Advanced Tips

I’ve got a few tips for working with OSD drivers in SCCM. Here we go:

Finding the Model Name in WinPE

In task sequence actions, I use a WMI filter to target my ‘Apply Driver Package’ actions. Sometimes the target device is new and doesn’t have an OS yet. Since WinPE doesn’t run powershell, I can’t use my regular command to find the model.

Instead, try this. It’ll return the model.

wmic computersystem get model

Testing the Driver Package for Completion

Sure, you can wait until the OS is fully deployed, then run control panel -> system -> device manager, etc. You can also do this _during_ the task sequence :).

Anytime after the step named ‘Setup Windows and ConfigMgr’, press F8 to launch the command prompt, and then run the following command.

mmc devmgmt.msc

Driver Source Folder Organization

When importing new drivers, there’s a couple things to keep in mind.

  1. Keep your drivers organized. Create subfolders for the driver classes (model\net, model\sata, model\audio, model\graphics, etc.).
  2. Don’t put .exe files or .zip files in the driver source folders.
  3. If you extract an .exe or .zip file into the driver source folder, and the extracted contents don’t contain .inf files (autorun.inf doesn’t count), then delete that driver and try to work without it. Only drivers with .inf files are imported. If your driver doesn’t have any .inf files, you’ll need to treat it like you would an application or package.

SCCM Vendor Plugins

Look into the Dell DCIP and Lenovo Thin Installer. They can automate a lot of the driver\bios work.

SCCM 2012 – Importing and Managing Drivers for OSD

There are two main sets of drivers to worry about. WinPE drivers, and the target OS drivers. If your computer can’t boot WinPE, or WinPE can’t talk to the disk or network card, not much will get done. Conversely if WinPE lays down an image and reboots to it and the OS doesn’t have disk or network drivers, any subsequent task sequence steps will fail because your PC won’t be able to contact the SCCM server.

Here’s how to manage drivers in SCCM:

Driver Organization

We need two folders: first, a place to put drivers downloaded from the OEM’s website and second, a place for SCCM to store it’s driver databases (called ‘Driver Packages’).

I created the following folder structure on my SCCM site server:

  • source$\
    • driversource
    • driverpackages
    • applications
    • images
    • ossource
    • …etc

Driversource is where we will put downloaded OS drivers. For example:

  • source$\driversource\
    • Win7\
      • Dell Optiplex 9010
        • <a bunch of folders, INF files, etc.>
      • Dell Optiplex 990
        • <a bunch of folders, INF files, etc.>
      • Lenovo X1C
        • <a bunch of folders, INF files, etc.>
    • WinXP\
      • HP xw4300
        • <a bunch of folders, INF files, etc.>
      • HP xw4600
        • <a bunch of folders, INF files, etc.>

Driverpackages is a folder that SCCM will manage. Messing with stuff in this folder will break things. SCCM will make folders subfolders with GUID’s for each driver included in the package.

In the following example folder structure, I would have created the source$ share, the driverpackages folder, the OS folders, and the make\model folders. However, SCCM creates and manages the GUID-named folders.

  • source$\driverpackages
    • Win7
      • Dell Optiplex 9010
        • {idsfbsg-srgsrtg-4564w65mklsfsfgs}
    • WinXP
      • Dell Optiplex 990
        • {83453q-efsdfgsgs-45545yerthdfgssdfg}

Step-By-Step – OS Drivers

  1. Create a folder in .\source$\driverpackages\<os>\<model>.
  2. Create a folder in .\source$\driversource\<os>\<model>.
  3. Download the OEM drivers, extract them, and put the extracted files in the .\driversource\… folder.
  4. Open SCCM Console -> Software Library -> Operating Systems -> Drivers.
  5. Right-click ‘Drivers’ and choose ‘Import Driver’.
  6. On the ‘Locate Driver’ screen, enter the unc of your downloaded source drivers. This should look like: \\sccm-server\source$\driversource\<os>\<model>.
  7. On the ‘Driver Details’ screen, add a category to make it easier to clean up after bad or accidental imports later. I always use the Make + Model + OS (ex: “Dell Optiplex 9010 Win7”).
  8. On the ‘Add Driver to Driver Packages’ screen, click ‘New Package’.
  9. On the ‘Create Driver Package’ screen, enter a name and path. The name of the driver package should match the category for clarity. The path of the driver package should be the folder .\source$\driverpackages\<os>\<model> created in a previous step.
  10. On the ‘Add Driver to Boot Images’ screen, do not choose to add any drivers to the boot image at this time.
  11. Finish the import wizard. It will take some time for the drivers to finish importing.

Step-By-Step – Boot Image Drivers

Next, we need to add the network and sata drivers to the boot images so that WinPE can access the HDD and NIC. Without this step, it’s likely that WinPE will attempt to load then immediately reboot because it cannot reach the SCCM server.

  1. Navigate to SCCM Console -> Software Library -> Operating Systems -> Driver Packages.
  2. Right-click your new driver package and choose ‘Show Members’.
  3. Right-click the headers of the viewing pane (The bar showing column names like “Icon”, “Name”, “Provider”, etc.) and add the ‘Content Source Path’ field.
  4. Sort the list by driver ‘class’, then highlight all drivers with the classes ‘SCSIAdapter’, ‘Net’, and ‘hdc’, but only those which are for the x86 architecture. You can usually tell the architecture by the content source path.
  5. Right-click the highlighted drivers -> Edit -> Boot Images.
  6. Add your selected drivers to the x86 boot images listed. Be careful, because adding x86 drivers to an x64 boot image, or vice versa can break the boot image. Also, ensure that the checkbox labeled ‘Update the distribution points’ is checked before hitting ‘OK’.

Now, you should be able to PXE boot your target computer. You can verify that the nic drivers work by pressing F8 in WinPE to open a command prompt, then trying to ping an ip address. To verify disk drivers, in the WinPE command prompt run the command ‘diskpart’ then enter ‘List Disk’.

Step-By-Step for Win7+

Next, we need to get the OS drivers into the task sequence.

First, we need to find out what your target computer thinks it’s model name is.

  1. Open PowerShell on the target system.
  2. Execute the following command, and copy down the answer somewhere safe. We need the response that this command gives to properly form the WMI query in the Task Sequence.
    (gwmi win32_ComputerSystem).Model

Next, let’s actually edit the task sequence.

  1. Navigate to SCCM Console -> Software Library -> Operating Systems -> Task Sequences.
  2. Right-click your desired task sequence and choose ‘Edit’.
  3. Select a position after ‘Apply OS Image’ but before ‘Setup Windows and ConfigMgr’ and choose Add -> Drivers -> Apply Driver Package.
  4. On the new TS action, click ‘Browse’ and select the driver package that was just created in the previous section.
  5. Click the ‘Options’ tab of the new TS action.
  6. Click ‘Add Condition’ -> Query WMI.
  7. On the ‘WMI Query Properties’ screen, add the following WMI query. Replace the words ‘Latitude e4300’ from the example query below with the output of the GWMI command in powershell from a previous step. The quotes and % sign should -stay in- the query.
    select * from Win32_ComputerSystem where Model like "Latitude e4300%"
  8. Click OK to close the TS Edit Window and save the TS.
  9. Right-click the TS and choose, ‘Distribute Content’, then complete the wizard to distribute the driver package to your distribution points.

For Win7, you should now be good to go! For XP, there are a couple more steps.

Step-By-Step for WinXP

XP Requires 3 sets of drivers: WinPE, OS Drivers, and OS Mass Storage drivers. The above steps will walk you through completing WinPE and OS Drivers. The subsequent steps will cover mass storage drivers.

  1. Follow the instructions for the WinPE and Win7 sections, then come back here.
  2. Complete the instructions at the following blog post. It is an excellent write-up of the process for finding the correct mass-storage driver and including it in the task sequence. Identifying Windows XP Mass Storage Drivers in Windows PE with Devcon

And that’s it! Good luck out there.

Installing All Software Updates in a XP in Build and Capture TS

I had a hell of a time getting software updates to work in an XP Build and Capture Task Sequence. Things would work okay if I used ZTIUpdates, but not the ‘Install Software Updates’ TS action. A lot of people online seem to have given up, but I think I found the keys to getting things going.

The Problem

When you run an XP Task Sequence with ‘Install Software Updates’, the updates don’t actually install.

The Cause

  1. SCCM can’t scan with the XP SP3 default WUAgent because it’s too old.
  2. SCCM can’t scan for updates with IE 6 installed, which is the XP SP3 default.
  3. SCCM can’t scan for updates without the WSUS patch KB898461 installed.
  4. SCCM can’t download updates with XP SP3 unless joined to the domain.
  5. SCCM can’t communicate with the client once joined to the domain unless the XP certificate hotfix is installed.
  6. Once a software scan action is completed with the ‘install Software Updates’ step, subsequent updates are not detected because it doesn’t re-scan for new updates after every set of updates is installed.

We’ll resolve these issues below.

The Fix

Packages and Prep

This post assumes that you have MDT Integrated and can use the ZTIWindowsUpdates script.

  1. Download the IE 7 installer here: Windows Internet Explorer 7 for Windows XP.
  2. Make a package for the IE7 installer using the following command-line action.
    IE7-WindowsXP-x86-enu.exe /NoRestart /NoBackup /UpDate-No /Quiet
  3. Download the WUAgent 7.4 Installer here: Windows Update Agent 7.4.7600.226. I found the link here: Forum Post – Windows Update Agent.
  4. Create a package for the WUAgent 7.4.7600.226 installer using the following command-line action.
    WindowsUpdateAgent30-x86.exe /quiet /norestart /wuforce
  5. Download the Windows XP Certificate Enrollment hotfix here: Windows Server 2003 and Windows XP clients cannot obtain certificates
  6. Create a package for the hotfix using the following command-line action.
    WindowsXP-KB968730-x86-ENU.exe /quiet

Task Sequence Changes

  1. Open the XP Build and Capture Task Sequence.
  2. On the ‘apply network settings’ action, join a workgroup instead of a domain.
  3. Directly after the ‘Setup Windows and ConfigMgr Step’, add ‘Install Package’ actions for IE 7, WUAgent 7.4, then the Certificate Hotfix.
  4. Next, right after the certificate hotfix install, add join domain and reboot actions.
  5. Next, add a ‘set task sequence variable’ action with the variable ‘WSUSServer’ set to your site server’s WSUS URL (ex: https://sccm.domain.local:8531″).
  6. Next, add the ‘Use Toolkit Package’ and ‘ZTIUpdates’ steps. This will install the WSUS patch and update WUAgent to the latest version.
  7. Next, create an ‘Install Software Updates’ action.
  8. After that, create a new ‘Run Command-Line Action’ with the following command. This will re-scan for new updates.
    WMIC /namespace:\\root\ccm path sms_client CALL TriggerSchedule "{00000000-0000-0000-0000-000000000113}" /NOINTERACTIVE
  9. Repeat the Install Software Updates and Re-Scan command line actions. This will ensure that all updates are installed, since each Install Software Updates action is hard-coded to time out after 30mins.

Here’s a screenshot of my final task sequence.

XPBuildAndCapUpdates

Enjoy!

[SCCM 2012] XP Task Sequence – Removing Windows Tour, MSN, etc.

We have an XP Task Sequence for a couple of really old applications. Here’s how I pull some of the older and unused features out with my build and capture task sequence.

The Goal

Remove the following features from an XP Deploy.

  • MSN Messenger
  • MSN Exploder
  • Windows Tour
  • Outlook Express

The Process

Unattend.txt and the Build and Capture

  1. Create a file named unattend.txt with the following contents, place it in a package, and distribute the package to your distribution points.
    [Components]
    msnexplr=off
    oeaccess=off
    zonegames=off
    msmsgs=off
  2. Check this list to remove any other features you don’t want.
    XP Components
  3. Edit your XP Build and Capture Task Sequence, and choose to use the unattend.txt file \ package created in step 1.
  4. Run the Build and Capture to pull an image without Outlook Express or MSN.

The Deploy

  1. Create a batch file named remove-windowstour.cmd with the following contents, place it in a package, and distribute the package to your distribution points

    REM Loading Default User's HKCU hive
    REG LOAD HKLM\temp "C:\Documents and Settings\Default User\NTUser.Dat"
    
    REM Adding Config-NewUser.cmd to default user's HKCU\Runonce
    REG IMPORT Remove-WindowsTour.reg
    
    REM Unloading Default User's HKCU hive
    REG UNLOAD HKLM\Temp
  2. Create a reg file named remove-windowstour.reg with the following contents, place it in the same package as remove-windowstour.cmd, and update the distribution points.
    Windows Registry Editor Version 5.00
    
    [HKEY_LOCAL_MACHINE\temp\Software\Microsoft\Windows\CurrentVersion\Applets\Tour]
    "RunCount"=dword:00000000
    
  3. Add a ‘Run Command-Line Action’ in your task sequence to run the batch file.
  4. Test the task sequence. It shouldn’t ask to run the Tour, and shouldn’t show the features we removed.

Technically, Outlook Express and Windows Tour aren’t ‘removed’, they’re just hidden. I’m okay with this though.

[SCCM 2012] Task Sequence Hangs on Install Package During OSD (part 2)

So, in my previous post on the issue, I described a complicated series of hotfixes and WMI rebuild scripts which fix this serious issue. After a whole lot of trial and error, I recently found an easier workaround.

The Problem

Task sequences hang indefinitely on the ‘Install Package’ task sequence action.

The Solution

  1. In the ‘Apply Network Settings’ action, join a workgroup instead of a domain.
  2. Add a ‘Join Domain’ action later in the task sequence, but before any ‘Install Software Updates’ actions.

I have no idea why this works :(. However, it really does seem to work for me at least. Yay!

 

 

SCCM 2012 – Optimizing Dell CCTK OSD Actions into WinPE

We wanted all of our CCTK actions to happen before the disk gets partitioned. To do this, everything needs wrapped into WinPE. This involves some customization of our various scripts, cctk package folder structures, and boot images. On the plus side, the actions all run much quicker since there’s no need to download a full CCTK package on every step.

The Parts

  1. Folder Structure and CCTK Files
  2. Supporting Files
  3. Modifying the Supporting Files
  4. Making the WinPE Changes
  5. Making the TS Changes

Folder Structure and CCTK Files

  1. On your site server, create the following folder structure:
     * C:\Program Files\Microsoft Configuration Manager\OSD\Extras\CCTK32
     * C:\Program Files\Microsoft Configuration Manager\OSD\Extras\CCTK32\HAPI
     * C:\Program Files\Microsoft Configuration Manager\OSD\Extras\CCTK64
     * C:\Program Files\Microsoft Configuration Manager\OSD\Extras\CCTK64\HAPI
     * C:\Program Files\Microsoft Configuration Manager\OSD\Extras\CCTKShared
  2. Place the CCTK executable and HAPI drivers in their respective locations from the previous step.

Supporting Files

  1. Using the instructions in the following blog post, create the following files and place them in .\CCTKShared.
  2. SCCM 2012 – Generic Multi-Platform Dell CCTK BIOS Settings
    1. Dell-CustomSettings.cctk
    2. CCTK-Generic.cmd
    3. Show-CCTKErrors.vbs
  3. Using the instructions in the following blog post, create the following file and place it in .\CCTKShared.
    SCCM 2012 – Testing for Dell TPM Activation in a Task Sequence

    1. Check-TPMActivation.vbs

Modifying the Supporting Files

Some of the script files need modified since we will no longer be using the cctk.cmd wrapper to select the appropriate cctk executable for the running architecture. Instead, we will only include the 32-bit cctk on the 32-bit WinPE, and vice-versa.

CCTK-Generic.cmd

In this file, make the following changes.

  1. Remove lines 16 through 29 since we don’t need to select architecture.
  2. Replace all instances of “%CCTKPath%\”  with “%~dp0”. See this example:
    %CCTKPath%\cctk.exe --tpmactivation=activate !ARG1! !ARG2!
    --should turn into--
    %~dp0cctk.exe --tpmactivation=activate !ARG1! !ARG2!
    
  3. Before every instance of Show-CCTKErrors.vbs, add “%~dp0”. For example:
    cscript.exe //nologo Show-CCTKErrors.vbs %errorlevel%
    --should turn into--
    cscript.exe //nologo %~dp0Show-CCTKErrors.vbs %errorlevel%
    

check-tpmactivation.vbs

In this file, make the following changes:

  1. Replace all instances of ‘cctk.cmd’ with ‘cctk.exe’.
  2. Delete line 23 (strPath) and replace it with the following code:
    strPath = Wscript.ScriptFullName
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    Set objFile = objFSO.GetFile(strPath)
    strPath = objFSO.GetParentFolderName(objFile)

HAPIInstall.cmd

Replace this entire file with the following code:

@echo off
%~dp0hapi\hapint.exe -i -k C-C-T-K -p "hapint.exe"

Making the WinPE Changes

  1. Open the following file from your site server in a decent editor: “C:\Program Files\Microsoft Configuration Manager\bin\x64\osdinjection.xml”.
  2. Find the section for i386\SCCM, and add the following lines of code:
    <File name="hapint.exe">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK32\HAPI</Source>
            <Destination>windows\system32\HAPI</Destination>
    	  </File>
    	  <File name="dcmdev32.exe">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK32\HAPI</Source>
            <Destination>windows\system32\HAPI</Destination>
    	  </File>
    	  <File name="dchipm32.dll">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK32\HAPI</Source>
            <Destination>windows\system32\HAPI</Destination>
    	  </File>
    	  <File name="dchcfg32.exe">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK32\HAPI</Source>
            <Destination>windows\system32\HAPI</Destination>
    	  </File>
    	  <File name="dchbas32.dll">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK32\HAPI</Source>
            <Destination>windows\system32\HAPI</Destination>
    	  </File>
    	  <File name="dchapi32.dll">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK32\HAPI</Source>
            <Destination>windows\system32\HAPI</Destination>
    	  </File>
    	  <File name="dcdbas32.sys">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK32\HAPI</Source>
            <Destination>windows\system32\HAPI</Destination>
    	  </File>
    	  <File name="dcdbas32.inf">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK32\HAPI</Source>
            <Destination>windows\system32\HAPI</Destination>
    	  </File>
    	  <File name="dcdbas32.cat">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK32\HAPI</Source>
            <Destination>windows\system32\HAPI</Destination>
    	  </File>
    	  <File name="pci.ids">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK32</Source>
            <Destination>windows\system32</Destination>
    	  </File>
    	  <File name="CCTK.exe">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK32</Source>
            <Destination>windows\system32</Destination>
    	  </File>
    	  <File name="mxml1.dll">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK32</Source>
            <Destination>windows\system32</Destination>
    	  </File>
    	  <File name="show-cctkerrors.vbs">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTKShared</Source>
            <Destination>windows\system32</Destination>
    	  </File>
    	  <File name="dell-customsettings.cctk">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTKShared</Source>
            <Destination>windows\system32</Destination>
    	  </File>
    	  <File name="HAPIInstall.cmd">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTKShared</Source>
            <Destination>windows\system32</Destination>
    	  </File>
    	  <File name="check-tpmactivation.vbs">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTKShared</Source>
            <Destination>windows\system32</Destination>
    	  </File>
    	  <File name="CCTK-Generic.cmd">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTKShared</Source>
            <Destination>windows\system32</Destination>
    	  </File>
  3. Find the section for x64\SCCM, and add the following lines of code:
    <File name="hapint.exe">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK64\HAPI</Source>
            <Destination>windows\system32\HAPI</Destination>
    	  </File>
    	  <File name="dcmdev32.exe">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK64\HAPI</Source>
            <Destination>windows\system32\HAPI</Destination>
    	  </File>
    	  <File name="dchipm32.dll">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK64\HAPI</Source>
            <Destination>windows\system32\HAPI</Destination>
    	  </File>
    	  <File name="dchcfg32.exe">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK64\HAPI</Source>
            <Destination>windows\system32\HAPI</Destination>
    	  </File>
    	  <File name="dchbas32.dll">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK64\HAPI</Source>
            <Destination>windows\system32\HAPI</Destination>
    	  </File>
    	  <File name="dchapi32.dll">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK64\HAPI</Source>
            <Destination>windows\system32\HAPI</Destination>
    	  </File>
    	  <File name="dcdbas32.sys">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK64\HAPI</Source>
            <Destination>windows\system32\HAPI</Destination>
    	  </File>
    	  <File name="dcdbas32.inf">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK64\HAPI</Source>
            <Destination>windows\system32\HAPI</Destination>
    	  </File>
    	  <File name="dcdbas32.cat">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK64\HAPI</Source>
            <Destination>windows\system32\HAPI</Destination>
    	  </File>
    	  <File name="pci.ids">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK64</Source>
            <Destination>windows\system32</Destination>
    	  </File>
    	  <File name="CCTK.exe">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK64</Source>
            <Destination>windows\system32</Destination>
    	  </File>
    	  <File name="mxml1.dll">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTK64</Source>
            <Destination>windows\system32</Destination>
    	  </File>
    	  <File name="show-cctkerrors.vbs">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTKShared</Source>
            <Destination>windows\system32</Destination>
    	  </File>
    	  <File name="dell-customsettings.cctk">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTKShared</Source>
            <Destination>windows\system32</Destination>
    	  </File>
    	  <File name="HAPIInstall.cmd">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTKShared</Source>
            <Destination>windows\system32</Destination>
    	  </File>
    	  <File name="check-tpmactivation.vbs">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTKShared</Source>
            <Destination>windows\system32</Destination>
    	  </File>
    	  <File name="CCTK-Generic.cmd">
            <LocaleNeeded>false</LocaleNeeded>
            <Source>extra\CCTKShared</Source>
            <Destination>windows\system32</Destination>
    	  </File>
  4. Update the distribution points of your boot image. If this fails, double-check that all the files added to osdinjection.xml actually exist.

Making the TS Changes

Now that all the leg-work is done; let’s use it!

  1. Open your task sequence, and create the following actions.
    1. Name: Install Dell HAPI Drivers
      Command: X:\Windows\System32\HAPIInstall.cmd
      Package: None
    2. Name: Check TPM Activation
      Command: X:\Windows\System32\Check-TPMActivation.vbs warnonly
      Package: None
    3. Name: Set Default Dell BIOS Settings
      Command: X:\Windows\System32\CCTK-Generic.cmd
      Package: None
    4. Name: Reboot (HD)
    5. Name: Check TPM Activation (force)
      Command: X:\Windows\System32\Check-TPMActivation.vbs
      Package: None

You should now be in business!

SCCM 2012 – Testing for Dell TPM Activation in a Task Sequence

We want our task sequences to fail as early as possible if there’s going to be a problem. One thing we’ve noticed is that if the TPM fails to activate, the task sequence will eventually fail on the ‘Enable Bitlocker’ step. What ends up happening is that the TS fails, reboots, and the system looks completely normal except that Bitlocker isn’t enabled. Our help desk ended up sending out a few machines like this, which had to be found and encrypted after the fact.

Here’s how to test for TPM actication and fail the task sequence.

  1. Create a CCTK Package using the instructions on my previous post: SCCM 2012 – Architecture Agnostic Dell CCTK WinPE Bios Package.
  2. Using the same instructions, create a TS action to install the Dell HAPI drivers.
  3. Optionally, use the instructions on my previous post to create a generic bios settings template: SCCM 2012 – Generic Multi-Platform Dell CCTK BIOS Settings.
  4. Save the following file as ‘check-tpmactivation.vbs’ in your dell-cctk package.
    'if argument 'warn', set bFailIfDeactivated = True
    'if argument 'fail', set bFailIfDeactivated = True
    Dim bWarnOnly, bArgOK, mainArg, iExitcode
    iExitcode = 0
    bArgOK = vbFalse
    bWarnOnly = vbFalse
    If WScript.Arguments.Count = 1 Then
    	mainArg = Wscript.Arguments(0)
    	If mainArg = "warnonly" Then
    		bArgOK = vbTrue
    		bWarnOnly = vbTrue
    	End If
    ElseIf Wscript.Arguments.Count = 0 Then
    	bArgOK = vbTrue
    	bWarnOnly = vbFalse
    Else
    	bArgOK = vbFalse
    End If
    
    Dim msg, cmd, text, objShell, strPath, action
    If bArgOK = vbTrue Then
    	Set objShell = CreateObject("Wscript.Shell")
    	strPath = objShell.CurrentDirectory
    
    	'ref: http://stackoverflow.com/questions/5690134/running-command-line-silently-with-vbscript-and-getting-output
    	cmd = "cmd /c " & strPath & "\cctk.cmd --tpmactivation > " & strPath & "\tpmout.txt"
    	'wscript.echo cmd
    	action = objShell.Run(cmd, 0, True)
    
    	'parse result
    	Set fso  = CreateObject("Scripting.FileSystemObject")
    	Set file = fso.OpenTextFile((strPath & "\tpmout.txt"), 1)
    	text = file.ReadAll
    	file.Close
    
    	'if 'deactivated' then act
    	If InStr(text,"deactivated") Then
    		If bWarnOnly = True Then
    			msg = "Warning! This system's TPM is deactivated. The task sequence will now attempt to enable the TPM then reboot. If this attempt fails, the task sequence will fail. I recommend entering the BIOS after clicking OK and enabling the TPM manually."
    			msgbox msg
    			iExitcode = 0
    		Else
    			msg = "Warning! This task sequence is failing because the TPM is deactivated and the task sequence was not able to enable it automatically."
    			msgbox msg
    			iExitcode = 1
    		End If
    	End If
    Else
    	msg = "Arguments invalid."
    	iExitcode = 1
    End If
    
    Wscript.Quit iExitcode
  5. Create a ‘run command-line’ action after the Install HAPI Drivers action, linked to the dell-cctk package, with the following command.
    check-tpmactivation.vbs

Now, the task sequence will throw a message box if the TPM is deactivated, and fail the task sequence. I recommend duplicating this task sequence action and placing one of the duplicates before your automated attempt to enable the TPM, with the following modified command:

check-tpmactivation.vbs warnonly

This will throw a different message box suggesting that the user manually check the BIOS setting during the next reboot.

Have fun!

SCCM 2012 – Generic Multi-Platform Dell CCTK BIOS Settings

This is a quick overview of how to create a default BIOS settings template that can be pushed to all Optiplex, Latitude, and Precision rebuilds. Also, it’s possible to try progressively better RAID settings in order to leave systems at the maximum potential that their BIOS offers.

Creating the CCTK Package

Please see the instructions in my previous post SCCM 2012 – Architecture Agnostic Dell CCTK WinPE Bios Package for creating the basic CCTK package. We will use this as the base, and then add a few files to it.

Creating a Template File

Here’s the template file we use. Save this as ‘Dell-CustomSettings.cctk’ in your cctk package directory. Here’s the full command-line reference: Dell CCTK Documentation.

[cctk]
chasintrusion=silentenable
bootorder=legacytype,+embnic,+hdd,+floppy,+usbdev,+cdrom
cpucore=all
cpuxdsupport=enable
embnic1=on
cstatesctrl=enable
energystarlogo=enable
fanctrlovrd=disable
integratedaudio=enable
limitcpuidvalue=off
logicproc=enable
fastboot=minimal
serial1=com1
multicpucore=enable
lptmode=disable
serrdmimsg=on
pcislots=enable
postf12key=enable
smarterrors=enable
standbystate=s3
tpm=on
tpmactivation=activate
trustexecution=on
usbctl=enable
usbportsfront=enable
usbreardual=on
usbrearquad=on
virtualization=enable
vtfordirectio=on
usbemu=enable
turbomode=enable
esataports=enable
multidisplay=enable
speedstep=automatic

Creating a CCTK Response Parse Script

This script will take the DOS errorlevel returned by CCTK, and echo out the respective human-readable error message. This message will show up in your smsts.log and on the site server’s status message logs. It’s very helpful for diagnosing bios task sequence errors.

Save the file as ‘show-cctkerrors.vbs’

'Show-Errors.vbs
'johnpuskar@gmail.com
'windowsmasher.wordpress.com

'This script maps dos %errorlevel% into a human readable error from the dell CCTK utilities, and write it to the screen.

Dim arrMessages(254)
arrMessages(0) = "Success."
arrMessages(1) = "Attempt to read write-only parameter '%s'."
arrMessages(2) = "Password cannot exceed 16 characters."
arrMessages(3) = "A BMC was either not detected or is not supported."
arrMessages(4) = "This username is already in use. Enter a unique username."
arrMessages(5) = "Access mode not supported."
arrMessages(6) = "Cannot return number of requested data bytes."
arrMessages(7) = "User ID 1 cannot be assigned a username."
arrMessages(8) = "Cannot execute duplicated request."
arrMessages(9) = "There was an error clearing the SEL."
arrMessages(10) = "Clear SEL cannot be accompanied with any other option."
arrMessages(11) = "racreset cannot be accompanied with any other option."
arrMessages(12) = "Cannot execute command. Command, or request parameter(s), not supported in present state."
arrMessages(13) = "Command not supported on given channel."
arrMessages(14) = "The community string may only contain printable ASCII characters."
arrMessages(15) = "Destination unavailable. Cannot deliver request to selected destination."
arrMessages(16) = "Cannot execute command. Insufficient privilege level."
arrMessages(17) = "Command illegal for specified sensor or record type."
arrMessages(18) = "Invalid commstring value."
arrMessages(19) = "Hardware subsystem error. Invalid data field in Request."
arrMessages(20) = "Invalid destination IP address."
arrMessages(21) = "The GUID is invalid."
arrMessages(22) = "Invalid gateway."
arrMessages(23) = "Invalid hostname."
arrMessages(24) = "Invalid IP address."
arrMessages(25) = "Invalid DNS IP address."
arrMessages(26) = "Invalid sub net mask."
arrMessages(27) = "Invalid value for PEF. PEF value should be between 1 and 16."
arrMessages(28) = "Reservation Canceled or Invalid Reservation ID."
arrMessages(29) = "Invalid Time to live value."
arrMessages(30) = "Invalid VLANID value."
arrMessages(31) = "Invalid Command. Used to indicate an unrecognized or unsupported command."
arrMessages(32) = "Command invalid for given LUN."
arrMessages(33) = "Load defaults cannot be accompanied with any other option."
arrMessages(34) = "There was an error loading the defaults."
arrMessages(35) = "Node Busy. Command could not be processed because command processing resources are temporarily unavailable."
arrMessages(36) = "Out of space. Command could not be completed because of a lack of storage space required to execute the given command operation."
arrMessages(37) = "This parameter is not supported."
arrMessages(38) = "Parameter out of range. One or more parameters in the data field of the Request are out of range."
arrMessages(39) = "The password may only contain printable ASCII characters."
arrMessages(40) = "Password test failed."
arrMessages(41) = "Requested data length invalid."
arrMessages(42) = "Requested data field length limit exceeded."
arrMessages(43) = "Requested Sensor, data, or record not present."
arrMessages(44) = "Request data truncated."
arrMessages(45) = "Command response could not be provided."
arrMessages(46) = "Command response could not be provided. BMC initialization or initialization agent in progress."
arrMessages(47) = "Command response could not be provided. Device in firmware update mode."
arrMessages(48) = "Command response could not be provided. SDR Repository in update mode."
arrMessages(49) = "Cannot execute command, SEL erase in progress."
arrMessages(50) = "Attempt to set the 'set in progress' value when not in the 'set in complete' state."
arrMessages(51) = "The SOL character 'accumulate interval' is invalid."
arrMessages(52) = "The SOL character 'send threshold' is invalid."
arrMessages(53) = "The SOL 'retry interval' is invalid."
arrMessages(54) = "Command completed successfully."
arrMessages(55) = "Timeout while processing command. Response unavailable."
arrMessages(56) = "Unspecified error."
arrMessages(57) = "The password may only contain printable ASCII characters."
arrMessages(58) = "Username cannot exceed 16 characters."
arrMessages(59) = "Invalid VLANID value. Enter in 'dddd' format."
arrMessages(60) = "Attempt to write read-only parameter '%s'."
arrMessages(61) = "BMC is busy."
arrMessages(62) = "Response data did not return successfully."
arrMessages(63) = "BMC time out error."
arrMessages(64) = "Invalid Configuration Option."
arrMessages(65) = "Cannot execute command.Parameter is illegal because command sub-function has been disabled or is unavailable."
arrMessages(66) = "Option '%s' requires an argument."
arrMessages(67) = "The asset tag for this system is not available."
arrMessages(68) = "The asset tag cannot be more than 10 characters long."
arrMessages(69) = "The required BIOS interfaces cannot be found on this system."
arrMessages(70) = "The BIOS version information is not available."
arrMessages(71) = "There is not enough free system memory to complete the BIOS update."
arrMessages(72) = "The BIOS update file version is a different version class (A00, X00) than the current system BIOS. Use the --force option to use this BIOS image."
arrMessages(73) = "The BIOS update file version is older than the current system bios.  Use the --force option to use this BIOS image."
arrMessages(74) = "The BIOS update file version is identical to the current system bios.  Use the --force option to use this BIOS image."
arrMessages(75) = "The sequence list must be a comma-separated numerical list of valid unique boot device numbers (ex: 2, 1, 3)."
arrMessages(76) = "The sequence list must be a comma-separated list of valid unique device names (ex: nic.emb.1, hdd.emb.1) or a comma-separated numerical list of valid unique boot device numbers (ex: 2, 1, 3)."
arrMessages(77) = "There was an error setting the sequence."
arrMessages(78) = "The list is not formatted correctly. See the help for more details."
arrMessages(79) = "The size of returned buffer is larger than the size of allocated buffer."
arrMessages(80) = "There was a problem getting the state byte."
arrMessages(81) = "The state byte is not available on this system."
arrMessages(82) = "There was a problem setting the state byte."
arrMessages(83) = "The state byte must be a value between 0 and 255 decimal."
arrMessages(84) = "The CPU information is not available."
arrMessages(85) = "The dependent option '%s' required for this subcommand is missing in the command line."
arrMessages(86) = "Duplicate sub command '%s' has been entered."
arrMessages(87) = "The script file does contain not a valid DTK environment script signature.  (%s)"
arrMessages(88) = "The format of the environment variable is incorrect."
arrMessages(89) = "The --envar/-s option can only be used for a single option."
arrMessages(90) = "The --envar/-s option can only be used for report operations."
arrMessages(91) = "The individual sub commands should be specified for the -s option."
arrMessages(92) = "Getting external serial connector settings failed."
arrMessages(93) = "Setting external serial connector settings failed."
arrMessages(94) = "There was an error opening the file %s."
arrMessages(95) = "File '%s' does not have write permission."
arrMessages(96) = "The file contains invalid option '%s'."
arrMessages(97) = "The replication information does not match for this system."
arrMessages(98) = "There can only be one section in the input file."
arrMessages(99) = "Bad ini file, the section (%s) cannot be found."
arrMessages(100) = "The format of the bios image file is incorrect."
arrMessages(101) = "Report operations and set operations must be separate."
arrMessages(102) = "Help is not available for the option '%s'."
arrMessages(103) = "The -x (--hex) option can only be used with -b or -r."
arrMessages(104) = "Input file '%s' not found."
arrMessages(105) = "Input file '%s' cannot be read."
arrMessages(106) = "Invalid argument for option '%s'."
arrMessages(107) = "Function table lookup error."
arrMessages(108) = "The machine ID was not found in the file '%s'."
arrMessages(109) = "The system memory information is not available."
arrMessages(110) = "Mode can only be used with the --pci option."
arrMessages(111) = "The device name or index must be present in the boot order."
arrMessages(112) = "The output file '%s' could not be opened. Please make sure the path exists and the media is not write protected."
arrMessages(113) = "Could not write to output file, disk may be full."
arrMessages(114) = "The current password must be supplied with a new password using --valsyspwd."
arrMessages(115) = "The current password must be supplied with a new password using  --valsetuppwd."
arrMessages(116) = "The current password can only be supplied when setting a new password."
arrMessages(117) = "Actions are not allowed for this filter. Only alerts are allowed."
arrMessages(118) = "There was an error getting the option '%s'."
arrMessages(119) = "The option '%s' is not available or cannot be configured through software."
arrMessages(120) = "There was an error setting the option '%s'."
arrMessages(121) = "The -n (--namefile) option can only be used with --pci."
arrMessages(122) = "The password may only contain alphanumeric characters."
arrMessages(123) = "The BIOS passwords have been disabled via jumper."
arrMessages(124) = "The password length must be between 1 and 32."
arrMessages(125) = "This password is locked and can only be unlocked by the admin user."
arrMessages(126) = "There was an error setting the password."
arrMessages(127) = "The LCD string length must be between 1 and %s."
arrMessages(128) = "The LCD string may only contain alphanumeric characters."
arrMessages(129) = "There was an error setting the LCD string."
arrMessages(130) = "The second channel can only be set if the RAID controller is set to RAID."
arrMessages(131) = "The set operation, '%s', requires sub commands."
arrMessages(132) = "The service tag for this system is not available."
arrMessages(133) = "The system ID value is not available."
arrMessages(134) = "The system information string is not available."
arrMessages(135) = "A system error has occured."
arrMessages(136) = "Usage error."
arrMessages(137) = "The uuid information is not present on this system."
arrMessages(138) = "The manufacturing/first-power-on date information is not present on this system."
arrMessages(139) = "Version cannot be accompanied with any other option."
arrMessages(140) = "The self-identify blinker timer should be set to 0..255 second(s)."
arrMessages(141) = "Encrypt key is too long. 142. Encrypt key is invalid, accepted characters are 0 to 9 or A to F."
arrMessages(142) = "Undefined"
arrMessages(143) = "Parameter has been temporarily disabled due to a dependancy on other settings."
arrMessages(144) = "The old password supplied is incorrect. The new password will not be set. Please try again."
arrMessages(145) = "Cannot stat /etc/omreg.cfg file. Please ensure /etc/omreg.cfg file is present and is valid for your environment. You can copy this file from the DTK iso."
arrMessages(146) = "Getting nicselection settings failed."
arrMessages(147) = "HAPI Driver Load Error."
arrMessages(148) = "Filter action power reduction is only supported for the system power warn/fail filters."
arrMessages(149) = "TPM Clear settings requires setup password."
arrMessages(150) = "There is currently no TPM Clear request pending."
arrMessages(151) = "Password is not required for retrieving the TPM options."
arrMessages(152) = "Setup password is required for setting the TPM options."
arrMessages(153) = "Invalid Password override."
arrMessages(154) = "Invalid TPM set option."
arrMessages(155) = "There was an error setting the TPM option."
arrMessages(156) = "There is no setup password installed on this system."
arrMessages(157) = "The setup password supplied is incorrect. Please try again."
arrMessages(158) = "Profile should be custom for setting cpupowermode, memorypowermode and fanmode."
arrMessages(159) = "There was an error setting the Power Option."
arrMessages(160) = "The power cap value entered is out of range. Please try again."
arrMessages(161) = "The power cap value entered must be between 0 to 100 if unit is percent."
arrMessages(162) = "Invalid IPv6 address. The IPv6 address cannot be link-local or multicast."
arrMessages(163) = "Invalid IPv6 address. The IPv6 address specified has incorrect address format."
arrMessages(164) = "Invalid IPv6 address. The gateway address specified has incorrect address format."
arrMessages(165) = "Invalid IPv6 address. The Primary DNS server address specified has incorrect address format."
arrMessages(166) = "Invalid IPv6 address. The Secondary DNS server address specified has incorrect address format."
arrMessages(167) = "Invalid IPv6 address. The gateway address specified is invalid."
arrMessages(168) = "Invalid configuration. Attempting to apply IPv6 configuration on a non supported platform."
arrMessages(169) = "Invalid IPv6 configuration. Attempt to set DNS server address manually while DNS address source is set to auto."
arrMessages(170) = "Invalid IPv6 configuration. Attempt to set IPv6 address manually while IPv6 address source is set to auto."
arrMessages(171) = "Invalid IPv6 configuration. Attempting to apply IPv6 configuration without loading IPv6 stack."
arrMessages(172) = "Invalid IPv4 configuration. Attempting to apply IPv4 configuration with IPv4 disabled."
arrMessages(173) = "Invalid IPv6 configuration. Ipv6 address cannot be specified without specifying prefix-length."
arrMessages(174) = "Invalid IPv6 configuration. dnssrcv6 cannot be set to auto when ipsrcv6 is set to manual."
arrMessages(175) = "Error while executing IPMI Set command."
arrMessages(176) = "Error while executing IPMI Get command."
arrMessages(177) = "Error during Trap Alert."
arrMessages(178) = "Unspecified error."
arrMessages(179) = "Unsupported device. Re-try with supported device"
arrMessages(180) = "Setup password is required. Re-try providing setup/admin password"
arrMessages(181) = "System password is required. Re-try providing system password"
arrMessages(182) = "The password supplied is incorrect. Please try again."
arrMessages(183) = "Password verification failed."
arrMessages(184) = "User input password does not fit system requirement."
arrMessages(185) = "Password not installed in the system."
arrMessages(186) = "password status is disabled."
arrMessages(187) = "Error in Validation."
arrMessages(188) = "Error in Setting the Value."
arrMessages(189) = "SMI call (10-0) only supports password no more than %d characters."
arrMessages(190) = "This is not a Dell machine. CCTK supports only Dell machines."
arrMessages(191) = "Setup Password is required to change the setting. Use --valsetuppwd to provide password."
arrMessages(192) = "System Password is required to change the setting. Use --valsyspwd to provide password."
arrMessages(193) = "Password is not Installed. so use only --setuppwd"
arrMessages(194) = "Password is not Installed. so use only --syspwd"
arrMessages(195) = "The system password supplied is incorrect. Please try again."
arrMessages(196) = "The Sequence list must be a comma-separated list of valid unique device names (ex: hdd,cdrom)."
arrMessages(197) = "The system revision information is not available for this system."
arrMessages(198) = "The completion code information is not available for this system."
arrMessages(199) = "The BIOS characteristics information is not available for this system."
arrMessages(200) = "The password should not contain special characters."
arrMessages(201) = "Please use 64-bit version of this application."
arrMessages(202) = "%s cannot be modified when TPM is OFF."
arrMessages(203) = "System password cannot be set when pwdlock option is in locked state (pwdlock=lock)."
arrMessages(204) = "adddevice option not supported by this machine's BIOS"
arrMessages(205) = "usb device already present in this machine."
arrMessages(206) = "Unable to get information from BIOS."
arrMessages(207) = "%s - Error : Unable to store BIOS information."
arrMessages(208) = "Duplicate entry found in the input list : %s , Operation Aborted."
arrMessages(209) = "Typo found in the input list : %s , Operation Aborted."
arrMessages(210) = "Asset tag can have only printable ASCII characters."
arrMessages(211) = "Multiple inputs will not be accepted."
arrMessages(212) = "Invalid Hex format."
arrMessages(213) = "Hex value range should be 0x0 to 0xffff."
arrMessages(214) = "%s - Only positive numeric values are acceptable."
arrMessages(215) = "%s - Length cannot exceed two characters."
arrMessages(216) = "Range for autoon hour value should be 0 to 23(24 hour format)."
arrMessages(217) = "Range for autoon minute value should be 0 to 59."
arrMessages(218) = "This Option Not supported on UEFI Bios."
arrMessages(219) = "Unable to Set Bootorder."
arrMessages(220) = "Invalid Arguments. Unable to Set Bootorder."
arrMessages(221) = "%s should not combine with other suboptions."
arrMessages(222) = "The property ownership tag for this system is not available."
arrMessages(223) = "The property ownership tag cannot be more than 80 characters for non portable machines."
arrMessages(224) = "The property ownership tag is limited to 48 characters for portable systems."
arrMessages(225) = "Property ownership tag can have only printable ASCII characters."
arrMessages(226) = "Error in Setting the Value. Note: In some machines, If System password is set, you can't set Setup password."
arrMessages(227) = "'admin/root' privileges required to execute this application."
arrMessages(228) = "The option related BIOS information is not available in this machine."
arrMessages(229) = "Improper Output from Bios. Please try again."
arrMessages(230) = "Error in Bootorder."
arrMessages(231) = "The manufacturing/first-power-on date information is not present on this system."
arrMessages(232) = "Not Applicable."
arrMessages(233) = "Uefi bootlisttype is not supported in this Machine."
arrMessages(234) = "Improper Output from Bios. Please try again."
arrMessages(235) = "Error in Bootorder."
arrMessages(236) = "Unable to get information specific to machine."
arrMessages(237) = "The input file is invalid."
arrMessages(238) = "No Status Present."
arrMessages(239) = "File Do not have configurable Options."
arrMessages(240) = "Please provide the days to enable."
arrMessages(241) = "Password is not Installed. Please try again without providing --val%s"
arrMessages(242) = "Please provide the old password to set the new password using --valownerpwd."
arrMessages(243) = "The owner password is incorrect. Please try again."
arrMessages(244) = "Error in setting the value. Note : Setup or system password might be set on the system. Clear the password(s) and try again."
arrMessages(245) = "Owner password is not supported in file operations."
arrMessages(246) = "Password operation is not supported on the system."
arrMessages(247) = "The owner of the system has enabled the Owner Access feature. To set the Bios configuration, create setup or system password."
arrMessages(248) = "Either the system hardware or the BIOS version does not support the option. To resolve the BIOS version issue, upgrade the BIOS to the latest version."
arrMessages(249) = "Unable to get password information."

Dim cctkError, msg, bArgOK
bArgOK = vbFalse

On Error Resume Next
cctkError = CInt(Wscript.Arguments(0))

If WScript.Arguments.Count = 1 Then
	If cctkError <> "" Then
		bArgOK = vbTrue
	End If
End If

If bArgOK = True Then
	msg = "CCTK Returned message: """ & arrMessages(cctkError) & """"
	Wscript.Echo msg
	Wscript.Quit(cctkError)
Else
	Wscript.Echo "The script input was invalid."
	Wscript.Quit(1)
End If

Creating a CCTK Script

This script will enable and activate the TPM if possible, set the SATA level to it’s highest supported setting, then import the template file. Save it as CCTK-Default.cmd.

@ECHO OFF
REM Parse Arguments
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION

SET ARGV=.%*
CALL :PARSE_ARGV
IF ERRORLEVEL 1 (
  ECHO Cannot parse arguments
  ENDLOCAL
  EXIT /B 1
)

REM ---START MAIN LOOP---
ECHO == Seting BIOS Settings ==

REM Determine Arch
IF "%PROCESSOR_ARCHITECTURE%" == "AMD64" GOTO :X64
GOTO X86

:X64
COPY /Y Dell-CustomSettings.cctk .\x64 >NUL
SET CCTKPath="x64"
GOTO RunCCTK

:X86
COPY /Y Dell-CustomSettings.cctk .\x86 >NUL
SET CCTKPath="x86"
GOTO RunCCTK

:RunCCTK
ECHO --Enabling TPM
%CCTKPath%\cctk.exe --tpm=on !ARG1! !ARG2!
cscript.exe //nologo Show-CCTKErrors.vbs %errorlevel%
IF errorlevel 157 GOTO END

ECHO --Activating TPM
%CCTKPath%\cctk.exe --tpmactivation=activate !ARG1! !ARG2!
cscript.exe //nologo Show-CCTKErrors.vbs %errorlevel%

ECHO --Attempting to set ATA sata mode
%CCTKPath%\cctk.exe --embsataraid=ata !ARG1! !ARG2!
cscript.exe //nologo Show-CCTKErrors.vbs %errorlevel%

ECHO --Attempting to set AHCI sata mode
%CCTKPath%\cctk.exe --embsataraid=ahci !ARG1! !ARG2!
cscript.exe //nologo Show-CCTKErrors.vbs %errorlevel%

ECHO --Attempting to set RAID ON sata mode
%CCTKPath%\cctk.exe --embsataraid=raid !ARG1! !ARG2!
cscript.exe //nologo Show-CCTKErrors.vbs %errorlevel%

ECHO --Enabling other features
%CCTKPath%\cctk.exe -i Dell-CustomSettings.cctk !ARG1! !ARG2!
cscript.exe //nologo Show-CCTKErrors.vbs %errorlevel%
GOTO END

REM ---END MAIN LOOP---

:PARSE_ARGV
REM ref: http://skypher.com/index.php/2010/08/17/batch-command-line-arguments/
  SET PARSE_ARGV_ARG=[]
  SET PARSE_ARGV_END=FALSE
  SET PARSE_ARGV_INSIDE_QUOTES=FALSE
  SET /A ARGC = 0
  SET /A PARSE_ARGV_INDEX=1
  :PARSE_ARGV_LOOP
  CALL :PARSE_ARGV_CHAR !PARSE_ARGV_INDEX! "%%ARGV:~!PARSE_ARGV_INDEX!,1%%"
  IF ERRORLEVEL 1 (
    EXIT /B 1
  )
  IF !PARSE_ARGV_END! == TRUE (
    EXIT /B 0
  )
  SET /A PARSE_ARGV_INDEX=!PARSE_ARGV_INDEX! + 1
  GOTO :PARSE_ARGV_LOOP

  :PARSE_ARGV_CHAR
    IF ^%~2 == ^" (
      SET PARSE_ARGV_END=FALSE
      SET PARSE_ARGV_ARG=.%PARSE_ARGV_ARG:~1,-1%%~2.
      IF !PARSE_ARGV_INSIDE_QUOTES! == TRUE (
        SET PARSE_ARGV_INSIDE_QUOTES=FALSE
      ) ELSE (
        SET PARSE_ARGV_INSIDE_QUOTES=TRUE
      )
      EXIT /B 0
    )
    IF %2 == "" (
      IF !PARSE_ARGV_INSIDE_QUOTES! == TRUE (
        EXIT /B 1
      )
      SET PARSE_ARGV_END=TRUE
    ) ELSE IF NOT "%~2!PARSE_ARGV_INSIDE_QUOTES!" == " FALSE" (
      SET PARSE_ARGV_ARG=[%PARSE_ARGV_ARG:~1,-1%%~2]
      EXIT /B 0
    )
    IF NOT !PARSE_ARGV_INDEX! == 1 (
      SET /A ARGC = !ARGC! + 1
      SET ARG!ARGC!=%PARSE_ARGV_ARG:~1,-1%
      IF ^%PARSE_ARGV_ARG:~1,1% == ^" (
        SET ARG!ARGC!_=%PARSE_ARGV_ARG:~2,-2%
        SET ARG!ARGC!Q=%PARSE_ARGV_ARG:~1,-1%
      ) ELSE (
        SET ARG!ARGC!_=%PARSE_ARGV_ARG:~1,-1%
        SET ARG!ARGC!Q="%PARSE_ARGV_ARG:~1,-1%"
      )
      SET PARSE_ARGV_ARG=[]
      SET PARSE_ARGV_INSIDE_QUOTES=FALSE
    )
    EXIT /B 0

:END
ENDLOCAL

EXIT /B %errorlevel%

Save these files in your dell-cctk package, then create a ‘run command-line’ task sequence action linked to the package. The command should be ‘CCTK-Generic.cmd’. Good luck!

SCCM 2012 – Architecture Agnostic Dell CCTK WinPE Bios Package

I’m tired of choosing between our 32-bit and 64-bit Dell CCTK packages. We needed separate packages since the 32-bit cctk doesn’t run in Windows 7 x64, and the 64-bit cctk doesn’t run in x86 WinPE. This post will show you how to create a cmd wrapper to pass arguments to the appropriate executable for the running architecture.

  1. Download CCTK and install.
  2. Use the files that the cctk installer places in it’s installation directory to create the following folder structure in your package source directory. The files are usually kept in C:\Program Files (x86)\Dell\CCTK\X86 and ..\X86_64.
     \dell-cctk
     \dell-cctk\x86
     \dell-cctk\x86\
     \dell-cctk\x86\cctk.exe and supporting files
     \dell-cctk\x86\HAPI
     \dell-cctk\x64
     \dell-cctk\x64\cctk.exe and supporting files
     \dell-cctk\x64\HAPI
    
  3. Create a file named cctk.cmd in the \dell-cctk directory, and paste in the following code. The large majority of this code was re-purposed from the awesome blog post here: Batch Command-Line Arguments. This script will accept up to three arguments, and pass them to the correct cctk executable.
    @ECHO OFF
    REM Parse Arguments
    SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
    
    SET ARGV=.%*
    CALL :PARSE_ARGV
    IF ERRORLEVEL 1 (
      ECHO Cannot parse arguments
      ENDLOCAL
      EXIT /B 1
    )
    
    REM ---START MAIN LOOP---
    ECHO == Seting BIOS Settings ==
    
    REM Determine Arch
    IF "%PROCESSOR_ARCHITECTURE%" == "AMD64" GOTO :X64
    GOTO X86
    
    :X64
    SET CCTKPath="x64"
    GOTO RunCCTK
    
    :X86
    SET CCTKPath="x86"
    GOTO RunCCTK
    
    :RunCCTK
    ECHO --Running command
    %CCTKPath%\cctk.exe !ARG1! !ARG2! !ARG3!
    cscript.exe //nologo Show-CCTKErrors.vbs %errorlevel%
    GOTO END
    
    REM ---END MAIN LOOP---
    
    :PARSE_ARGV
    REM ref: http://skypher.com/index.php/2010/08/17/batch-command-line-arguments/
      SET PARSE_ARGV_ARG=[]
      SET PARSE_ARGV_END=FALSE
      SET PARSE_ARGV_INSIDE_QUOTES=FALSE
      SET /A ARGC = 0
      SET /A PARSE_ARGV_INDEX=1
      :PARSE_ARGV_LOOP
      CALL :PARSE_ARGV_CHAR !PARSE_ARGV_INDEX! "%%ARGV:~!PARSE_ARGV_INDEX!,1%%"
      IF ERRORLEVEL 1 (
        EXIT /B 1
      )
      IF !PARSE_ARGV_END! == TRUE (
        EXIT /B 0
      )
      SET /A PARSE_ARGV_INDEX=!PARSE_ARGV_INDEX! + 1
      GOTO :PARSE_ARGV_LOOP
    
      :PARSE_ARGV_CHAR
        IF ^%~2 == ^" (
          SET PARSE_ARGV_END=FALSE
          SET PARSE_ARGV_ARG=.%PARSE_ARGV_ARG:~1,-1%%~2.
          IF !PARSE_ARGV_INSIDE_QUOTES! == TRUE (
            SET PARSE_ARGV_INSIDE_QUOTES=FALSE
          ) ELSE (
            SET PARSE_ARGV_INSIDE_QUOTES=TRUE
          )
          EXIT /B 0
        )
        IF %2 == "" (
          IF !PARSE_ARGV_INSIDE_QUOTES! == TRUE (
            EXIT /B 1
          )
          SET PARSE_ARGV_END=TRUE
        ) ELSE IF NOT "%~2!PARSE_ARGV_INSIDE_QUOTES!" == " FALSE" (
          SET PARSE_ARGV_ARG=[%PARSE_ARGV_ARG:~1,-1%%~2]
          EXIT /B 0
        )
        IF NOT !PARSE_ARGV_INDEX! == 1 (
          SET /A ARGC = !ARGC! + 1
          SET ARG!ARGC!=%PARSE_ARGV_ARG:~1,-1%
          IF ^%PARSE_ARGV_ARG:~1,1% == ^" (
            SET ARG!ARGC!_=%PARSE_ARGV_ARG:~2,-2%
            SET ARG!ARGC!Q=%PARSE_ARGV_ARG:~1,-1%
          ) ELSE (
            SET ARG!ARGC!_=%PARSE_ARGV_ARG:~1,-1%
            SET ARG!ARGC!Q="%PARSE_ARGV_ARG:~1,-1%"
          )
          SET PARSE_ARGV_ARG=[]
          SET PARSE_ARGV_INSIDE_QUOTES=FALSE
        )
        EXIT /B 0
    
    :END
    ENDLOCAL
    
    EXIT /B %errorlevel%
  4. Create a package for your dell-cctk directory and files named ‘Dell CCTK Multi-Arch’, but don’t add a program.
  5. Create a file in \dell-cctk named HAPIInstall.cmd and add the following code.
    @echo off
    REM Determine Arch
    IF "%PROCESSOR_ARCHITECTURE%" == "AMD64" GOTO :X64
    GOTO X86
    
    :AMD64
    x64\hapi\hapint.exe -i -k C-C-T-K -p "hapint.exe"
    GOTO END
    
    :X86
    x86\hapi\hapint.exe -i -k C-C-T-K -p "hapint.exe"
    GOTO END
    
    :END
  6. Add a task sequence step in WinPE with the following characteristics. This enables use of CCTK in WinPE. If desired, this action and the next action can be placed in a group (folder) so that the conditional WMI queries only need to be specified once.
    Type: Run Command-Line
    Name: Install Dell HAPI Drivers
    Package: Dell CCTK Multi-Arch
    Command: HAPIInstall.cmd
    Conditions: If any of the following:
      * select * from win32_computersystem where Model like 'Latitude%'
      * select * from win32_computersystem where Model like 'Precision%'
      * select * from win32_computersystem where Model like 'Optiplex%'
    
  7. Add a task sequence step after the one created in Step 5 with the following characteristics. Substitute the command line arguments with whatever you’d like the action to do in the Dell BIOS.
    Type: Run Command-Line
    Name: Dell Bios - Enable TPM
    Package: Dell CCTK Multi-Arch
    Command: cctk.cmd --TPM=on --valsetuppwd=YourBiosPassword
    Conditions: If any of the following:
      * select * from win32_computersystem where Model like 'Latitude%'
      * select * from win32_computersystem where Model like 'Precision%'
      * select * from win32_computersystem where Model like 'Optiplex%'
    

Congrats! That should do ya. No more worrying about whether or not you selected the appropriate CCTK package for your architecture.

SCCM – Check for Laptop Power and Battery Status Before Imaging

[Update] It helps if I add a download link! The script can be had from my Github repo here: John Puskar’s Github Repo.


Our task sequences have some Dell CCTK integration, which fails if the battery is below a certain percentage or if the AC adapter isn’t connected. The following AutoIT script will pop-up a box prompting that the AC adapter be connected. Once connected, the popup shows the battery’s charge with a progress window. Once the battery hits 60%, the task sequence continues.

Screenshots!

power-1
power-2

Instructions

To use the script:

  1. Download and install AutoIt.
  2. Compile a 32 and 64 bit version of the script.
  3. Add the compiled EXE files to the following respective folders on your SCCM site server:
    C:\Program Files\Microsoft Configuration Manager\OSD\Extras\Power32
    C:\Program Files\Microsoft Configuration Manager\OSD\Extras\Power64
  4. Modify the following file on your site server:
    C:\Program Files\Microsoft Configuration Manager\bin\X64\osdinjection.xml

    Add the following lines in the respective sections:

    --to the i386\SCCM section:
    <File name="waitforbattery.exe">
    	<LocaleNeeded>false</LocaleNeeded>
    	<Source>extra\power32</Source>
    	<Destination>windows\system32</Destination>
    </File>
    
    --to the x64\SCCM section:
    <File name="waitforbattery.exe">
    	<LocaleNeeded>false</LocaleNeeded>
    	<Source>extra\power64</Source>
    	<Destination>windows\system32</Destination>
    </File>
    
  5. Update distribution points for your boot images.
  6. Add a ‘run command line’ task sequence action with the following command line:
    X:\windows\system32\waitforbattery.exe

Step 4…Profit! Hope you have a great day. 🙂