Utilizing Postscripts (Rename, JoinDomain, Drivers, Snapins)


  • Developer

    Hi All,

    i haven’t got round to it until now but i thought i’d share how i used postscripts to give the community ideas of how it could be used and how potentially powerful postscripts really can be. i’ll try to notation anything that may not make sense and try not to fill this thread full of code! i’ll seperate each “file script” into a new post

    so under /images/postdownloadscripts i have the following files:
    fog.ad, fog.drivers, fog.postdownload, fog.snapins (rather than having a bulk of code just in fog.postdownload - keeps it nice and seperate)

    THE FOG.POSTDOWNLOAD (the script that directs everything i guess you could say)
    fog.postdownload contains:

    [CODE]if [ $osid == “5” -o $osid == “6” -o $osid == “7” ]; then #only handling Win7/8/8.1
    clearScreen;
    mkdir /ntfs &>/dev/null
    ntfs-3g -o force,rw $part /ntfs #mount image (remember this is mounting partition [U][B]after[/B][/U] new image is deployed)
    mkdir /fog &>/dev/null
    mount -o nolock,proto=tcp $storageip:/fog/ /fog #this is a share created on server under /fog which contains drivers, software etc… (just add /fog to exports but you could use existing location i.e. /images and if you do, do not need to do this mount as /images is still mounted at this point)
    dots “Mounting Device”;
    if [ “$?” = “0” ]; then
    echo “Done”;
    . ${postdownpath}fog.drivers # run fog.drivers script
    . ${postdownpath}fog.ad # then run fog.ad … you get the jist
    . ${postdownpath}fog.snapins
    umount /ntfs; # unmount when all is done :-)
    else
    echo “Failed To Mount Device”;
    sleep 30;
    fi
    fi[/CODE]



  • This post is deleted!

  • Developer

    This post is deleted!

  • Moderator

    @Raj-G said in Utilizing Postscripts (Rename, JoinDomain, Drivers, Snapins):

    Silly question on the FOG client, but I gather you’re referring to the web client on the FOG server we’re using correct?

    Correct.

    @Raj-G said in Utilizing Postscripts (Rename, JoinDomain, Drivers, Snapins):

    The FOG Service on the host PC would pull from the information/data we have on the FOG server for printers, snap-ins, etc. correct?

    Right. You have to install this on your reference machine prior to image capture of course, and ensure it’s working before capturing by looking at the log file, typically located at C:\fog.log. The FOG Client is what enables lifetime management of hosts registered with the FOG Server.

    You may also find this wiki article very informative:
    https://wiki.fogproject.org/wiki/index.php?title=FOG_Client



  • @Lee-Rowlett
    Silly question on the FOG client, but I gather you’re referring to the web client on the FOG server we’re using correct? The FOG Service on the host PC would pull from the information/data we have on the FOG server for printers, snap-ins, etc. correct?

    Thanks!


  • Developer

    @Raj-G If you just put the executables in folder /fog/MapFiles they will just copy to root the of the imaged machine.

    all the fog.snapins script does it put things in place, set which node to use and which snapin to run.

    you’ll need to write the script to actually run and execute the installers etc… (setupcomplete.cmd)

    if you are unsure or uncomfortable scripting, you may be better off with the FOG client doing all the work for you, it’s very stable and much better going forward to maintain your image.

    this script/scenario is best suited if you already have another solution managing your clients but you want fog to handle the initial imaging. otherwise FOG Client is defo your friend :-)



  • Hi all,

    New user here, working with my team head to get a FOG server setup; all these scripts have been super useful for drivers and such. Just need to SysPrep our image and we’re good to go. That being said, I have a question about the Snap-Ins script here.

    We have just about the same software setup for most of the users for a client we service; however, we have about half our users who have a full Office 365 (Office 2016 install) and the others don’t, while we have a hodgepodge of users that use some specific apps for their work (scattered between folks who use Office 2016 and not).

    Do I simply put in the installation executables in the SnapinData/Map Files folders or does this script for Snap-Ins need to change? I’m not great at scripting at all, but I wondering what would need to change in this script.

    Script from @Lee-Rowlett as follows:

    #!/bin/sh
     
    snpchk=`wget -O - --post-data="mac=${mac}" "http://${web}service/snapcheck.php" 2>/dev/null` #checks for snapintask
    if [ "$snpchk" == "1" ]; then
        setupcmd="/ntfs/Windows/Setup/Scripts/SetupComplete.cmd";
        mkdir /ntfs/Windows/Setup/Scripts
        #this line below pulls my latest build script from server
        cp /fog/CompleteBuild/CompleteBuild.exe /ntfs/Windows/Setup/Scripts/CompleteBuild.exe  &>/dev/null
        #copies lastest setupcomplete.cmd from server
        #which only actually contains one line to execute
        #C:\Windows\Setup\Scripts\CompleteBuild.exe
        cp /fog/CompleteBuild/SetupComplete.cmd $setupcmd #above script
        sloc="/ntfs/Windows/Setup/Scripts/Node.txt"; # this is just so my above script
        #knows which node to use to run software from (if needed) left in to give you
        #guys ideas....
        echo "$storageip" >> "$sloc"; # writes node ip to the text file
        #next line gets snapin name
        snapname=`wget -O - --post-data="mac=${mac}&getSnapnames=1" "http://${web}service/snapcheck.php" 2>/dev/null`
        #next gets snapin argument/switch
        snaparg=`wget -O - --post-data="mac=${mac}&getSnapargs=1" "http://${web}service/snapcheck.php" 2>/dev/null`
        #this next line adds the switch to the setupcomplete.cmd
        # so if switch was /DefaultBuild .cmd line would now look like:
        #C:\Windows\Setup\Scripts\CompleteBuild.exe /DefaultBuild
        #if switch empty just nothing gets added
        sed -i -e "s|$| ${snaparg}|g" $setupcmd
     
        #this is self explanatory - some of our builds rely on 24GB of map files
        #rather than adding them to the "general" image
        #as it's the select few machines
        #i get fog to add it for me after imaging
        #so if they ever change, just update on server, job done.
        if [ "$snapname" == "MAP Build" -o "$snapname" == "Example Build" -o "$snapname" == "Test Build" ]; then
            dots "Downloading Map Files";
            echo "In Progress";
            rsync -a --info=progress2 "/fog/SnapinData/Map Files" /ntfs
            echo " * Downloading Map Files Completed.";
        fi
    else
        echo "No Snapin Task Found - Snapin Setup Skipped";
    fi```


  • I have been using the vendor/hardware ID to supply drivers to machines (this works well for the random bits we get from time to time that need re-imaging)

    However would ideally like to be able to utilise the scripts in this document to download the drivers based on vendor and machine type, while still retaining the functionality of pulling the drivers if the machine type does not exist (if for instance we didn’t have Windows 10 drivers for a Dell Optiplex 3020 then it would pull drivers based on vendor and hardware ID).

    Is anyone else doing anything like this or is it just not possible?

    Thanks


  • Moderator

    Two additional comments.

    This is the search command I had to use on Centos 7 to find the unattend file in the sysprep folder. It was a bit of a cheat (not looping through the found entries, but this way I knew only one file would be returned).

     unattendfile=`find /ntfs/Windows -type f -iname "unattend.xml"|grep ystem32`
    

    We since moved the only unattend file to the Panther folder since that is where Win10 searches first (we do specify the full path anyway when the system is sysprep’d). We did this to simplify the script since the case doesn’t change on Panther.

    The second thing we do is use this sed search to replace the computer name (just in case there is something for the computer name that isn’t a star ( * ). Its a little be more complex of a regex expression but it works in all cases.

    sed -i -e "s#<ComputerName>\([^<][^<]*\)</ComputerName>#<ComputerName>$hostname</ComputerName>#gi" $unattendfile
    

  • Moderator

    One point that I found if you use the /Windows/System32/sysprep folder, that name changes under Win10 to /Windows/System32/Sysprep this caused me a little pain (case change on the sysprep folder), until Tom gave me the hint to use find function. It does slow down the install a bit while find does its magic. You can cut down some of the time by specifying a path a bit closer like /ntfs/Windows since the unattend.xml file should be in there.


  • Senior Developer

    The beauty of the postdownloadscripts are that you can do whatever it is you need to do.

    If we’re unsure of where to find the unattend.xml (or whatever you wanted to name it) you can use basic linux utilities to locate them.

    For example, instead of:

    #!/bin/bash
    hostadpwd="ADPASSWDHERRE"; #only downside to this method- this is the plain ad password
    unattend="/ntfs/Windows/Panther/unattend.xml";
    [[ ! -f $unattend ]] && return
    dots "Preparing Sysprep File"
    rm -f /ntfs/Windows/System32/sysprep/unattend.xml >/dev/null 2>&1
    if [[ ! $? -eq 0 ]]; then
        echo "Failed"
        debugPause
        handleError "Failed to remove original unattend file"
    fi
    echo "Done"
    debugPause
    dots "Writing Computer Name"
    sed -i "/ComputerName/s/*/$hostname/g" $unattend >/dev/null 2>&1
    if [[ ! $? -eq 0 ]]; then
        echo "Failed"
        debugPause
        handleError "Failed to update originating unattend file"
    fi
    echo "Done"
    echo "ComputerName set to $hostname"
    debugPause
    [[ -z $addomain ]] && return
    dots "Set PC to join the domain"
    sed -i "/<JoinWorkgroup>/d" $unattend >/dev/null 2>&1
    if [[ ! $? -eq 0 ]]; then
        echo "Failed"
        debugPause
        handleError "Failed to remove the Workgroup setter"
    fi
    sed -i \
        -e "s|<Password></Password>|<Password>${hostadpwd}</Password>|g" \
        -e "s|<Username></Username>|<Username>${addomain}\\\\${aduser}</Username>|g" \
        -e "s|<MachineObjectOU></MachineObjectOU>|<MachineObjectOU>${adou}</MachineObjectOU>|g" \
        -e "s|<JoinDomain></JoinDomain>|<JoinDomain>${addomain}</JoinDomain>|g" $unattend >/dev/null 2>&1
    if [[ ! $? -eq 0 ]]; then
        echo "Failed"
        debugPause
        handleError "Failed to update user, pass, ou, and domain setter"
    fi
    echo "Done"
    debugPause
    

    You could actually locate any unattend.xml file and make the edits to them with:

    #!/bin/bash
    hostadpwd="ADPASSWDHERRE"; #only downside to this method- this is the plain ad password
    unattends=$(find /ntfs/ -iname "unattend.xml")
    for unattend in $unattends
        [[ ! -f $unattend ]] && return
        dots "Preparing Sysprep File"
        #rm -f /ntfs/Windows/System32/sysprep/unattend.xml >/dev/null 2>&1
        #if [[ ! $? -eq 0 ]]; then
            #echo "Failed"
            #debugPause
            #handleError "Failed to remove original unattend file"
        #fi
        echo "Done"
        debugPause
        dots "Writing Computer Name to $unattend"
        sed -i "/ComputerName/s/*/$hostname/g" $unattend >/dev/null 2>&1
        if [[ ! $? -eq 0 ]]; then
            echo "Failed"
            debugPause
            handleError "Failed to update originating unattend file"
        fi
        echo "Done"
        echo "ComputerName set to $hostname in $unattend"
        debugPause
        [[ -z $addomain ]] && continue
        dots "Set PC to join the domain"
        sed -i "/<JoinWorkgroup>/d" $unattend >/dev/null 2>&1
        if [[ ! $? -eq 0 ]]; then
            echo "Failed"
            debugPause
            handleError "Failed to remove the Workgroup setter"
        fi
        sed -i \
            -e "s|<Password></Password>|<Password>${hostadpwd}</Password>|g" \
            -e "s|<Username></Username>|<Username>${addomain}\\\\${aduser}</Username>|g" \
            -e "s|<MachineObjectOU></MachineObjectOU>|<MachineObjectOU>${adou}</MachineObjectOU>|g" \
            -e "s|<JoinDomain></JoinDomain>|<JoinDomain>${addomain}</JoinDomain>|g" $unattend >/dev/null 2>&1
        if [[ ! $? -eq 0 ]]; then
            echo "Failed"
            debugPause
            handleError "Failed to update user, pass, ou, and domain setter"
        fi
        echo "Done"
        debugPause
    done
    

    This will enable you to make the same edits to ANY unattend file found. I think this way is a bit more dynamic, and we’re not having to delete any files. You can also add a nested loop system to scan ANY partition for this to make the edits.

    The intent of the postdownloadscripts are to allow people to do whatever it is they may need to do without having to continuously update their own scripts (of course are more than welcome if you feel you need to). So think of the postdownload scripts as a way to enable a kind of mechanism to enable the admins to make their edits however they deem necessary.


  • Moderator

    @Greg-Plamondon I’ve had issues in the past when I had unattend.xml in the sysprep folder that it would use that file regardless of whether or not I specified it. I’m guessing that’s your issue as well.


  • Senior Developer

    @x23piracy I think most of us are aware of that. Even if we’re not it does ultimately make things simpler to just know where to find the “default” locations.



  • @george1421 said in Utilizing Postscripts (Rename, JoinDomain, Drivers, Snapins):

    @Greg-Plamondon Then you must ensure that unattend.xml must be in panther or sysprep folder. Typically its good practice to specifically call out the direct path to unattend.xml file.

    BTW, great scripts!! thanks for posting them.

    Hi,

    there is no need for having unattend.xml in a Special Directory, use /unattend:[FQPath] to Point Panther to the file.

    Regards X23


  • Moderator

    @Greg-Plamondon Then you must ensure that unattend.xml must be in panther or sysprep folder. Typically its good practice to specifically call out the direct path to unattend.xml file.

    BTW, great scripts!! thanks for posting them.


  • Testers

    @george1421 said in Utilizing Postscripts (Rename, JoinDomain, Drivers, Snapins):

    @Greg-Plamondon it should be in one or the other place. Panther is checked first. When you sysprep’d where did you tell sysprep to look for the file?

    i didnt i just ran sysprep.exe /oobe /generalize /reboot


  • Testers

    @Lee-Rowlett Thanks for the base scripts and ideas behind them.
    @Tom-Elliott Thanks for helping me adjusting them for my needs.
    @Junkhacker Thanks for the fog log script, you dont know how many time I have forgotten to delete the damn fog.log
    Here are the scripts that @Tom-Elliott helped me with.

    fog.postdownload:

    #!/bin/bash
    . /usr/share/fog/lib/funcs.sh
    [[ -z $postdownpath ]] && postdownpath="/images/postdownloadscripts/"
    case $osid in
        5|6|7|9)
            clear
            [[ ! -d /ntfs ]] && mkdir -p /ntfs
            getHardDisk
            if [[ -z $hd ]]; then
                handleError "Could not find hdd to use"
                
            fi
            getPartitions $hd
            for part in $parts; do
                true
            done
            dots "Mounting partition $part"
            ntfs-3g -o force,rw $part /ntfs >/dev/null 2>&1
            if [[ ! $? -eq 0 ]]; then
                echo "Failed"
                debugPause
                handleError "Failed to mount $part ($0)\n    Args: $*"
            fi
            echo "Done"
            debugPause
            . ${postdownpath}fog.log
            . ${postdownpath}fog.drivers
            . ${postdownpath}fog.ad
            umount /ntfs
            ;;
        *)
            echo "Invalid OS"
            debugPause
            return
            ;;
    esac
    

    fog.ad :

    #!/bin/bash
    hostadpwd="ADPASSWDHERRE"; #only downside to this method- this is the plain ad password
    unattend="/ntfs/Windows/Panther/unattend.xml";
    [[ ! -f $unattend ]] && return
    dots "Preparing Sysprep File"
    rm -f /ntfs/Windows/System32/sysprep/unattend.xml >/dev/null 2>&1
    if [[ ! $? -eq 0 ]]; then
        echo "Failed"
        debugPause
        handleError "Failed to remove original unattend file"
    fi
    echo "Done"
    debugPause
    dots "Writing Computer Name"
    sed -i "/ComputerName/s/*/$hostname/g" $unattend >/dev/null 2>&1
    if [[ ! $? -eq 0 ]]; then
        echo "Failed"
        debugPause
        handleError "Failed to update originating unattend file"
    fi
    echo "Done"
    echo "ComputerName set to $hostname"
    debugPause
    [[ -z $addomain ]] && return
    dots "Set PC to join the domain"
    sed -i "/<JoinWorkgroup>/d" $unattend >/dev/null 2>&1
    if [[ ! $? -eq 0 ]]; then
        echo "Failed"
        debugPause
        handleError "Failed to remove the Workgroup setter"
    fi
    sed -i \
        -e "s|<Password></Password>|<Password>${hostadpwd}</Password>|g" \
        -e "s|<Username></Username>|<Username>${addomain}\\\\${aduser}</Username>|g" \
        -e "s|<MachineObjectOU></MachineObjectOU>|<MachineObjectOU>${adou}</MachineObjectOU>|g" \
        -e "s|<JoinDomain></JoinDomain>|<JoinDomain>${addomain}</JoinDomain>|g" $unattend >/dev/null 2>&1
    if [[ ! $? -eq 0 ]]; then
        echo "Failed"
        debugPause
        handleError "Failed to update user, pass, ou, and domain setter"
    fi
    echo "Done"
    debugPause
    

    fog.drivers:
    For some reason Lenovo doesn’t play like most PC manufactures. I had to use the dmidecode variable of system-version to populate what the actual model of the PC was, with system-product-name it was returning the numerical machine type or serial number?

    #!/bin/bash
    ceol=`tput el`;
    manu=`dmidecode -s system-manufacturer`;
    case $manu in
        [Ll][Ee][Nn][Oo][Vv][Oo])
            machine=$(dmidecode -s system-version)
            ;;
        *[Dd][Ee][Ll][Ll]*)
            machine=$(dmidecode -s system-product-name) #pruduct is typo, just realized sorry :(
            ;;
        *)
            machine=$(dmidecode -s system-product-name) # Technically, we can remove the dell one as it's the "default"
            ;;
    esac
    [[ -z $machine ]] && return #assuming you want it to break if it is not lenovo or dell?
    machine="${machine%"${machine##*[![:space:]]}"}" #Removes Trailing Spaces
    system64="/ntfs/Windows/SysWOW64/regedit.exe" # sloppy detect if 64bit or not
    [[ ! -f $system64 ]] && setarch="x86" || setarch="x64"
    #############################################
    #this is not section necessary needed, it's just to make the path "human readable"
    #rather than using osid for filepath
    case $osid in
        5) osn="Win7" ;;
        6) osn="Win8" ;;
        7) osn="Win8.1" ;;
        9) osn="Win10" ;;
    esac
    #############################################
    dots "Preparing Drivers"
    # below creates local folder on imaged pc
    # this can be anywhere you want just remember
    # to make sure it matches throughout!
    clientdriverpath="/ntfs/Windows/DRV"
    remotedriverpath="/images/drivers/$osn/$machine"
    [[ ! -d $clientdriverpath ]] && mkdir -p "$clientdriverpath" >/dev/null 2>&1
    echo -n "In Progress"
    #there's 3 ways you could handle this,
    #driver cab file, extracted driver files or both
    #so on the server put extracted driver files to match below folder tree
    #i.e. Model Latitude E5410, Windows 7 x86 image would be:
    #/fog/Drivers/Win7/Latitude E5410/x86
    rsync -aqz "$remotedriverpath" "$clientdriverpath" >/dev/null 2>&1
    [[ ! $? -eq 0 ]] && handleError "Failed to download driver information"
    
    #if you wanted to use driver.cab use this line below.
    #i.e. /fog/Drivers/Win7/Latitude E5410/E5410-Win7-A07-KTT4G.CAB
    #cabextract -d "$clientdriverpath" "$remotedriverpath/*.CAB" >/dev/null 2>&1
    
    #if you wanted to mix both cab and extracted use these:
    #rsync -aqz --exclude='*.CAB' "$remotedriverpath" "$clientdriverpath" >/dev/null 2>&1
    #[[ ! $? -eq 0 ]] && handleError "Failed to sync cab and non-cab drivers"
    #cabextract -d "$clientdriverpath" "$remotedriverpath/*.CAB" >/dev/null 2>&1
    #[[ ! $? -eq 0 ]] && handleError "Failed to extract cab files"
    
    #this next bit adds driver location on pc to devicepath in registry (so sysprep uses it to reference)
    # remember to make devicepath= match the path you've used locally
    #also do not remove %SystemRoot%\inf
    #and to add more locations just use ; in between each location
    regfile="/ntfs/Windows/System32/config/SOFTWARE"
    key="\Microsoft\Windows\CurrentVersion\DevicePath"
    devpath="%SystemRoot%\inf;%SystemRoot%\DRV";
    reged -e "$regfile" &>/dev/null <<EOFREG
    ed $key
    $devpath
    q
    y
    EOFREG
    echo -e "\b\b\b\b\b\b\b\b\b\b\b${ceol}Done"; # this just removes "In Progress and replaces it with done :-)"
    

    fog.log:

    #!/bin/bash
    #deletes fog.log for Windows 7, 8, or 8.1 or 10
    #Greg Grammon (Junkhacker)
    #
     
    #funcs.sh allows us to use the functions that are used in the rest of
    #fog i.e. "dots" and use the vars already in place i.e. "$part" and "$osid"
    . /usr/share/fog/lib/funcs.sh;
    case $osid in
        [5-7]|9)
            [[ -f /ntfs/fog.log ]] && rm /ntfs/fog.log >/dev/null 2>&1 || true
            if [[ ! $? -eq 0 ]]; then
                echo "Failed"
                debugPause
                handleError "Failed to remove original fog.log file"
            fi
            ;;
        *) return ;;
    esac
    

    Thanks For all the Help Tom and Lee


  • Moderator

    @Greg-Plamondon it should be in one or the other place. Panther is checked first. When you sysprep’d where did you tell sysprep to look for the file?


  • Testers

    @Lee-Rowlett The unattend.xml is in the C:\Windows\Panther directory. I removed the option from my setupcomplete.cmd that deletes the unattend.xml, so after it boots I can take a look at it and the edits were made to it. Should I be editing the C:\Windows\Sytstems32\Sysprep\unattend.xml instead of the Windows\Panther ?


  • Senior Developer

    @Lee-Rowlett I remoted in and took a look. Cleaned up the scripts a lot, with Gregs help (-- @Greg-Plamondon I grabbed some credit but it still mostly goes to you --). I asked Greg to post the finished scripts after generalizing them so his environment is safe. Hopefully you will like them, and others as well.


Log in to reply
 

515
Online

39.4k
Users

11.1k
Topics

105.4k
Posts

Looks like your connection to FOG Project was lost, please wait while we try to reconnect.