Deployment and Imaging Group

 View Only

A Simple Alternative to DeployAnywhere for Hardware Independent Imaging Drivers 

Dec 30, 2014 10:56 AM

Introduction

We've been doing Hardware Independent Imaging (HII) since DS 6.5, long before DeployAnywhere came along. When were first determining the process, we looked at several driver management tools and they all had the same issues. They worked fine for 95% of the drivers, but there were always 5% that just would not work, even though the drivers auto-installed just fine if they were in the Windows DevicePath. Finally we decided that the benefits of a driver database and avoiding driver replication just weren't worth the hassle. The method we've been using since then was developed on Windows XP and has worked flawlessly on every release of windows since then (actually getting simpler with the death of HAL files in Vista).

 

Preparation

First we set the DevicePath in our base image to add C:\Drivers. We then take advantage of the Driver packs available from most major business PC manufacturers (we use Dell and HP and both work great). We have a driver repository in a windows share called 'Drivers' on each site server. This share contains a folder for each model with subfolders containing drivers for each OS version we support, and a third folder called 'Common' for drivers that work for any windows OS. Within these folders we extract the driver packs. We also add one batch script we call 'OEMSetup.cmd' which for the vast majority contains nothing. In the very few cases we have drivers not fully install automatically during minisetup, we add command lines to this script to be performed after imaging in production. These driver folders can be synchronized using whatever method of fileshare replication you like (DFS for example).

Capture_2.PNG 90px_Capture.PNG 90px_Capture_0.PNG 90px_Capture_1.PNG

The job scripts also need several tokens (Settings>Deployment>Tokens) to access the driver folders:

Siteserver token:

select c.name from TaskTargetDeviceCache vc 
   left outer join Inv_Client_Task_Resources ctr 
      on ctr._ResourceGuid = vc.Guid 
         And vc.Guid = '%COMPUTERID%' 
   left outer join Inv_Client_Task_Servers cts 
      on cts.ClientTaskServerGuid = ctr.ClientTaskServerGuid 
   join vcomputer c on cts._ResourceGuid = c.guid

SymUser token:

Select '<symantec network username>'

​SymPwd token:

Select '<symantec network user password>'

 

Deploy Image Jobs

Our image deployment jobs then contain a deploy image task with DeployAnywhere unchecked, a Driver Copy run script task appropriate to the OS being deployed, a boot to production task, and a run script task to execute the 'OEMSetup.cmd' script. 

90px_Capture_3.PNG 90px_Capture_4.PNG 90px_Capture_5.PNG

The Driver Copy run script looks like this:

 

@Echo off
REM Copy Drivers to production for Win7 x64
Setlocal EnableDelayedExpansion

Echo Authenticating with Site Server
net use \\%Siteserver%\drivers %SymPwd% /user:<domain>\%SymUser%

Echo Retrieving Model Name...
For /F "tokens=2 delims==" %%A In ('WMIC computersystem get model /format:VALUE') Do Set STR=%%A
SET MODELNAME=%STR%
For /L %%A in (1,1,50) Do If "!MODELNAME:~-1!"==" " (Set MODELNAME=!MODELNAME:~0,-1!)

Echo Copying Driver files...
xcopy "\\%Siteserver%\drivers\%MODELNAME%\Common\*.*" C:\drivers /S /Y /I
xcopy "\\%Siteserver%\drivers\%MODELNAME%\Win7\X64\*.*" C:\drivers /S /Y /I
If %ERRORLEVEL% Neq 0 Goto DriverFail
Goto End

:DriverFail
REM driver copy failed.  This may be because C: is not mounted or is 
REM mounted as RAW.  Retry after manually assigning C: using diskpart
Exit 253

:End

The script authenticates with the site server share, queries the model name of the computer via wmic and then copies the contents of the appropriate OS and Common folders from \\%SiteServer%\drivers\%modelname%\ into C:\Drivers. Note that for WinXP you may also need to copy correct HAL files into place. We stopped supporting XP before we switched to 7.x so you'll need to track down that information elsewhere. Mini-setup then installs all the drivers automatically during the boot to production. Finally after the boot to production the OEMSetup.cmd script is run to finalize anything that doesn't work automatically.

 

Integrating New Hardware

With all this in place our process for adding a new computer model is:

  1. Determine the full model name (also known as productname in the BIOS) for the new computer and create a folder named this in our driver repository.
  2. Download the driver pack cabs for each OS we support from Dell or HP and extract them to the appropriate subfolders.
  3. Determine if any drivers are universal (applicable to all OS versions) and move them to the Common subfolder.
  4. Copy in a blank OEMSetup.cmd to this folder.
  5. Perform initial deployment on the first new computer (which deploys our standard image) and verify that all drivers installed correctly.
  6. Add custom unattended installation command lines for drivers that didn't install automatically (rare, so far only bluetooth drivers)

 

