Utilizing Postscripts (Rename, JoinDomain, Drivers, Snapins)
-
@gwhitfield as you’re using /images as your driver location you do not need to mount a share as it’s already mounted, so /fog mount is irrelevant to you. as you’re only doing one arch or having both drivers on the image, i’m assuming as you commented it out, make sure your folder layout for drivers matches this for example a Windows 7 build OptiPlex 7010 would be:
“/images/Drivers/Win7/OptiPlex 7010” and all your drivers for the 7010 would be within that folderTry these and let me know how you get on
fog.postdownload:
#!/bin/bash case $osid in [5-7]|9) clearScreen getHardDisk getPartitions $hd if [[ ! -d /ntfs ]]; then mkdir -p /ntfs >/dev/null 2>&1 [[ ! $? -eq 0 ]] && echo " * Failed to Mount Device" fi for part in $parts; do umount /ntfs >/dev/null 2>&1 ntfs-3g -o remove_hiberfile,rw $part /ntfs >/dev/null 2>&1 [[ ! $? -eq 0 ]] && continue done . ${postdownpath}fog.drivers umount /fog /ntfs /images >/dev/null 2>&1 ;; esac
fog.drivers:
#!/bin/bash ceol=`tput el`; machine=`dmidecode -s system-product-name`; machine="${machine%"${machine##*[![:space:]]}"}" if [ $osid == "5" ]; then osn="Win7" elif [ $osid == "7" ]; then osn="Win8.1" elif [ $osid == "9" ]; then osn="Win10" fi dots "Preparing Drivers"; mkdir /ntfs/Windows/DRV &>/dev/null; echo -n "In Progress"; rsync -aqz "/images/Drivers/$osn/${machine}" /ntfs/Windows/DRV &>/dev/null; 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";
-
@Lee-Rowlett Seems like I’m very close. The image task completes and I get the following just before the machine restarts. Unfortunately no drivers are copied so the image fails to bootup since there’s no drivers in it:
/images/postdownloadscripts/fog.postdownload: line 2: syntax error near unexpected token '$' in\r'' 'images/postdownloadscripts/fog.postdownload: line 2: 'case $osid in * Mounting directory ............................Done * Mounting directory ............................Done * Changing hostname .............................Done * Task complete * Updating Database..............................Done * Rebooting system as task is complete Reboot: Restarting system
-
can you send me both your fog.postdownload and fog.drivers file and i’ll take a look - (i mean physically send, not paste the code on here :-))
-
@Lee-Rowlett Sure, here’s the goods:
Screenshot of folders in /images
-
-
@Lee-Rowlett Success!! Evidently my fog.postdownload and fog.drivers files got corrupted by editing in Notepad. Thank you for sending me a clean version! Working like a champ. Also for purpose of posterity or future users, the name of the folder for each individual hardware type needs to exactly match the spelling and case of the “System Product” field in the “Inventory” for that machine (or type of machine):
-
I gotten this to make the edits to the unattend.xml but it still doesnt join the domain. Do you have a Windows10 Unattend.xml that i can compare where I went wrong?
-
@Greg-Plamondon where are you calling the unattend.xml from and how are u verifying the unattend.xml is beinf edited correctly? Also are is it x86 or x64?
-
@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.
-
@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 ?
-
@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?
-
@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
-
@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
-
@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.
-
@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
-
@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.
-
@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.
-
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.
-
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.
-
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