• Recent
  • Unsolved
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Register
  • Login
  • Recent
  • Unsolved
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Register
  • Login

FOG Post install script for Win Driver injection

Scheduled Pinned Locked Moved
Tutorials
18
69
43.3k
Loading More Posts
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • G
    george1421 Moderator @acatalepsy
    last edited by Apr 21, 2022, 3:02 PM

    @acatalepsy First I would follow the instructions in this post: https://forums.fogproject.org/topic/11126/using-fog-postinstall-scripts-for-windows-driver-injection-2017-ed

    I realize its 4 year old information but its still accurate and works for Win10. The thing you have to remember is that linux is case sensitive so you need to make sure your data path to the drivers is in the case format that is known and expected. You can surely debug your setup and make it work.

    Please help us build the FOG community with everyone involved. It's not just about coding - way more we need people to test things, update documentation and most importantly work on uniting the community of people enjoying and working on FOG!

    1 Reply Last reply Reply Quote 0
    • D
      DVBNL
      last edited by Aug 3, 2022, 12:04 PM

      I’m experiencing an issue with a Dell OptiPlex 3090. In the postscript:

      “/images/postdownloadscripts/fog.copydrivers: command substitution: line 14: syntax error near unexpected token ‘;;’”

      manu=dmidecode -s system-manufacturer; >> is working fine since it’s returning the next line of code:

      “echo “Unable to identify the hardware for manufacturer ${manu}”;”
      result:
      “Unable to identify the hardware for manufacturer Dell Inc.”

      case $manu in
          [Ll][Ee][Nn][Oo][Vv][Oo])
              machine=$(dmidecode -s system-version)
              ;;
          *[Dd][Ee][Ll][Ll]*)
              machine=$(#)
              ;;
          *I[Nn][Tt][Ee][Ll]*)
              # For the Intel NUC and intel mobo pick up the system type from the
              # baseboard product name
              machine=$(dmidecode -s baseboard-product-name)
              ;;
          *)
              # Technically, we can remove the Dell entry above as it is the same as this [default]
              machine=$(dmidecode -s system-product-name) 
              ;;
      esac
      

      Somewhere in the above code the script is unable to retrieve the product name. I’m still debugging this but maybe someone already resolved this issue?

      D J 2 Replies Last reply Aug 3, 2022, 12:41 PM Reply Quote 0
      • D
        DVBNL @DVBNL
        last edited by DVBNL Aug 3, 2022, 6:42 AM Aug 3, 2022, 12:41 PM

        @dvbnl

        Fixed it with the following code:

        #!/bin/bash
        ceol=`tput el`;
        manu=`dmidecode -s system-manufacturer`;
        dots "Identifying hardware"
        case $manu in
            [Ll][Ee][Nn][Oo][Vv][Oo])
                machine=$(dmidecode -s system-version)
                ;;
            *I[Nn][Tt][Ee][Ll]*)
                # baseboard-product-name
                machine=$(dmidecode -s baseboard-product-name)
                ;;
            *)
                # system-product-name
                machine=$(dmidecode -s system-product-name)
                ;;
        esac
        
        J 1 Reply Last reply Aug 10, 2022, 3:26 PM Reply Quote 1
        • J
          JJ Fullmer Testers @DVBNL
          last edited by Aug 8, 2022, 9:05 PM

          @dvbnl It’s the “.” in “Dell Inc.”
          I was just implementing this and found an issue with “Vmware Inc.” specifically the “.” not being seen as part of the string.

          I chose to remove any trailing dots in the manufacturer name.

          add this second manu definition, and it should help move you forward.

          manu=`dmidecode -s system-manufacturer`;
          manu="${manu%.*}";
          

          I would also add below it something like

          if [[ "${manu}" == "Dell Inc" ]]; then manu="Dell"; fi
          

          If you are structuring your folders with the name “Dell” rather then Dell Inc

          Have you tried the FogApi powershell module? It's pretty cool IMHO
          https://github.com/darksidemilk/FogApi
          https://fogapi.readthedocs.io/en/latest/
          https://www.powershellgallery.com/packages/FogApi
          https://forums.fogproject.org/topic/12026/powershell-api-module

          G 1 Reply Last reply Aug 8, 2022, 9:10 PM Reply Quote 1
          • G
            george1421 Moderator @JJ Fullmer
            last edited by Aug 8, 2022, 9:10 PM

            @jj-fullmer So how would you propose to tweak this code:

            #!/bin/bash
            ceol=`tput el`;
            manu=`dmidecode -s system-manufacturer`;
            dots "Identifying hardware"
            case $manu in
                [Ll][Ee][Nn][Oo][Vv][Oo])
                    machine=$(dmidecode -s system-version)
                    ;;
                *[Dd][Ee][Ll][Ll]*)
                    machine=$(dmidecode -s system-product-name)
                    ;;
                *I[Nn][Tt][Ee][Ll]*)
                    # For the Intel NUC and intel mobo pick up the system type from the
                    # baseboard product name
                    machine=$(dmidecode -s baseboard-product-name)
                    ;;
                *)
            

            ref: https://forums.fogproject.org/topic/11126/using-fog-postinstall-scripts-for-windows-driver-injection-2017-ed

            I need to look because someone else just recently found a bug in this section of code too. Maybe I need to update/create a 2022 version of this post. The 2017 version is still accurate even in 2022 (maybe)

            Please help us build the FOG community with everyone involved. It's not just about coding - way more we need people to test things, update documentation and most importantly work on uniting the community of people enjoying and working on FOG!

            J 1 Reply Last reply Aug 10, 2022, 4:10 PM Reply Quote 0
            • J
              JJ Fullmer Testers @DVBNL
              last edited by Aug 10, 2022, 3:26 PM

              @dvbnl Looking at it again, that makes sense, the old code had it setting all Dell manufactured systems to nothing.

              Have you tried the FogApi powershell module? It's pretty cool IMHO
              https://github.com/darksidemilk/FogApi
              https://fogapi.readthedocs.io/en/latest/
              https://www.powershellgallery.com/packages/FogApi
              https://forums.fogproject.org/topic/12026/powershell-api-module

              1 Reply Last reply Reply Quote 0
              • J
                JJ Fullmer Testers @george1421
                last edited by Aug 10, 2022, 4:10 PM

                @george1421 I was intending on sharing my changes in that 2017 post on drivers and on the unattend updates by the end of this month (still making sure everything is stable and will have to universalize a bit)
                Granted, the only changes I made for the drivers related to how I structure my driver packs. Like I don’t have anything other than 64 bit windows 10, so I didn’t need all the os code stuff or a structure matching that. I also have driver packs that fit multiple models, in windows/powershell I found ways to match models based on the folder name but wasn’t able to recreate that syntax in bash (I’m sure it can be done, I just didn’t want to put in the time). So instead I added a ModelList.txt file in each driver pack and have it use grep to search all of those files for the model of the machine. This also helps in handling spaces in the folder structure and model name, as I didn’t want to recreate my entire driver folder structure without spaces. So I didn’t need the bit that removes spaces from the make\model (I also change manu to make and machine to model). I also had to add bits as mentioned below for the makes that have a ‘.’ as it was seeing that as a command in some cases.

                I also had some notes on how and when the drivers are added in windows, as you can use the unattend.xml to deploy them during the specialize phase before it gets to oobe. You also can do pnputil without the /install flag first so that all the drivers are added to the pnp store so once they are visible they will auto add in windows.

                Also the unattend update example mentions putting the password in plaintext, but the fos console has access to the $adpass variable from the host information. So it can pass that to the unattend without displaying it. I would also add a note about being sure the unattend.xml files should be deleted.

                I don’t know why I waited so long to play with the driver injection and other postdownload scripts, once I did I added so many improvements in speed and stability to my provisioning system.

                I also added a log file for what is copied down that is visible inside of windows, basically had it pipe to said log file instead of to null.

                This is what my snippet looks like for getting the model

                ceol=`tput el`;
                make=`dmidecode -s system-manufacturer`;
                make="${make%.*}";
                
                dots "Identifying hardware"
                
                if [[ "${make}" == "Hewlett-Packard" ]]; then make="hp"; fi
                if [[ "${make}" == "HP" ]]; then make="hp"; fi
                if [[ "${make}" == "Hp" ]]; then make="hp"; fi
                if [[ "${make}" == "VMware, Inc" ]]; then make="VMware"; fi
                
                
                case $make in
                    [Ll][Ee][Nn][Oo][Vv][Oo])
                        model=$(dmidecode -s system-version)
                        ;;
                    *[Ii][Nn][Tt][Ee][Ll]* | *[Aa][Ss][Uu][Ss]*)
                        # For the Intel NUC and intel mobo pick up the system type from the
                        # baseboard product name
                        model=$(dmidecode -s baseboard-product-name)
                        ;;
                    *)
                        # Technically, we can remove the Dell entry above as it is the same as this [default]
                        model=$(dmidecode -s system-product-name) 
                        ;;
                esac
                
                # if the model isn't identified then no need to continue with this script, just return to caller
                if [[ -z $model ]]; then 
                    echo "Unable to identify the hardware for manufacturer ${make}";
                    debugPause;
                    return;
                elif [["${model}" == "Surface Go"]]; then
                    echo -en "\n\nSurface Go will also match other generations of Surface Go, adding a 1\n\n"
                    model="Surface Go 1";
                fi 
                
                echo "${model} Identified";
                
                

                Then I find the driver pack to copy like this

                dots "Preparing Drivers"
                #folder to copy into, I create this when I setup my image and also embed a small selection of storage drivers that aren't included in the default windows install (.i.e any that require loading a driver when installing windows manually such as intel vmd/raid types or vmware paravirtual scsii) These are added during audit system phase of sysprep
                clientdriverpath="/ntfs/Out-Of-Box Drivers"
                #the driverstore is organized as make/model but that Model folder can apply to multiple models (i.e. hp shares a driver pack for all the form factors of hp elitedesk/prodesk 400/600/800 g#)
                #define the base make path, and cd to it, helps with handling spaces in the path
                makePth="/images/drivers/${make}"
                cd $makePth;
                #find the model in a modellist.txt using grep. I used the API to get all my hosts and then sorted the inventory to show me all the unique makes/models and used that to built the modellist.txt files so that they would match what is found here.
                listFile=`grep -il "$model" ./*/*-ModelList.txt`
                #set the remote driver path to the parent folder of the modellist.txt where it was found
                remotedriverpath="$makePth/${listFile%/*}"
                #define the log file that will be visible
                injectLog="/ntfs/logs/driverInjection.log"
                

                Then I get ready to copy

                #I set up a generic/universal driver pack of network/storage/chipset drivers that I've found aren't included in the default windows install that I've found through trial and error. It probably has a bunch of duplicates (so I call it a hodgepodge) but it helps to get the machine on the network so it can find the drivers it needs when a driver pack wasn't found. 
                if [[ ! -d "${remotedriverpath}" ]]; then
                    echo "failed";
                #output to console and output to log
                    echo " ! Driver package not found for ${model} copying hodgepodge! ";
                    echo " ! Driver package not found for ${make} ${model} copying hodgepodge universtal oobe drivers ! " > $injectLog;
                    remotedriverpath="/images/drivers/generic/universal"
                    debugPause;
                else 
                # output to console and output to log
                    echo " Driver package for ${make} ${model} found! ${removedriverpath} will be copied to ${clientdriverpath}";
                    echo " Driver package for ${make} ${model} found via ${listFile}! ${removedriverpath} will be copied to ${clientdriverpath}" > $injectLog;
                fi 
                
                cd /;
                echo "Ready";
                
                echo -en "Driver Injection In Progress\n\n\n"
                
                echo -en "Driver Injection In Progress\n\n"
                #I removed the -q and tried to add a progress bar to no avail, but also found that rsync displayed a message saying to use -zz instead of -z for sending with compression, since the output is piped to a log, I kept -q out of it to get more verbose logging
                rsync -azz "$remotedriverpath" "$clientdriverpath" >> $injectLog;
                
                echo -en "Drivers.cmd Injection In Progress\n\n"
                #this is the drivers.cmd file used during specialize to add drivers
                rsync -azz "/images/drivers/drivers.cmd" "/ntfs/drivers.cmd" >> $injectLog;
                # I also copy additional files here following this same syntax
                
                [[ ! $? -eq 0 ]] && handleError "Failed to download driver information for [$model] or other files failed to copy"
                
                debugPause
                

                This is the contents of drivers.cmd

                echo "Adding drivers to driver store...."
                start pnputil.exe /add-driver "C:\Out-Of-Box Drivers\*.inf" /subdirs
                echo "Installing drivers for present devices...."
                start pnputil.exe /add-driver "C:\Out-Of-Box Drivers\*.inf" /install /subdirs
                

                This is the part of the sysprep unattend under the specialize phase I use to call it

                 <component name="Microsoft-Windows-Deployment" 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">
                            <!-- I have other settings inside this component, this is just to show the synchronous command in the component-->
                            <!-- commands to run in order during specialize -->
                            <RunSynchronous>
                            <!-- add and or install the injected drivers and then reboot -->
                                <RunSynchronousCommand wcm:action="add">
                                    <Path>C:\drivers.cmd</Path>
                                    <Order>1</Order>
                                    <Description>Add Injected Drivers</Description>
                                    <WillReboot>Always</WillReboot>
                                </RunSynchronousCommand>
                                <!-- Additional commands to run before getting to oobe, I use this for configuring built in windows features using dism powershell commands and I have a powershell function that detects nvidia drivers and attempts to install the graphics driver. This .cmd file just opens a .ps1 file -->
                                <RunSynchronousCommand wcm:action="add">
                                    <Order>2</Order>
                                    <Description>Pre-req steps</Description>
                                    <Path>C:\step0.cmd</Path>
                                    <WillReboot>Always</WillReboot>
                                </RunSynchronousCommand>
                            </RunSynchronous>
                            <!-- I have a case statement in my unattend updater to set the correct device form. This affects some UI settings in windows, I use 3 as a default as it is a normal desktop pc, there are also ones for detachable or convertible tablets, all in one machines, and many others. You can also just omit this-->
                            <DeviceForm>3</DeviceForm>
                        </component>
                

                This above component needs to be in the specialize settings block, i.e.

                   <settings pass="specialize">
                        <!-- other specialize components-->
                       <component name="Microsoft-Windows-Deployment" 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">
                           <!-- stuff from above -->
                       </component>
                   </settings>
                

                I recommend using windows system image manager (https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/wsim/windows-system-image-manager-technical-reference) for creating your initial unattend file.

                Have you tried the FogApi powershell module? It's pretty cool IMHO
                https://github.com/darksidemilk/FogApi
                https://fogapi.readthedocs.io/en/latest/
                https://www.powershellgallery.com/packages/FogApi
                https://forums.fogproject.org/topic/12026/powershell-api-module

                C 1 Reply Last reply Dec 16, 2022, 3:04 PM Reply Quote 0
                • C
                  Coolguy3289 @JJ Fullmer
                  last edited by Dec 16, 2022, 3:04 PM

                  @jj-fullmer Can you clarify a bit more on your file structure and the placement of the ModelList.txt file? I’m trying to duplicate your success but I’m having a little trouble with the remotedriverpath variable.

                  J 1 Reply Last reply Mar 31, 2023, 1:35 PM Reply Quote 0
                  • G george1421 referenced this topic on Mar 27, 2023, 10:21 AM
                  • J
                    JJ Fullmer Testers @Coolguy3289
                    last edited by Mar 31, 2023, 1:35 PM

                    @Coolguy3289 Sorry for the crazy delayed reply, I just saw this, I must have missed the notification

                    This is what my general structure looks like. You would not need to recreate that with the + pseudo wildcards, that is part of my windows side matching that I have now actually replaced with this modellist method. The grep line will search each model folder in the given make folder regardless of its name. I will probably end up changing those folders to be something like HP ElitePro G# or something like that.

                    e880c851-3f3c-418d-adb9-8ff886199667-image.png

                    Then say I have a HP Elite Mini 600 G9 Desktop PC

                    This bit

                    makePth="/images/drivers/${make}"
                    cd $makePth;
                    

                    Should get me into the /images/drivers/hp folder

                    Then this listFile=`grep -il "$model" ./*/*-ModelList.txt` should search each HP ModelList.txt for that model string using grep and return the matching modelList file with a match. In this case it would match /images/drivers/hp/HP + +00 G9+/HP + +00 G9+-ModelList.txt as that file looks like this where I have various possible matching model names these drivers apply to including the one being searched for

                    HP Elite Mini 600 G9 Desktop PC
                    HP Elitedesk 600 G9 DM
                    HP Elite Mini 800 G9 Desktop PC
                    HP Pro Mini 400 G9 Desktop PC
                    HP EliteOne 840 23.8 inch G9 All-in-One Desktop PC
                    

                    And then this remotedriverpath="$makePth/${listFile%/*}" should point to the parent path of where the found ModelList.txt file was found and it will then proceed to inject that folder to `C:\Out-Of-Box Drivers\HP + +00 G9+

                    And as to creating those modelList.txt files, it’s easier than it sounds, especially if you use the fog api powershell module FogApi (see my signature).

                    For example, to get all my current HP (and any other make that stores the friendly name of their model in system-product-name) model names as they are detected by fog you would setup the FogApi module in powershell

                    Install-Module FogApi;
                    Set-FogServerSettings -interactive
                    

                    Then this one liner would get all your fog host inventories, select just the sysman and sysproduct fields, and then sort it to unique model names giving you a list of model names you have in your inventory

                    (get-foghosts).inventory | select-object sysman,sysproduct | sort-object sysproduct -Unique
                    

                    You’d also what to run these other 2 commands to get lists of other model names stored in system-version or baseboard-product-name

                    (get-foghosts).inventory | select-object sysman,sysversion | sort-object sysversion -Unique
                    (get-foghosts).inventory | select-object sysman,mbproductname | sort-object mbproductname -Unique
                    

                    You could probably expound from there to programatically create to folder structure and the modelList files of your current hosts, but I don’t have time at the moment to get that deep into it. I don’t have that many different models and already had the folder structure so just getting those lists was all I needed to construct the model list files

                    Have you tried the FogApi powershell module? It's pretty cool IMHO
                    https://github.com/darksidemilk/FogApi
                    https://fogapi.readthedocs.io/en/latest/
                    https://www.powershellgallery.com/packages/FogApi
                    https://forums.fogproject.org/topic/12026/powershell-api-module

                    1 Reply Last reply Reply Quote 0
                    • G george1421 referenced this topic on Apr 4, 2023, 10:08 PM
                    • G george1421 referenced this topic on Jan 3, 2024, 7:42 PM
                    • J JJ Fullmer referenced this topic on Jan 11, 2024, 1:57 PM
                    • J JJ Fullmer referenced this topic on Jul 16, 2024, 6:31 PM
                    • G george1421 referenced this topic on Jul 29, 2024, 9:02 PM
                    • 1
                    • 2
                    • 3
                    • 4
                    • 4 / 4
                    • First post
                      Last post

                    168

                    Online

                    12.0k

                    Users

                    17.3k

                    Topics

                    155.2k

                    Posts
                    Copyright © 2012-2024 FOG Project