Closing

This works extremely well for us. We currently support 24 different models, both Dell and HP, laptops and desktops, and only two require any OEMSetup customization (both older models, both bluetooth drivers). We've never had a single issue with USB3 drivers, which seem to plague everyone else. Note that extended configuration applications for things like video cards (like AMD Catalyst) do not automatically get installed. If you want these (we generally don't) their setup command lines need to be added to OEMSetup.

The one downside to our method is driver duplication. Since many models have the same base hardware, the drivers are duplicated in each model subfolder. The total storage required for all 24 models' driver folders is currently 21GB per site server. Honestly, slow storage is cheap and we really don't care about this. In fact it makes it easier when some models are finicky about certain (older) driver versions working better than others.

Hopefully this helps those of you looking for a simple alternative to DeployAnywhere. Good luck!

 

Statistics
0 Favorited
1 Views
0 Files
0 Shares
0 Downloads

Tags and Keywords

Comments

Nov 27, 2018 12:23 PM

Anyone using this workflow with windows 10?  I realized even if I get the drivers to copy down, it's not using them.  I was having NIC issues on a Dell Latitude 5480 laptop, I did an update driver pointing it to c:\drivers and it found newer driver.  I'm wondering if I need to modify my answer file for driver path even though it is in the registry.

https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/wsim/add-a-device-driver-path-to-an-answer-file

Still testing, but I think adding this to my answer file helped.

<settings pass="offlineServicing">
        <component name="Microsoft-Windows-PnpCustomizationsNonWinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <DriverPaths>
                <PathAndCredentials wcm:action="add" wcm:keyValue="1">
                    <Path>C:\Drivers</Path>
                </PathAndCredentials>
            </DriverPaths>
        </component>
    </settings>

 

Jul 26, 2017 02:00 PM

Anyone using this driver workflow and also doing bios updates?

I got it working in powershell, but you have to disable/re-enable signing policy to get it to work.  Trying to write it via .bat script, but i'm pretty clueless with scripting.

If anyone can help me out in my other thread - would appreciate it

edit: I think I figured out my scripting mistake.  Thread has info for bios updates as part of imaging workflow if anyone is interested.

Nov 01, 2016 11:45 AM

Thanks all for all these hints. I actually got this working on GSS 3.1, but instead of using a SysPrep'd image, I use the Scripted OS install (never could quite get the hang of SysPrep).  For us, since not all PCs are all the same, it's not a big deal to do a complete install then install software per department as needed.

In GSS, I created scripted jobs where first, I run a manual DiskPart - which first boots into PXE10, then a 2nd job to copy the drivers to the new drive (C:\drivers) based on the DOS script above, then the 3rd job is the scripted OS install minus the DiskPart.  In PXE, I have it set for multiple drive mappings where one of the drives is the "main" drivers folder (it's actually off of the \\GSSserver\express folder).  There's very little modifications to the install.wim file except for some branding, the placing of the dagent(x64).msi to a c:\dagent folder, and setupcomplete.cmd file where it launches the dagent???.msi file after boot. Lastly, I modified the unattend.xml to use c:\drivers as the alternate folder for drivers. There's some slight modifications whether I am installing x64 or x86, but overall, this works marvelously.  I also made a modified .bat file based on the code above to echo out the machine type for new installs.

Thanks everyone!

Steve

Rutgers Athletics

Apr 08, 2015 02:15 PM

Happy to help!

Apr 08, 2015 12:36 PM

@sfaucher - thanks again for posting this.  Got in 2 new model Dells and had them up and working in minutes with drivers.  I'm so thankful!  

Feb 04, 2015 11:07 PM

Handy article! Since DISM found on Win7 does not support the add-driver switch, I use pnputil.exe during production run of tasks, post image load and minisetup. As intel did a great job of naming the xHCI drivers the same name, it requires you to differentiate Series 7 chipsets vs Series 8/9 chipsets. BTW still plodding along with DS 6.9 SP5 MR3 + WinPE 3.1. Might make the move to DS6.9 SP6, but we are slowly moving to SCCM

Jan 21, 2015 07:58 PM

Beware of the "if ERRORLEVEL 3010 goto success" line actually returning its own errorlevel, so by the next line you'll have lost the original return code.
I think you can do something like:
C:\drivers\folder\setup.exe /s
SET ERRORLEV=%ERRORLEVEL%
if "%ERRORLEV%" == "3010" goto success
if "%ERRORLEV%" == "0" goto success
Goto fail
:success
REM maybe copy a config file without losing the original error code
Copy config.txt...
:fail
REM The config file's not copied and the original return code is preserved
EXIT %ERRORLEV%
Some of the Intel driver installs have odd return codes too IIRC.

Jan 21, 2015 03:02 PM

Just wanted to post back something I learned in case it helps someone else.

In the oemsetup.cmd script, if you are running a driver install and it successfully installs but returns a failure with a return code, you can edit the script so that the DS agent reads that return code as a successful install.  

I've found this happens on driver installs which are asking for a reboot (even if run silently).  Found the code edits below somewhere on Connect, so thanks to that person.

C:\drivers\folder\setup.exe /s
if ERRORLEVEL 3010 goto success
if ERRORLEVEL 0 goto success
 goto failure
:success
set %ERRORLEVEL% = 0
goto end
:failure echo Failed
EXIT 1
#goto 
end
:end

 

Jan 13, 2015 10:01 AM

Hi David,

I like the scripting approach for the simplicity of it.  In 2 work days, I got all of our 8 model computers restoring both Win7 32 & 64 bit drivers (I had never attempted 64 bit before so we're better off with very little extra work).  It's cringeworthy to think of the hours I spent with support over the years (both my time and even more of theirs) when this approach is so straight forward and works. 

Also, not using DA means one less thing I have to worry about breaking during an upgrade.  Last upgrade from 7.1 to 7.5 not only was DA in shambles, I had image files that were deleted without making it to the new location, etc.  The more simple I think our Symantec setup is, the better off we'll be.  At some point in the near future I will be upgrading from 7.5 to the latest SP and Hot Fix, I'm a little less worried about that now.

A bonus is retargeting seems faster too as there is no database it's running through looking for a match, just bringing down the one Model folder with what it needs.

I look forward to some DS improvements coming but not sure I'll ever go back to DA unless it's super simple and straightforward to use and troubleshoot.

Thanks for all of your (and the teams) help over the last few months. 

 

 

Jan 12, 2015 04:45 PM

Thanks for the feedback Ian/Shawn. I think I'm ready to start talking about some alternatives here and I might think about creating a working group to start throwing some ideas together. DA was a great concept but it needs to evolve into something that is unilaterally beneficial.

Crowd sourcing in this way makes legal edgy and with the potential to introduce malware into drivers submitted we'd have trouble vetting this one appropriately. I have been in discussions with a third party about building out this kind of database over the last few months, but it's time intensive and demands access to the hardware generally to fully ratify.

This is definitely on my 'big things to to try and fix in 2015', so I'll be putting some more thought into it.

Jan 12, 2015 12:16 PM

I really like the meta-data framework idea. Allowing your customers to do the work for you AND for your OTHER customers is really smart. It would likely need some sort of vetting process.. perhaps a new driver would have to be "flagged" as working by X number of customers before confirming that it works on Y model and pushing it out to everybody automatically.

Jan 12, 2015 12:05 PM

At least in our case it's just a fundamentally different approach. One of the main purposes of DeployAnywhere is to prevent driver duplication by keeping only the latest copy of the same driver that is shared by hardware from different models. Unfortunately there are often cases where manufacturers don't properly vet their changes with older revisions of hardware and the newer drivers just plain do not work correctly with older models. The driver specs say they are compatible, but they aren't anymore. There is no automated way to determine that other than to try to run it on older hardware and say "yup, it's broke" and roll back to an older driver for that model. It's not just DeployAnywhere. We've tried many different solutions that attempt to do the same thing (consolidate drivers in a database) and they all have these issues.

Really the only thing you can (mostly) depend on with drivers is that the driver packs released by the manufacturer generally work with the hardware they were compiled for. In my opinion any automated driver consolidation model is doomed to failure. There needs to be a human involved in the process somewhere to say "no, that driver really isn't compatible with X hardware anymore, even though it says it is, so we need to keep the old version around." Ideally that human should not be your end user, because it is a frustrating problem that is duplicated needlessly by every end user when it could instead be solved at a higher level for all of them.

At the same time, it is unreasonable of us to expect you to keep around the hundreds of models of older hardware we all have to deal with and test each new driver against them all. We get that, or at least I do. There's no easy answer. Perhaps the best I can think of is to crawl the major manufacturer web sites and keep a database of latest driver version available for download per model. I can see that quickly becoming a logistical nightmare, however, as cool as it would be if it worked. I'll be honest, though, with as little problem as we have with this method, as little work as it takes to configure a new model, and as little it costs to support the amount of space required to just duplicate drivers for every model... I doubt we ever switch to DeployAnywhere.

The one other problem you guys desperately need to fix SOUNDS like is already being addressed, which is the interminably long timeline between releases. It really is ridiculous that the USB3 issue hung around as long as it did (is it even fixed yet?).

Jan 12, 2015 11:41 AM

Hi David,

The problem with DeployAnywhere is that the problem spent troubleshooting it can quickly outweigh the benefit gained in using it as a managed solution for driver delivery in environments with high-model counts.

As you know, we're another customer that implemented their own hardware independent imaging solution with simple scripts. The problem for DeployAnywhere is that simple scripts that copy drivers across to the target PC are simply incredibly effective, and once they work they always just work. So DeployAnywhere must be able to add value by reducing painpoints elsewhere.

A painpoint common to both custom HII implementations and DeployAnywhere is the new model / first install issue. Here drivers need to be downloaded and isolated for both the production and automation operating systems. This can be a pain which if removed might make the pain using DeployAnywhere worthwhile.

What I've always wanted to see is a solution which looks looks at your PC inventory and bulilds you a driver database (automation and production) as appropriate. You then select the models you want imaging to support (most of us think in terms of models) and then the system just downloads them, puts them in the right locations and the invokes the right processes to just make it work. That would be brilliant.

A framework which enables Connect users to provide meta-data (hence crowd-sourcing the work) might be an option? This way, once someone solves a driver problem, the rest of the community can benefit from it with a meta-data upload.

Jan 12, 2015 11:13 AM

I've been following this thread with interest and while I don't like to hear that our in built tools aren't quite doing the job I'm happy to see that there are robust options in it's place. DeployAnywhere does work for the majority of our customers but I can see there is still a way to go.

What I'd like to do is take some feedback on what we need to change to make this work how we need it to. I took over PM of the product mid last year and I've had the team spend some time making some much needed changes to DeployAnywhere. These will be landing in the 7.6 release in a couple of months. I think this will be a step in the right direction but I'd really like to work with this group to drive further change to get this right. Driver management has always been a big slice of the effort when managing desktops and I'm determined to get a solution that takes the vast majority of this effort away.

Let me know your thoughts..

 

Jan 09, 2015 06:39 PM

There should be something in the logs where it at least looks at the inf file.
One problem I've had before is that the signing of the driver has become invalid at some point when being copied around the place, but this showed up in the logs.

Jan 09, 2015 05:21 PM

ortolani

Thanks for the powershell example. This is the direction I will be going at some point. I just need to get beter at PS.

sfaucher

I agree with the six of one... This is how I had setup my XP image back in the day, I get it. I just wanted to throwout ideals for others to consider and that may help make everyones HII process better. Including mine.   

One thing I've been toying with, looks similar to what Sally5432 is trying to do, is grouping drivers into compatible groups and adding only the specific drivers needed for select hardware in model spicific folders.

Example: If all laptops are DELL and 80% of the drivers are common across the board, then hold those common drivers in a single folder and then have a model specific folders that holds the one offs. 

At this point I think this is too much work for little gain as you pointed out in your artical. I know the OEM's/purchasing has changed hardware in the middle of a production year and I had to scramble to adjust.

I did see a thread about scanning hardware and downloading only what is needed. I may look into that option at some point but for now I have to get support out of the habit of building from scratch and into automation as quickly as possible. Then I can start adding bells and whistles.  

 

Jan 09, 2015 04:28 PM

I follow the same approach JSour did, but I use PowerShell instead of vbscript. The Driver injection happen at the WinPE environment and I also use DISM.

The script below does the following:

  • Get Computer Model and trim extra spaces. Dell models that is a Precision get the word "Workstation” removed
  • Check where windows is install – which driver letter
  • Map a Driver folder (sample structure below)
    • Win7x64
      • OptiPlex 745
      • OptiPlex 9020
      • Latidute E6500
      • Etc
    • Sample for Win7x86
  • Inject the driver(s)
  • Remove the map
  • Exit

The Drivers I download all from Dell Driver Packs for Enterprise Client at DriverPage

Since I create a Run Script task in the Altiris Console, all I have to do is target the computer I want run while in WinPE. I hope this help anyone that would like to do this in PowerShell.

# ---------------------------------------------------------------------------------------------
function Get-ComputerInfo
{
    <#
    .SYNOPSIS
        Gets info from Computer
    .DESCRIPTION
        GET Computer Name, Model, OS, COU, RAM, Video, HD, MAC and IP
    #>
	[CmdletBinding()]
    Param(
		[Parameter(Position=1)]
		[Boolean]$DebugMode
    )
	PROCESS 
    {
	    try {
            $System  = get-wmiobject -class win32_computersystem -namespace "root\CIMV2" -ErrorVariable +err -WarningAction SilentlyContinue 

            $Comp_Info = New-Object System.Object 
            $Comp_Info | Add-Member -type NoteProperty -name "Model" -Value ($System.Model.Trim() -replace 'WorkStation ', '')

            # Display on the screen computer info
            Write-Host " - Model   : $($Comp_Info.Model)"
            Start-Sleep 2

            Write-Host
            Write-Host "------------------------------------------------------------------------------"
            Write-Host "- Checking Windows Install Location:                                         -"
            Write-Host "------------------------------------------------------------------------------"
            $i           = 0
            $search      = 1
            $arrDriver   = "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","X","Y","Z"
            $WindowsPath = "\Windows\System32"
            Do{
                $SystemPath      = "$($arrDriver[$i]):"
                $DestinationPath = "$SystemPath$WindowsPath"
                Write-Host " - Checking if Drive: $DestinationPath exist ..."
                
                if (Test-Path $DestinationPath){
                    Write-Host
                    Write-Host " --> Drive: [$DestinationPath] Found it  - continuing script ..."
                    $search = 0
                    $Comp_Info | Add-Member -type NoteProperty -name "System32"   -Value ($DestinationPath)
                    $Comp_Info | Add-Member -type NoteProperty -name "SystemPath" -Value ($SystemPath)
                }
                $i++
                Start-Sleep 1
            } While ($search -eq 1)
	    } catch {
		    write-Warning " - Fail to get Computer Info"
            # sleep for 20 sec
            start-sleep 20
            exit
        } #endtry
    } #endprocess
} #endfunction

# ---------------------------------------------------------------------------------------------
function MapNetworkDrive
{
    <#
    .SYNOPSIS
        Gets info from Computer
    .DESCRIPTION
        GET Computer Name, Model, OS, COU, RAM, Video, HD, MAC and IP
    #>
	[CmdletBinding()]
    Param(
		[Parameter(Position=1)]
		[Boolean]$DebugMode
    )
	PROCESS 
    {
	    try {

            write-host " - Starting mapping ..."
            $DriverLetter = "W:"
            $Password     = "PASSWORD"
            $UserName     = "SERVERNAME\USERNAME"
            $DriverPath   = "\\SERVERNAME.DOMAIN\DriverFolder"

            if (Test-Path $DriverLetter -erroraction SilentlyContinue) {
                write-host "- Drive already mapped."
            } else {

                # Initialize WMI Object
                $objWscriptNetwork = new-object -com wscript.network
                $objWscriptNetwork.MapNetworkDrive($DriverLetter, $DriverPath, $false, $UserName, $Password)

                if (Test-Path $DriverLetter -erroraction SilentlyContinue) {
                    write-host " - Drive successfully mapped."
                } else {
                    write-warning " - ERROR: Drive did not get mapped!"
                    start-sleep 20
                    exit
                } #endif
            } #endif

	    } catch {
		    write-Warning " - Fail to Map Network Drive"
            # sleep for 20 sec
            start-sleep 20
            exit
        } #endtry
    } #endprocess
} #endfunction

# ---------------------------------------------------------------------------------------------
Function RunProcess
{
    <#
    .SYNOPSIS
        Run a specific Process
    .DESCRIPTION
        Runs a Process, EXE and wait untill is done
    .EXAMPLE
        RunProcess -PathtotheApplication "{Application Path and EXE}
    .EXAMPLE
        RunProcess -PathtotheApplication "{Application Path and EXE} -ApplicationArgument "{Special Arguments}"
    .EXAMPLE
        RunProcess -PathtotheApplication "{Application Path and EXE} -ApplicationArgument "{Special Arguments}" -Msg "{Display a message}"
    #>
	[CmdletBinding()]
    Param(
        [Parameter(Mandatory=$True,Position=1)]
		[ValidateScript({Test-Path $_})]
        [string]$FilePath,
		
		[Parameter(Position=2)]
		[string]$App_Argument,

		[Parameter(Position=3)]
		[string]$Msg,

		[Parameter(Position=4)]
		[Boolean]$DebugMode
    )
	PROCESS 
    {
        try {
                $Proc = ""
       		    if ($Msg -ne $null ) {
            	    write-host " - Launching Application  : $Msg" }

       		    if ($DebugMode) {
                    Write-Host " - Path to the Application: [$FilePath]"
                    Write-Host " - Application Argument   : [$App_Argument]"
                }

                #start process
                if (($App_Argument -eq $null) -or ($App_Argument -eq "")){
                    #$Proc = Start-Process $FilePath$FileName -Wait -PassThru -ErrorVariable +err -WarningAction SilentlyContinue
                    $Proc = Start-Process $FilePath -Wait -PassThru
                }else{
                    $Proc = Start-Process $FilePath -Argument $App_Argument -Wait -PassThru
                }

                $Run_Info = New-Object System.Object 
                $Run_Info | Add-Member -type NoteProperty -name "ExitCode" -Value ($Proc.ExitCode)

                Write-host " - Exit Code              : $($Proc.ExitCode)"
                start-sleep 4
	    } catch {
            write-Warning $Error
        } #end try
    } #end process
}


 
try {

    # -----------------------------------------------------------------------------------------
    # Main Program
    Write-Host "------------------------------------------------------------------------------"
    Write-Host "- ************** -     Altiris WinPERollOut Script Utility - *************** -"
    Write-Host "------------------------------------------------------------------------------"
    Write-Host "-                                                                            -"
    Write-Host "-                                                          Update 2014/07/01 -"
    Write-Host "- Academic Technology                                                Ver 1.0 -"
    Write-Host "------------------------------------------------------------------------------"
    Write-Host "- Retrieving Machine Info:                                                   -"
    Write-Host "------------------------------------------------------------------------------"
    . Get-ComputerInfo
    Start-Sleep 2
    Write-Host
    Write-Host "------------------------------------------------------------------------------"
    Write-Host "- Mapping Driver folder:                                                     -"
    Write-Host "------------------------------------------------------------------------------"
    . MapNetworkDrive
    Start-Sleep 2
    Write-Host
    Write-Host "------------------------------------------------------------------------------"
    Write-Host "- Injecting drivers into the image:                                          -"
    Write-Host "------------------------------------------------------------------------------"
    if(Test-Path "$DriverLetter\Drivers\Win7x64\$($Comp_Info.Model)" -ErrorAction SilentlyContinue) {
        Write-Host " - Loading Drivers ..."
        $argument = "/image:$($Comp_Info.SystemPath)\ /scratchdir:`"$($Comp_Info.SystemPath)\windows\temp`" /Add-Driver /driver:`"$DriverLetter\Drivers\Win7x64\$($Comp_Info.Model)`" /ForceUnsigned /recurse /norestart"
        . RunProcess -FilePath "$DriverLetter\Scripts\DISMx86\dism.exe" -App_Argument $argument -Msg "dism.exe"
        Write-Host " - Finished Loading Drivers ..."
    } else {
        Write-Host " - Skipping Driver: Computer Model Folder doesn't exist."
    }
    Start-Sleep 2
    Write-Host
    Write-Host "------------------------------------------------------------------------------"
    Write-Host "- Remove the Shared Drive from Altiris Server:                               -"
    Write-Host "------------------------------------------------------------------------------"
    RunProcess -FilePath "X:\Windows\System32\net.exe" -App_Argument "use $DriverLetter /delete" -Msg "net use"
    Start-Sleep 2
    Write-Host
    Write-Host "------------------------------------------------------------------------------"
    Write-Host "- Altiris WinPERollOut Script - Done                                         -"
    Write-Host "------------------------------------------------------------------------------"
    Write-Host "-                                         Developed By - Academic Technology -"
    Write-Host "------------------------------------------------------------------------------"
    
    # sleep for 20 sec
    Start-Sleep 20
    
} catch {
    $Error
} #endcatch

 

Jan 09, 2015 04:19 PM

Thanks!

The driver script is a bit legacy for us, since it's been around in some form or another for over a decade at this point, which is why it's a batch script. I think at some point back when we used PXE we had pared our winpe down for size and didn't have the scripting components to use vbscript.

The choice to let setup handle driver installs is another legacy decision from the XP days before DISM. In XP we had an additional helper utility to parse the subfolder tree of the drivers folder and add each one to the devicepath since XP setup driver installation did not traverse subdirectories. In Win7, DISM in winpe vs setup/devicepath to me seems a bit of "six of one half a dozen of the other." Setup is just doing the equivalent of a DISM /Add-Driver anyway. We like to have the driver folder on the deployed image in the event someone gets clever and decides to update drivers themselves and breaks things, so letting setup take care of it just seemed appropriate.

Jan 09, 2015 02:52 PM

sfucher - Great artical.

My spin on this process is 1. I use vbscipt most of the time, I just know it better. 2. I use loginw to create a password file and copy that into winpe as needed. It allows me to be a little more flexible on what user accounts I use and yet keep the password relatively secure (not plan text). 3. I use DISM while still in WinPE to inject the drivers.

I like the option of using OEMSetup, I was considering using just a generic batch file under each model folder and calling that in the task sequence. The handful of systems that I am currently managing have played well with DISM so I haven't needed to take this step.   

One note on hardware model, in my vbscript, I had to trim the computer model, it had extra spaces at the end of some models.

The below script is not a complete script but it gives you a good base on how to use DISM with the various options. Please keep in mind that I'm currently in a new environment and this script is still in Bata.

 

DIM objWshShell, objFSO, objWMIService
DIM colLogicalDisks, colItems
DIM compModel, CompManf

Set objWshShell = CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colLogicalDisks = objWMIService.ExecQuery("Select Name from Win32_LogicalDisk Where MediaType = '12'")
Set colItems = objWMIService.ExecQuery("Select * from Win32_Computersystem")

' Find Windows Directory of Image 
' On Error Resume Next
' File system errors for virtual drives
If colLogicalDisks.Count > 0 Then
   For Each objLogicalDisks In colLogicalDisks
      strTmpDrv = objLogicalDisks.Name
      If objFSO.FolderExists(strTmpDrv & "\Windows\Tasks\") Then
 strDrv = strTmpDrv
 Wscript.Echo "Selected Drive: " & strDrv
 strLogFileName = strDrv & "\Windows\Temp\DriverInjection.log" 'Log file
      End If
   Next
End If

' Use WMI to pull Hardware Model
For Each Item In colItems
    CompManf = TRIM(Item.Manufacturer)
    compModel = TRIM(Item.Model)
Next

' Should I copy Drivers?
Select Case True
 Case Instr(1,CompManf,"VMware",1) <> 0
      Wscript.Echo "VMware doesn't need drivers"
         Wscript.Sleep (30000)
         Wscript.quit (0)
 Case Instr(1,CompManf,"Dell",1) <> 0
         Wscript.Echo "Installing Dell Drivers"
         InstallDvr compModel, strLogFileName
    Case Instr(1,CompManf,"H",1) <> 0
         Wscript.Echo "Installing HP Drivers"
         InstallDvr compModel, strLogFileName
    Case Instr(1,CompManf,"Lenovo",1) <> 0
         Wscript.Echo "Installing Lenovo Drivers"
         InstallDvr compModel, strLogFileName
 Case Else
   Wscript.Echo "I don't recognize this hardware, please provide your own drivers"
         Wscript.Sleep (30000)
         Wscript.quit (0)
End Select

If objFSO.FolderExists("Y:\Win7\" & compModel) Then

   strCMD1 = "DISM /Image:" & strDrv & " /scratchdir:" & strDrv & "\Windows\Temp /Add-Driver /Driver:" & Chr(34) & "Y:\Win7\" & compModel & "\x64" & Chr(34) & " /recurse /ForceUnsigned /norestart /logpath:" & strLogFileName

Jan 09, 2015 09:37 AM

I use a VMWare VM, without VMWare Tools installed. Literally zero drivers that aren't already in the OS required. Standard VM settings except I change the virtual disk to IDE so no SCSI drivers are needed.

Jan 09, 2015 09:24 AM

No luck with logs so far.  It's almost like it thinks the standard driver is good enough so doesn't process the input driver in c:\drivers.

The only difference with this model is it's the one I used to build the base image, so I wonder if that's playing into it.  I'm going to see if I can get OEMSetup to get it working as it's not a model we'll support much longer.

Do you guys use a VM or one of your model computers for base image building?  

Thanks again

Jan 09, 2015 05:11 AM

For the record of driver installs during post sysprep setup you can look in c:\windows\panther\SetupAct.log and c:\windows\inf\setupapi.dev.log.
I found with trying to use the setup.exe for the Lenovo UltraNav driver (a Synaptics device) that it seemed to be quite sensitive to what had gone before, that it was best to run the setup immediately after a reboot.

Jan 08, 2015 03:53 PM

You're welcome! I'm glad to hear it's working for you. At first I was fairly meticulous about just copying in drivers that were needed like you are, but we had too many models where depending upon when we ordered it they had different hardware options installed and I got tired of having to revisit the driver folders unexpectedly. Basically, I'm lazy and we had the disk space to burn. ;)

I'm not sure on the touchpad driver. We don't have any E5420's, we went with the E6xxx series in that generation. I've never had a driver not install when it works via device manager. The bluetooth issues we had with older models were because the helper app that the setup.exe installed had to be installed for bluetooth to work correctly. The actual bluetooth device drivers showed installed in device manager, bluetooth just didn't work without the app. If device manager driver update works for you, that's not likely the case here.

Jan 08, 2015 02:44 PM

Shawn, I can’t thank you enough for posting this. That script and the screenshots really helped. It seems too simple to be true, but it works great. All of our models are working with 64 bit windows 7 after minimal effort and will tackle 32 bit next.

The only changes I had to make were to copy the files to d instead of c (in PXE our C drive is the 100MB bitlocker partition). To try to minimize stuff on the share, I started by creating empty folders on the share so a test job finishes, then in production see what drivers are missing on each system, then put just those drivers on the share from the dell cab site (http://en.community.dell.com/techcenter/enterprise-client/w/wiki/2065.dell-command-deploy-driver-packs-for-enterprise-client-os-deployment) and redeploy and check.

I love that doing it this way I know exactly what drivers are being deployed to each model. I think DA will eventually be similar with their tagging feature, but I love how clean the sharepoint is to understand and if I go this route, I don’t have to worry about DS upgrades breaking DA on me again.

The only thing I am having trouble with is the Dell Touchpad drivers on Latitude E5420s.  On every other Dell laptop, I copy the right input driver folder over, and it retargets properly.  On the 5420 the input driver folder copies over, but doesn't install and not sure why.

In device manager in production, if I point the generic 'mouse' driver to the copied over folder in c:\drivers it does install properly so I know it's the right driver.  There is an exe I guess I could run via the oemsetup script, but sure would've liked to avoid that.  

Let me know if anyone has any ideas on the Touchpad?

Jan 08, 2015 12:32 PM

Exactly what I needed, thanks Shawn.  I was making a stupid mistake (my share had the right folder name, but I didn't follow the structure properly on new folders).  Thanks for taking the time to reply, Andy too.

Jan 08, 2015 10:48 AM

Echo %modelname% should work, except for inside the For loops because of the delayed expansion (use ! in there). You might change it to echo "%modelname%" so if modelname is empty it will echo the empty quotes. This is what I suggest:

...
Echo Retrieving Model Name...
For /F "tokens=2 delims==" %%A In ('WMIC computersystem get model /format:VALUE') Do Set STR=%%A
SET MODELNAME=%STR%
echo "%MODELNAME%"
For /L %%A in (1,1,50) Do If "!MODELNAME:~-1!"==" " (Set MODELNAME=!MODELNAME:~0,-1! & echo "!MODELNAME!")
echo "%MODELNAME%"
pause
...

This will tell you the result of the tokenization (getting the second line from WMIC get...), the results of the trimming of trailing spaces as it trims, and the final result.

Edit: also it helps to add a pause at the end of that section of the script so you can see the output in winpe on the client you're testing. I added one to the snippet above. You'll want to remove that once you're done troubleshooting.

Jan 08, 2015 10:44 AM

After %MODELNAME% is set just add a line:
echo %MODELNAME% > c:\drivers\modelname.txt

Jan 08, 2015 09:34 AM

This has been really helpful, I've gotten pretty far with it.

Can someone help me that in the script output it would print the result of what %MODELNAME% is?

I got a few models working great, but I have a few other Dell models where the script is failing.

If I run WMIC computersystem get model - it matches my folder name, but something seems to be off.  I was thinking if I could get the script to output what it's trying to match on it may help.

I was hoping it was echo %modelname% but no dice.  

Jan 05, 2015 08:57 AM

The only thing I can suggest is make sure you download the WinPE 4 driver pack for the model in question. We had at least one case on an HP laptop (Elitebook 820 G1 I think) where the Windows 8 NIC driver would not work correctly in automation but the NIC driver in the WinPE driver pack worked fine.

Jan 05, 2015 05:39 AM

Great article, thanks for posting!

Would you by any chance also have a trick for computer models that refuse to pick up the NIC or Mass Storage drivers during WinPE/Automation?
Had a specific case with an HP model where the driver DID come down to the client in Automation/PE, but the NIC wouldn't be detected automatically, while the DRVLOAD.EXE tool DID work. Obvioulsy not ideal to always run this manually in order to get the NIC working (which is required before Altiris can do anything else).

Personally I'm really looking forward to the updated DeployAnywhere module that was announced during the Deployment Solution webcast last December. The driver tagging feature will allow for drivers to be pushed/forced onto specific clients.

Dec 30, 2014 12:39 PM

To get round the driver bloat problem I do two things:
1/ Extract only the files you need from the driver set, most driver sets come with the setup.exe files you don't use and infs and drivers for many OSs you're not using.
2/ Consider putting some of the smaller inf based sets into the image during your initial scripted install prior to sysprep, I use the Offline Servicing pass. As an example, in the build I am working on at the moment for three HP desktops, two Toshiba laptops and two Lenovo laptops, the inf based driver sets for NIC, Chipset, Mass Storage and Intel AMT hardware comes to 8MB, 147 files in 31 folders. The three desktops, two Tosh laptops and one of the Lenovos share two NIC drivers and two chipset drivers are shared across a desktop and laptop each. The newest laptop mass storage driver works for all models.

Related Entries and Links

No Related Resource entered.