Image Prep Script


  • Testers

    Once upon a time @Wayne-Workman asked me to share my script for prepping images with or without using sysprep.
    At the time it was still being developed and not quite stable enough to share. It still needs a bit more work to be truly universal and I will likely put it in a public git when it’s closer to that level. But hey, I figure it might help somebody out. There are some pre-reqs for it like having devcon.exe from the windows wdk (freely available) in your C:\Windows\System32 folder, or elsewhere in the path, if you want to not use sysprep. So read through the comments, ask questions, and hopefully this helps someone. I designed it around windows 10 and vm’s for images.

    ::-----------------------------------------------------------------------------
    :: Arrowhead Dental Lab admin_scripts
    :: Script Name: ImagePrep
    :: Original Author: jfullmer
    :: Created Date: 2016-02-18 16:39:23
    :: Last Updated Date: 2016-06-23 16:50:45
    :: Update Author: jfullmer
    :: Version: 8.2
    ::-----------------------------------------------------------------------------
    
    @ECHO off
    	rem This script prepares a customized computer to be imaged.
    	rem It will stop the fog service and prompt you to queue the upload
    	rem It then will take care of cleaning up the windows\installer folder
    	rem Then it will make sure hibernate is off
    	rem Then it will run a system file check and windows update component cleanup as well as run chkdsk
    	rem Then it will run CCleaner
    	rem then it will empty all recycle bins 
    	rem Then it will delete the weird volume registry keys
    	rem Then it will delete all ze drivers and restart for the image to start uploading
    	rem Before all that it copies itself to C:\ so that it can still run after uninstalling the network drivers.
    
    rem start by setting path and passwd
    SET pwd=%~dp0
    set scriptShare= rem where this script and image version logs are to be stored
    set backupShare= rem where things like group policies and firewall rules will be backed up to
    set domain= rem the domain for the login of the above shares
    set user= rem the user for the login to the shares
    set passwd= rem the password for the login to the share
    set ntpSrv=time.windows.com rem the local or global ntp server you sync to. Your Domain controller for example.
    echo. Mounting shares...
    net use %scriptShare% /USER:%domain%\%user% %passwd%
    net use %backupShare% /USER:%domain%\%user% %passwd%
    
    
    call :main
    rem if it does not exit after sysprep pause to show errors, then exit
    rem @pause
    rem devcon reboot & exit
    echo. unmount shares...
    net use %scriptShare% /delete
    net use %backupShare% /delete
    rem Delete self, devcon reboot to finish uninstalling devices and exit script.
    del C:\ImagePrep.bat & devcon reboot & exit
    
    :main
    	call :funcHead "Welcome to image prep!"	
    
    	call :copySelf
    	call :setvars
    	call :syncTime
    	call :perms
    	call :updateImageVersion
    	call :queueUpload
    	call :cleanup
    	call :setupFirstLogon
    	call :backupGroupPolicy
    	call :hardwareIndependence
    	rem call :runSysprep
    	echo. Done!
    
    	EXIT /B
    
    :copySelf
    	IF NOT %pwd%==C:\ (
    		echo. Copying self to C drive
    		XCOPY %~f0 C:\ /H /Y
    		start C:\ImagePrep.bat
    		exit
    	)
    	EXIT /B
    
    :setVars
    	:: Function to set script variables and mount network directory
    
    	call :funcHead "Creating Backup dir and Setting directory variables..."
    
    	FOR /F "usebackq" %%i IN (`hostname`) DO SET hn=%%i
    	if %hn%==BASEIMG-32 (
    		set CCleaner=C:\Program Files\CCleaner\CCleaner.exe
    	) else (
    		set CCleaner=C:\Program Files\CCleaner\CCleaner64.exe
    	)
    	if %hn%==BASEIMG-32 (
    		set Firefox="C:\Program Files\Mozilla Firefox\firefox.exe"
    	) else (
    		set Firefox="C:\Program Files (x86)\Mozilla Firefox\firefox.exe"
    	)
    	set uploadPage="http://fog-server/fog/management/index.php?node=host&sub=deploy&type=2&id=11"
    	set ThreeShapeUpPage="http://fog-server/fog/management/index.php?node=host&sub=deploy&id=14&type=2"
    	set legacyUpPage="http://fog-server/fog/management/index.php?node=host&sub=deploy&id=144&type=2"
    	set tasksmgmt="http://fog-server/fog/management/index.php?node=task&sub=active"
    	set notePlus="C:\Program Files (x86)\Notepad++\notepad++.exe"
    	set fogHost="http://fog-server/fog/management/index.php?node=task&sub=listhosts"
    	set drivers=C:\Windows\System32\DriverStore\FileRepository
    	set sysprep=C:\windows\system32\sysprep
    	setlocal enableextensions enabledelayedexpansion
    	set imageScripts=%scriptShare%\Automating-Imaging\Before-Image
    	if not exist %imageScripts% mkdir %imageScripts%
    	set afterScripts=%scriptShare%\Automating-Imaging\After-Image
    	if not exist %afterScripts% mkdir %afterScripts%
    	set verLogs=%scriptShare%\Version-Change-Logs
    	if not exist %verLogs% mkdir %verLogs%
    	set verLog=%verLogs%\ImageVer-%hn%.log
    	set policiesPath=%backupShare%\policies\policies-%hn%
    	if not exist %policiesPath% mkdir %policiesPath%
    	endlocal
    	EXIT /B
    
    :syncTime
    	rem Function that makes sure the time is synced to time.arrowheaddental.computer
    	rem Simply runs a resync 5 times to be sure, since if it is off due to a snapshot, it takes a couple tries
    	echo. net time set....
    	net time \\%ntpSrv% /set /y
    	echo. stopping w32time service, configuring it, and resyncing it...
    	net stop w32time
    	w32tm /config /syncfromflags:ALL /manualpeerlist:%ntpSrv%
    	net start w32time
    	w32tm /config /update
    	for /l %%i in (1, 1, 5) do (
    		echo. time sync %%i
    		w32tm /resync
    	)
    	EXIT /B
    
    :updateImageVersion
    	rem Function to open up the image version log for updating
    
    	call :funcHead "Update Image Version Log"
    	
    	echo. Copying latest imageVersion log from git repo...
    	if not exist %verLog% (
    		echo. %hn% does not have a version log
    	) else (
    		XCOPY %verLog% C:\ImageVersion.log /Y
    	)
    
    	EXIT /B
    
    :queueUpload
    	rem This function pauses the script to confirm you queued the upload
    	call :funcHead "Queueing upload!"
    
    	echo. Stopping fog service to prevent auto restart during prepares
    	net stop FOGservice
    	rem sc config FOGService start= disabled
    	echo. done
    
    	echo. Opening FOG upload page
    	if %hn%==baseImageVM (
    		%Firefox% %uploadPage%
    	) else if %hn%==3SHAPEIMAGE (
    		%Firefox% %ThreeShapeUpPage%
    	) else if %hn%==BASEIMG-32 (
    		%Firefox% %legacyUpPage%
    	) else (
    		%Firefox% %fogHosts%
    	)
    
    	set /p queued="Did you start the upload task? y/n: "
    
    	if NOT %queued%==y (
    		echo. Well then let's start over...
    		@pause
    		goto :main
    	)
    
    	call :funcHead "Create Snapshot!"
    
    	echo. Before Continuing you should really make a snapshot of the vm to be safe...
    	echo. And not just to be safe, also because since you can only rearm a windows license 3 times
    	echo. This image would have to be redone if you don't revert to the snapshot once you're done 
    	echo. uploading the image.
    	echo. So please do that now...
    	@pause
    	echo. Continuing...
    
    	EXIT /B
    
    :cleanup
    	call :funcHead "Running Cleanup and Maintenance tasks"
    	rem This just runs some quick maintenance tasks
    
    	echo. Windows Maintenance...
    	call :cleanWindows
    
    	echo. turning hibernate off...
    	powercfg /Hibernate off	
    
    	echo. Deleting fog.log so there's a fresh log for imaged computers...
    	del C:\fog.log
    	
    	echo. Running CCleaner...
    	"%CCleaner%" /AUTO
    	
    	echo. Emptying all recycle bins
    	rmdir C:\$Recycle.Bin /S /Q
    
    	EXIT /B
    
    :cleanWindows
    	rem Function that runs chkdsk cleans up windows update
    	call :funcHead "Windows maintenance and cleanup"
    	
    	echo. Windows update cleanup...
    	dism /online /cleanup-image /startcomponentcleanup
    
    	echo. running check disk scan and pausing if full run is needed
    	call :checkDiskChk
    
    	echo. Windows cleanmgr
    	rem run cleanmgr /sageset:1 to change clean settings
    	cleanmgr /sagerun:1
    
    	echo. System File Check...
    	sfc /scannow > C:\sfc.log
    
    	echo. Defrag hard drive
    	Defrag C: /H /U /V >> c:\defrag.log 
    	Defrag C: /X /H /U /V >> C:\defrag-freespace.log
    
    	EXIT /B
    
    :checkDiskChk
    	call :funcHead "Running chkdsk scan to check if repair is needed"
    	echo. Scan is running, log available at C:\chk.log....
    	chkdsk C: /scan /perf /V >C:\chk.log
    	echo. Searching for no problemo string...
    	FOR /F "usebackq" %%i IN (`findstr /B /N /C:"Windows has scanned the file system and found no problems." C:\chk.log`) DO SET found=%%i
    	echo. Checking if string was found...
    	if NOT defined found (
    		echo. Problem! You need to run chkdsk /F /R /perf, restart, and then run this script again before uploading!
    		%Firefox% %tasksmgmt%
    		set /p confirm="Please enter y/n to confirm you canceled the upload task"
    		echo. Thank you, Queueing chkdsk and restarting now...
    		echo. Y | chkdsk /F /R /scan /perf C: 
    		shutdown -r & exit
    	) else (
    		echo. String was found!
    		echo. %found%
    		echo. Done with checking disk!
    	)
    
    	EXIT /B
    
    :perms
    	call :funcHead "Changing permissions"
    
        call :grantPerms C:\img
        call :grantPerms C:\users\adladmin
        call :grantPerms C:\users\Administrator
        call :grantPerms C:\Windows\Installer
        call :grantPerms "C:\Program Files\Inventrix"
        call :grantPerms "C:\Program Files (x86)\Sage"
        call :grantPerms "C:\Program Files (x86)\Sage Software"
        call :grantPerms "C:\Program Files (x86)\FOG"
        call :grantPerms "C:\Program Files\FOG"
    
        EXIT /B
    
    :grantPerms
    	call :funcHead "Granting permissions"
    
    	echo. Granting Authenticated Users full access to %~1...
    	cacls "%~1" /T /E /R everyone > C:\remove.log
    	cacls "%~1" /T /E /G "Authenticated Users":F > C:\add.log
    
    	EXIT /B
    
    :setupFirstLogon
    	rem Function to enable autologon for Administrator
    	echo... apply General Profile on base images...
    	if %hn%==baseImageVM (
    		start %afterScripts%\Apply-Default-Profile-args.bat General
    	) else if %hn%==BASEIMG-32 (
    		start %afterScripts%\Apply-Default-Profile-args.bat General-32
    	) else (
    		echo. do not apply anything here...
    	)
    	echo. wait for profile to apply...
    	timeout /t 60
    
    	echo. loop through and import all keys...
    	REG IMPORT %afterScripts%\autologon-keys\admin-autologon.reg
    	REG IMPORT "%afterScripts%\autologon-keys\admin-autologon.reg" /reg:32
    	REG IMPORT "%afterScripts%\autologon-keys\admin-autologon.reg" /reg:64
    	
    	echo. Create the script to run the logon script via echos...and create in both possible spots...
    
    	call :createScript AdlAdmin
    	call :createScript Administrator
    
    	EXIT /B
    
    :createScript
    	rem Function to create the script to start the logon script, takes user Parameters...
    	call :funcHead "Creating startup script for %~1"
    	set firstLoginBatPath=AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\firstLogin.bat
    	echo @ECHO OFF > "C:\Users\%~1\%firstLoginBatPath%"
    	echo net use %scriptShare% /USER:%domain%\%user% %passwd% >> "C:\Users\%~1\%firstLoginBatPath%"
    	echo start %afterScripts%\firstLogonCommands.bat >> "C:\Users\%~1\%firstLoginBatPath%"
    
    	EXIT /B
    
    :backupGroupPolicy
    	call :funcHead "Backing up local gpo"
    	echo. export current policies...
    	mkdir C:\policies
    	ROBOCOPY C:\Windows\System32\GroupPolicy C:\policies\GroupPolicy /S /MIR /ZB /R:1 /W:1 /MT:64 /LOG:C:\groupPolicy-bck.log
    	call :regPort HKLM\SOFTWARE\Policies\Microsoft gp
    	call :regPort HKLM\SOFTWARE\WOW6432Node\Policies\Microsoft gpWow64
    	call :regPort HKLM\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy firewall
    	secedit /export /cfg C:\policies\gp.inf /log C:\secplcy-bck.log
    
    	echo. backup current policies
    	ROBOCOPY C:\policies %policiesPath% /S /MIR /R:1 /W:1 /ZB /MT:8
    	
    	echo. Delete that stuff...
    	rmdir C:\policies /S /Q
    
    	EXIT /B
    
    :hardwareIndependence
    	rem Runs devcon tool to remove all drivers just like sysprep
    	call :funcHead "Make the image hardware independent"
    	
    	echo. Rearm windows licensing...
    	cscript C:\Windows\System32\slmgr.vbs -rearm > c:\rearmed.log
    	
    	echo. This will restart the computer and it will happen fast, do not reset the vm if the screen is blank...
    	echo. It is most likely starting to image and you will probably interupt resizing.
    	
    	rem If 32 bit legacy image or 3shape image, then just remove everything, otherwise remove everything except printers
        if %hn%==baseImageVM( 
    		rem Loop through devcon classes skipping print queues to keep pdf and papervision printers
    		for /F "tokens=1 delims=:" %%i in ('devcon classes') do call :printerCheck %%i 
        ) else (
        	del C:\ImagePrep.bat & C:\Windows\System32\devcon.exe -r remove * & exit
        )
    
    	EXIT /B
    
    :printerCheck
    	rem loop function to check if class is printqueue and remove the class if it is not
    	rem note the 5 spaces plus one. The command looping through the classes parses 5 spaces after each class and you need one for the ()
    	if NOT %~1==PrintQueue      (
    		rem Remove all devices in the class
    		echo. Removing all devices of class %~1 ...
    		C:\Windows\System32\devcon.exe remove =%~1 *
    		echo. Done
    	)
    
    	EXIT /B
    
    rem :runSysprep
    rem 	rem copies current git unattend.xml and runs a generalize sysprep to prep for imaging.
    rem 	call :funcHead "Running Microsoft sysprep"
    	
    rem 	echo. copying unattend.xml...
    rem 	XCOPY %imageScripts%\unattend.xml %sysprep%\ /Y /H
    rem 	XCOPY %imageScripts%\unattend.xml c:\windows\Panther\ /Y /H
    
    rem 	XCOPY %imageScripts%\removeMetro.ps1 %sysprep%\ /Y /H
    rem 	powershell -Command "Set-ExecutionPolicy RemoteSigned;"
    rem 	powershell -Command "%sysprep%\removeMetro.ps1;"
    
    rem 	echo. Running sysprep and exiting...
    rem 	del C:\ImagePrep.bat & %sysprep%\sysprep.exe /generalize /oobe /reboot /unattend:%sysprep%\unattend.xml & exit
    
    rem 	EXIT /B
    
    :regPort
    	call :funcHead "Export Reg Key"
    	echo. Exporting arch specific key for %~2...
        if %PROCESSOR_ARCHITECTURE%==x86 (
    		REG EXPORT %~1 "C:\policies\%~2.reg" /reg:32 /y
    	) else (
    		REG EXPORT %~1 "C:\policies\%~2.reg" /reg:64 /y
    	)
    	echo. Exporting non-arch specific key for %~2...
    	REG EXPORT %~1 "C:\policies\%~2-nonarch.reg" /y
    		
    	EXIT /B
    
    :dots
    	:: just echoing dots in a Function instead of copy pasting them so that it is consistent
    	echo ......................................................................
    	EXIT /B
    
    :funcHead
    	:: A simple function for displaying a consistent header at the start of functions
    	call :dots
    	echo. %~1
    	rem Uncomment the next line to enable debug mode
    	rem @pause 
    	call :dots
    	EXIT /B
    


  • @JJ-Fullmer this is awesome thank you for sharing your knowledge and scripts.


  • Testers

    @Greg-Plamondon said in Image Prep Script:

    what is this used for?

    set secretKeyPath=\\path\to\secure\keys
    

    what keys are you referring to?

    That would be relating to the mntShare.bat and ps1 script/commands. It’s a method of mounting shares in scripts without plain text credentials that I just discovered. I put my secure keys in the fog program files folder so I can run scripts with it manually on any computer or with fog. You could also put them in every snapin pack and then only have them on a host when they’re in use. But that would be a bit of extra work for each snapin you create. Granted that could probably be scripted.

    @JJ-Fullmer said in Image Prep Script:

    mntShare.bat (Alternative to plain text credentials with net use, Requires creating powershell compatible aes key and password files, instructions on that in ps1 script after this one)
    ::-----------------------------------------------------------------------------
    :: Arrowhead Dental Lab admin_scripts
    :: Script Name: mntShare
    :: Original Author: jfullmer
    :: Created Date: 2016-06-24 13:34:10
    :: Last Updated Date: 2016-07-21 10:31:47
    :: Update Author: jfullmer
    :: Version: 3.4
    ::-----------------------------------------------------------------------------

    @ECHO OFF
    setlocal enableextensions enabledelayedexpansion
    rem set passed param of the share path to mount as mntPnt
    set mntPnt=%1
    rem To use Persist you have to use a drive letter. Start with A and B
    set name=%2
    set mounted=0
    call :main
    GOTO :EOF

    :main
    rem function to mount a share passed as param
    call :funcHead “Mounting network share”

    call :setVars
    call :mnt %login1% %pwFile1% %key1%
    if !mounted!==1 call :success & EXIT /B
    call :mnt %login2% %pwFile2% %key2%
    if !mounted!==0 call :failed
    if !mounted!==1 call :success
    EXIT /B

    :setVars
    rem Set vars to the domain and local share login names and key paths
    rem Path to encrypted password and key files
    set pth=C:\Program Files (x86)\Fog\Keys

    rem Domain Login
    set domain1=Arrowhead
    set user1=Scriptmin
    set login1=%domain1%%user1%
    set pwFile1="%pth%~"
    set key1="%pth%~.key"

    rem Secondary local admin login
    set login2=AdlAdmin
    set pwFile2="%pth%~2"
    set key2="%pth%~2.key"

    rem variables to call the Powershell command cleaner
    set psc=Powershell.exe -C
    set PSDrive=New-PSDrive -Name ‘%name%’ -PSProvider FileSystem -Persist -Root
    set createCred=-Credential (New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList
    set log=“C:\logs\PS-mnt-%name%.log”
    set log2=“C:\logs\net-use.log”
    set log3="C:\logs\net-use-delete.log"
    EXIT /B

    :mnt
    rem function to call the New-PSDrive command with encrypted credentials
    rem call :dots
    echo. Attempting to Mount drive to %name% with encrypted credentials for %~1 (log at %log%)…
    rem Delete log to ensure its creation
    del %log%
    %psc% “%PSDrive% ‘%mntPnt%’ %createCred% ‘%~1’, (Get-Content ‘%~2’ | ConvertTo-SecureString -Key (Get-Content ‘%~3’)));” > %log%
    call :mntCheck
    EXIT /B

    :mntCheck
    rem echo mounted is !mounted!
    if !mounted!==1 (
    rem echo. already mounted!
    EXIT /B
    )
    rem Device was mounted if log contains GB in description of mounted drive
    call :check “GB” %log% 1

    rem Device was already mounted…
    call :check “The local device name is already in use” %log% 2

    rem multiple connections exist, so it’s already mounted via a different user
    call :check “Multiple connections” %log% 3

    rem Check with net use for mntPnt just in case
    net use > %log2%
    call :check %mntPnt% %log2% 4
    if !mounted!==0 echo. The drive did not mount with this login…
    EXIT /B

    :check
    if !mounted!==1 (
    rem echo. already mounted!
    EXIT /B
    )
    rem echo. Checking for %~1 string…
    set varStr1="%%found%~3%%"
    set varStr2=%varStr1:"%=%
    set varStr=%varStr2:~0,6%
    set %varStr%=
    FOR /F “usebackq” %%i IN (findstr /N /C:"%~1" %~2) DO SET %varStr%=%%i
    rem echo %varStr% is !%varStr%!
    rem type %log%
    if defined %varStr% set mounted=1
    EXIT /B

    :dots
    REM just echoing dots in a Function instead of copy pasting them so that it’s consistent
    echo …
    EXIT /B

    :funcHead
    REM A simple function for displaying a consistent header at the start of functions
    call :dots
    echo. %~1
    call :dots
    rem @pause ::Uncomment to enable debugging mode for script
    EXIT /B

    :success
    echo. %mntPnt% Mounted successfully as %name%
    GOTO :EOF
    EXIT /B

    :failed
    echo. %mntPnt% Did not Mount as %name%!
    GOTO :EOF
    EXIT /B

    -_-seperator

    Run once ps1 script to create encrypted key and password files for mounting shares (I make one for a domain login, and one for a local admin login for redundancy in this example) (more info found here http://www.adminarsenal.com/admin-arsenal-blog/secure-password-with-powershell-encrypting-credentials-part-2/)
    $pth="\path\to\securely\store\keys"
    $keyFile1="$pth~.key"
    $keyFile2="$pth~2.key"

    #Create aes key 1
    $AESkey1 = New-Object Byte[] 32
    [Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($AESkey1)
    $AESkey1 | out-file $keyFile1

    #create aes key 2
    $AESkey2 = New-Object Byte[] 32
    [Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($AESkey2)
    $AESkey2 | out-file $keyFile2

    $pwFile1 = “$pth~”
    $pwFile2 = “$pth~2”

    #create encrypted pw file with aes key
    $pw1 = “domainPassword” | ConvertTo-SecureString -AsPlainText -Force
    $pw1 | ConvertFrom-SecureString -key $AESkey1 | Out-File $pwFile1

    #create encrypted pw file with other aes key
    $pw2 = “localAdminPassword” | ConvertTo-SecureString -AsPlainText -Force
    $pw2 | ConvertFrom-SecureString -key $AESkey2 | Out-File $pwFile2

    #to create powershell credential objects (mntshare.bat does this already)
    $user1 = “domain\user”
    $user2 = “.\Administrator”
    $domainCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user1, (Get-Content $pwFile1 | ConvertTo-SecureString -Key $AESkey1) $administratorCredential = New-Object -TypeName System.Management.Automation.PSCredential
    -ArgumentList $user2, (Get-Content $pwFile2 | ConvertTo-SecureString -Key $AESkey2)


  • Testers

    what is this used for?

    set secretKeyPath=\\path\to\secure\keys
    

    what keys are you referring to?


  • Testers

    @Wayne-Workman said in Image Prep Script:

    @JJ-Fullmer said in Image Prep Script:

    pnputil

    Can you tell us more about that? I’m thinking I’m going to have to build a universal image now.

    What @jayrob86 posted was some good stuff.

    My basic explanation would be.

    pnputil can add, install, or add and install drivers to a host.
    If you use pnputil -a driver.inf you will add a driver to the plug n play store but not install it. This makes it so you can add drivers to your image without losing hardware independence.
    If you use pnputil -i -a driver.inf it will install that driver for you and add it to the driverstore. Which is what I would use for a driver installer script.
    You can also do recursive searches with for loops.
    like this one that would go through the first level of folders in a folder and install all inf files in each folder (to do all subfolders would take more loops or something)… (disclaimer: untested, just doing it off the top of my head right quick, syntax may be wrong, but I’ve done it before, should really make this a sharedFunction script)
    run from path you’re searching
    use %%F (or i, or whatever variable floats your boat) in a script but just 1 % in command line)
    %F= each line of output of dir /b which is just a folder name list (/b takes out the full path, makes it like ls) Then the loop just takes the foldername*.inf to install all inf files in that folder.
    FOR /F %F in ('dir /b') do pnputil -i -a %F\*.inf

    For drivers in a universal image I use that loop on downloaded drivers with just -a for any model that has drivers that are missing from windows 10 by default. A word of caution though, be careful with things like intel rapid storage technology drivers, and other hard drive/raid/sata controller type drivers. Sometimes having multiple in the store ends up having the wrong one install and then there are problems. So I try to limit it to simpler drivers, like network drivers, graphics drivers can work too, however trying to preinstall all nvidia drivers from a single nvidia driver download will take up a good chunk of GB of your image. So I stopped trying to do that one. But other than those 2 caveats of graphics drivers taking up space and IRST drivers having occasional conflicts, it’s a pretty great practice for universalizing images. Another important note, that I may have mentioned earlier, some inf files reference sys files and cab files in subdirs or the same dir. So you can’t always just copy the inf file to a share or something like that, so it’s good to install it from the original location that you find it in so it can copy those required files to the driver store as needed.

    So some more examples would be the sol and heci drivers for a HP 8000 elite, or the latest intel network driver IL29 or something like that. Chipset drivers, monitor drivers, touchscreen drivers, printer drivers etc. And from what I understand, and I’m not 100% on this, but basically it puts drivers in 2 places on adding and installing. I think that when it’s installed it creates a C:\Windows\inf\oem#.inf file and when it adds it, it puts it in the driver store at C:\Windows\System32\DriverStore\FileRepository but I may have that backwards. But those are the 2 locations that drivers will go.

    The other advantage to this method, that I think I mentioned before, is that it skips over having to install any extra software from the manufacturer. You can usually use 7zip to extract any driver installer exes and find the inf files you need.

    Hopefully that answers your question enough to utilize it.


  • Testers

    Post was too long, continuing…

    Shared functions (including ones I use not used by these scripts)

    CopyDir.bat

    ::-----------------------------------------------------------------------------
    :: Arrowhead Dental Lab admin_scripts
    :: Script Name: copyDir
    :: Original Author: jfullmer
    :: Created Date: 2016-06-27 08:53:06
    :: Last Updated Date: 2016-07-20 15:19:40
    :: Update Author: jfullmer
    :: Version: 2.7
    ::-----------------------------------------------------------------------------
     
    @ECHO OFF
     	REM Function inputs - 1 = display of what is copying and log file title 2 = source folder 3 = destination folder 4=Type
    	
    	REM This Function simply displays what you're copying and copies it. Did a Function to have less
    	REM copy paste of command line options and have cleaner code.
    	REM Note that when calling the Function all passed parameters should be encased in double quotes
    	REM otherwise ROBOCOPY won't read the directories as seperate
    	
    	REM ROBOCOPY or robust copy, is a tool for copying directories or files in windows command line
    	REM The syntax is ROBOCOPY sourceFolder DestFolder options
    	REM the options used make it so a mirrored version of the source and its subdirectories are copied
    	REM to the destination with 64 threads (64 files at once) overwriting existin files retrying any failed files 
    	REM only once after 1 second of waiting and all logged to a given logfile
    	
    	REM /S - subdirectories /MIR - mirror /MT:64 - multithreaded copy with 64 threads, i.e. 64 files at a time instead of 1. 
    	REM /LOG - output to logfile instead of console, ROBOCOPY /? says this provides better performance in multithreaded mode
    	REM /R:1 retry on error once (default is 1 million) W:1 - wait one second between retry on error (default is 30 seconds) /
    	REM /XJ - exclude junction points (take out for shortcut files) /XA:SH excludes files with windows system attribute
    	REM /ZB first attempts to copy files in restartable mode (as in you can restart copying where you left off) and if it fails retries in backup mode
    
    set var1=%1
    set var2=%2
    set var3=%3
    set var4=%4
    set log=%var1:"=%
    call :setSrc 
    call :setDst
    set typ=%var4:"=%
    rem Set params, default is Mir
    if "%typ%"=="" (
    	call :CASE_Mir
    ) else (
    	call :CASE_%typ%
    )
    
    rem Copy the dir with the set params
    call :copyDir
    rem GOTO :EOF
    GOTO :EOF
    
    :copyDir
    	call :funcHead "Copying %typ% Dirs"
    	echo. Copying %log%...
    	echo. "src is %src%" 
    	echo. "dst is %dst%" 
    	echo. "params are %params%"
    	rem src and dst variables are set in quotes or not in quotes to fix issues with copying to or from the root of C:\
    	ROBOCOPY %src% %dst% /LOG:"C:\%log%.log" /ZB /R:1 /W:1 %params%	
    	echo. Done Copying %log%
    	echo. setting perms on copied directory...
    	call :func perms.bat %dst% "%log%-%dst%-perms"
    EXIT /B
    
    :setSrc
    	rem call :funcHead "Setting src"
    	if %var2%=="C:\" (
    		call :rootSrc
    	) else if %var2%=="\" (
    		call :rootSrc
    	) else (
    		call :setQuotedSrc
    	)
    EXIT /B
    
    :rootSrc
    	set src=\
    EXIT /B
    
    :setQuotedSrc
    	set src="%var2:"=%"
    EXIT /B
    
    :setDst
    	rem call :funcHead "Setting dst"
    	if %var3%=="C:\" (
    		call :rootDst
    	) else if %var3%=="\" (
    		call :rootDst
    	) else (
    		call :setQuotedDst
    	)
    EXIT /B
    
    :rootDst
    	set dst=\
    EXIT /B
    
    :setQuotedDst
    	set dst="%var3:"=%"
    EXIT /B
    
    :CASE_Mir
    	rem Sets Mirror with multithreaded at 32, exc
    	set params=/S /MIR /MT:64 
    EXIT /B
    
    :CASE_MirX
    	rem Mirror excluding junction points and system/hiddent files
    	set params=/S /MIR /MT:64 /XA:SH /XJ
    EXIT /B
    	
    :CASE_MirXiso
    	rem Sets Mirror with multithreaded at 32, exc
    	set params=/S /MIR /MT:64 /XA:SH /XF *.iso
    EXIT /B
    
    :CASE_MirIS
    	rem Sets Mirror with multithreaded at 32, Includes and overwrites any same files instead of skipping them
    	set params=/S /MIR /MT:64 /XA:SH /IS
    EXIT /B
    
    :CASE_Bck
    	rem Sets parameters for backing up user files
    	set params=/S /MIR /MT:8 /XD App* /XD *drive /XD DropBox /XD odrive /XD *min /XD "Default User*" /XD Default* /XD Administrator* /XD NetworkService* /XD ".NET*" /XD adl* /XD QBD* /XD Updatus* /XD spiceworks* /XJ /XA:SH /XF ntuser* /XF *.ost /XF *.lnk
    EXIT /B
    
    :CASE_Rst
    	rem Sets parameters for restoring user files
    	set params=/E /MT:8 /XD App* /XD *drive /XD DropBox /XD odrive /XJ /XA:SH /XF ntuser* /XX
    EXIT /B
    
    :CASE_Mv
    	rem Sets parameters for moving local files
    	set params=/E /MT:128 /MOVE /XD App* /XD *drive /XD DropBox /XD odrive /XJ /XA:SH /XF ntuser* /XX
    EXIT /B
    
    :CASE_Pf
    	rem set params for copying custom program files
    	set params=/E /IS /MT:64 /XA:SH
    EXIT /B
    
    :CASE_defPrinters
    	rem sets parameters for copying default printer setters to desktop
    	set params=/IS /MT:64 /XF "copy-default-printer-sets-to-desktop.bat" /IF *.bat
    EXIT /B
    
    :CASE_MoveLogs
    	rem Sets parameters for moving remote log files
    	set params=/IS /IT /MT:64 /MOV /IF *.log /IF *.htm /IF *.txt /XF imageVersion.log /XF fog.log
    EXIT /B
    
    :CASE_XP
    	rem Sets params and runs XP version of ROBOCOPY and leaves function
    	set params=/ZB /S /MIR /XD App* /XD *drive /XD DropBox /XD odrive /XD "Cookies*" /XD "*IE*" /XD "*Hood" /XD "Start Menu*" /XD "Templates*" /XD "Recent*" /XD "SendTo*" /XD "Local*" /XD *min /XF tokens.dat /XF cache.dat /XD "Default User*" /XD Default* /XD Administrator* /XD NetworkService* /XD Public* /XD ".NET*" /XD adl* /XD QBD* /XD Updatus* /XD spiceworks* /XJ /XA:SH /XF ntuser* /XF *.ost /XF *.lnk
    	call :funcHead "Copying %typ% Dirs"
    	echo. Copying %log%...
    	C:\robocopy.exe "%src%" "%dst%" /LOG:"C:\%log%.log" /R:1 /W:1 %params%	
    	echo. Done Copying %log%
    	GOTO :EOF
    EXIT /B
    
    :func
    	rem Function to call external shared functions
    	call :funcHead "Calling %~1"
    	set params="%~2" "%~3" "%~4" "%~5" "%~6" "%~7" "%~8" "%~9"
    	CALL \\arrowfs4.arrowheaddental.com\includes\%~1 %params%
    EXIT /B	
    
    :dots
    	REM just echoing dots in a Function instead of copy pasting them so that it's consistent
    	echo ......................................................................
    EXIT /B
    
    :funcHead
    	REM A simple function for displaying a consistent header at the start of functions
    	call :dots
    	echo. %~1
    	call :dots
    	rem @pause ::Uncomment to enable debugging mode for script 
    EXIT /B
    

    copySelf.bat

    ::-----------------------------------------------------------------------------
    :: Arrowhead Dental Lab admin_scripts
    :: Script Name: copySelf
    :: Original Author: jfullmer
    :: Created Date: 2016-07-08 09:39:44
    :: Last Updated Date: 2016-07-18 11:31:44
    :: Update Author: jfullmer
    :: Version: 1.6
    ::-----------------------------------------------------------------------------
     
     
    @ECHO OFF
    rem Takes parameters of %~dp0 for runPath, %~f0 for fully qualified path, and %0 for file name
    rem This function should be called after setting these outside of other functions. i.e. at the top of the script before calling main you could have
    rem set pwd=%~dp0
    rem set fPath=%~f0
    rem set fName=%~n0
    rem Then run the script like this call :func copySelf.bat %pwd% %fPath% %fname%
    
    set var1=%1
    set var2=%2
    set var3=%3
    set runPath=%var1:"=%
    set fqPath=%var2:"=%
    set fileName=%var3:"=%
    call :main
    rem @pause ::Uncomment to enable debugging mode for script 
    GOTO :EOF
    
    :main
    	call :funcHead "Copying self to C drive and ensuring being run as admin"
    	IF NOT %runPath%==C:\ (
    		echo. Copying self to C drive
    		set includes=\\arrowfs4.arrowheaddental.com\includes
    		net use %includes% /USER:rawr meow
    		call :func mntShare.bat \\arrowfs4.arrowheaddental.com\scripts Q	
    		XCOPY %fqPath% C:\ /H /Y
    	 	net session >nul 2>&1
    	    if %errorLevel% == 0 (
    			echo opening copied version.
    			CALL C:\%fileName%
    			call :func delShare.bat Q:
    			GOTO :EOF
    	    ) else (
    	        echo This needs to be run as admin, try again as admin if it fails...
    	    	GOTO :EOF
    		)
    		GOTO :EOF
    	)
    EXIT /B
    
    :func
    	call :funcHead "Calling %~1"
    	set params="%~2" "%~3" "%~4" "%~5" "%~6" "%~7" "%~8" "%~9"
    	CALL %includes%\%~1 %params%
    EXIT /B
    	
    :dots
    	REM just echoing dots in a Function instead of copy pasting them so that it's consistent
    	echo ......................................................................
    EXIT /B
    
    :funcHead
    	REM A simple function for displaying a consistent header at the start of functions
    	call :dots
    	echo. %~1
    	call :dots
    	rem @pause ::Uncomment to enable debugging mode for script 
    EXIT /B
    

    copyShortcuts.bat (for creating shortcuts on silent installations)

    ::-----------------------------------------------------------------------------
    :: Arrowhead Dental Lab admin_scripts
    :: Script Name: copyShortcuts
    :: Original Author: jfullmer
    :: Created Date: 2016-06-24 15:37:20
    :: Last Updated Date: 2016-07-15 14:57:50
    :: Update Author: jfullmer
    :: Version: 2.3
    ::-----------------------------------------------------------------------------
     
     
    @ECHO OFF
    
    rem Set each var to the passed parameter minus the "'s'
    set var1=%1
    set var2=%2
    set var3=%3
    set programName=%var1:"=%
    set programCat=%var2:"=%
    set shortcuts=%var3:"=%
    call :main
    rem GOTO :EOF
    GOTO :EOF
    
    
    :main
    	REM this is a function to copy/move any shortcuts to the organized folders
    	REM I reccomend making a shortcut directory in the self extracting archive so that you only need this one command
    
    	set includes=\\arrowfs4.arrowheaddental.com\includes
    	net use %includes% /USER:rawr meow
    
    	set startMenu=C:\ProgramData\Microsoft\Windows\Start Menu\Programs\%programCat%
    	set curUserStartMenu=AppData\Roaming\Microsoft\Windows\Start Menu\Programs\%programCat%
    	set startFolder=%startMenu%\%programName%
    	set curUserStartFolder=%curUserStartMenu%\%programName%
    
    	call :funcHead "Organizing Start Menu shortcuts"
    	setlocal enableextensions enabledelayedexpansion 
    
    	echo. Create shared shortcut dirs...
    	echo. Creating "%startMenu%" and "%startFolder%"
    	if not exist "%startMenu%" mkdir "%startMenu%"
    	if not exist "%startFolder%" mkdir "%startFolder%"
    
    	echo. Copy to shared startmenu...
    	call :func copyDir.bat "Start menu shortcuts" "%shortcuts%" "%startFolder%" Mir
    	
    	echo. Copy to each user's start menu...
    	for /F %%i in ('dir /a:-s /b C:\Users') DO (
    		if not %%i==Public (
    			echo. create %%i shortcut dirs...
    			if not exist "C:\Users\%%i\%curUserStartMenu%" mkdir "C:\Users\%%i\%curUserStartMenu%"
    			if not exist "C:\Users\%%i\%curUserStartFolder%" mkdir "C:\Users\%%i\%curUserStartFolder%"
    			echo. copy %%i shortcuts...
    			call :func copyDir.bat "User Start Menu Shortcuts-%%i" "%shortcuts%" "C:\Users\%%i\%curUserStartFolder%" Mir
    		)
    	)
    	endlocal
    	echo. Done Organizing Start Menu!
    
    EXIT /B
    
    :func
    	call :funcHead "Calling %~1"
    	set params="%~2" "%~3" "%~4" "%~5" "%~6" "%~7" "%~8" "%~9"
    	CALL %includes%\%~1 %params%
    EXIT /B
    
    :dots
    	REM just echoing dots in a Function instead of copy pasting them so that it's consistent
    	echo ......................................................................
    EXIT /B
    
    :funcHead
    	REM A simple function for displaying a consistent header at the start of functions
    	call :dots
    	echo. %~1
    	call :dots
    	rem @pause ::Uncomment to enable debugging mode for script 
    EXIT /B
    

    delShare.bat

    ::-----------------------------------------------------------------------------
    :: Arrowhead Dental Lab admin_scripts
    :: Script Name: delShare
    :: Original Author: jfullmer
    :: Created Date: 2016-06-24 14:31:09
    :: Last Updated Date: 2016-07-14 08:23:26
    :: Update Author: jfullmer
    :: Version: 1.9
    ::-----------------------------------------------------------------------------
     
     
    @ECHO OFF
    rem Tried looping through param count, but could only echo the string of %1 etc and it didn't parse it as an arg within the for loop.
    
    call :funcHead "Deleting Share"
    
    echo. Deleting %1 share....
    net use %1 /delete /Y >nul
    
    GOTO :EOF
    
    :dots
    	REM just echoing dots in a Function instead of copy pasting them so that it's consistent
    	echo ......................................................................
    EXIT /B
    
    :funcHead
    	REM A simple function for displaying a consistent header at the start of functions
    	call :dots
    	echo. %~1
    	call :dots
    	rem @pause ::Uncomment to enable debugging mode for script 
    EXIT /B
    

    InstallMSI.bat (Would like to add ability to include extra optional property parameters, but haven’t figured that one out yet)

    ::-----------------------------------------------------------------------------
    :: Arrowhead Dental Lab admin_scripts
    :: Script Name: installMsi
    :: Original Author: jfullmer
    :: Created Date: 2016-07-07 13:16:30
    :: Last Updated Date: 2016-07-14 08:23:08
    :: Update Author: jfullmer
    :: Version: 1.2
    ::-----------------------------------------------------------------------------
     
     
    @ECHO OFF
    	REM @ECHO off makes it so the commands run from the scripts are not displayed in the console
    	REM This is a template to start new silent installation scripts for use with the 7z sfx maker
    	REM It is just the functions that are needed for every install with some standardization
    	REM Just save this as your new install.bat and change the programName variable
    	rem Could make this take install/unintsall parameter to quickly install or uninstall a msi
    
    set var1=%1
    set var2=%2
    set var3=%3
    set msiPath=%var1:"=%
    set log=%var2:"=%
    set msiMode=%var3:"=%
    call :main_%msiMode%
    rem @pause ::Uncomment to enable debugging mode for script 
    GOTO :EOF
    
    :main_install
    	REM Function to call other functions and run the installation process
    	call :funcHead "Installing msi"
    	echo. "Installing msi at %msiPath% logged at %log%..."
    	msiexec /i "%msiPath%" /quiet /qn /norestart /log "%log%"
    	echo. Done installing msi...
    EXIT /B
    
    :main_uninstall
    	REM Function to call other functions and run the installation process
    	call :funcHead "uninstalling msi"
    	echo. "Installing msi at %msiPath% logged at %log%..."
    	msiexec /x "%msiPath%" /quiet /qn /norestart /log "%log%"	
    	echo. Done uninstalling msi...
    EXIT /B
    	
    :dots
    	REM just echoing dots in a Function instead of copy pasting them so that it's consistent
    	echo ......................................................................
    EXIT /B
    
    :funcHead
    	REM A simple function for displaying a consistent header at the start of functions
    	call :dots
    	echo. %~1
    	call :dots
    	rem @pause ::Uncomment to enable debugging mode for script 
    EXIT /B
    

    LogCleanup.bat (Copies logs put at C:*.log into C:\logs and then copies that folder to a remote location named by the hostname)

    ::-----------------------------------------------------------------------------
    :: Arrowhead Dental Lab admin_scripts
    :: Script Name: LogCleanup
    :: Original Author: jfullmer
    :: Created Date: 2016-07-14 09:47:57
    :: Last Updated Date: 2016-07-20 15:43:47
    :: Update Author: jfullmer
    :: Version: 1.8
    ::-----------------------------------------------------------------------------
     
     
    @ECHO OFF
    	rem Function to move and copy log files to archive directories both local and remote
    
    setlocal enableextensions enabledelayedexpansion
    
    call :main
    rem @pause ::Uncomment to enable debugging mode for script 
    GOTO :EOF
    
    :main
    	REM Function to call other functions and run the installation process
    
    	call :funcHead "Welcome to the log cleaner!"
    	call :setVars
    	call :copyLogs
    	call :func delShare.bat O:
    EXIT /B
    
    :setVars
    	REM function for setting script variables, typically for directories
    
    	call :funcHead "Setting script variables"
    	FOR /F "usebackq" %%i IN (`hostname`) DO SET hname=%%i
    	set includes=\\arrowfs4.arrowheaddental.com\includes
    	net use %includes% /USER:rawr meow
    
    	set root=\\arrowfs4.arrowheaddental.com\backups
    	set localLogs=C:\Logs
    	set remoteLogs=%root%\%hname%\logs
    	if not exist %localLogs% mkdir %localLogs%
    	call :func perms.bat %localLogs%
    	if not exist %remoteLogs% mkdir %remoteLogs%
    	call :func perms.bat %remoteLogs%
    
    	echo. Done setting script variables!
    
    	echo. Mounting installer directory
    	call :func mntShare.bat "%root%" O
    
    	echo. done!	
    EXIT /B 
    
    :copyLogs
    	call :funcHead "Moving Log Files"
    	call :func copyDir.bat "logs\Local Logs" C:\ %localLogs% MoveLogs
    	call :func copyDir.bat "logs\Remote Logs" %localLogs% %remoteLogs% Mir
    EXIT /B
    
    :func
    	call :funcHead "Calling %~1"
    	set params="%~2" "%~3" "%~4" "%~5" "%~6" "%~7" "%~8" "%~9"
    	CALL %includes%\%~1 %params%
    EXIT /B	
    	
    :dots
    	REM just echoing dots in a Function instead of copy pasting them so that it's consistent
    	echo ......................................................................
    EXIT /B
    
    :funcHead
    	REM A simple function for displaying a consistent header at the start of functions
    	call :dots
    	echo. %~1
    	call :dots
    	rem @pause ::Uncomment to enable debugging mode for script 
    EXIT /B
    

    mntShare.bat (Alternative to plain text credentials with net use, Requires creating powershell compatible aes key and password files, instructions on that in ps1 script after this one)

    ::-----------------------------------------------------------------------------
    :: Arrowhead Dental Lab admin_scripts
    :: Script Name: mntShare
    :: Original Author: jfullmer
    :: Created Date: 2016-06-24 13:34:10
    :: Last Updated Date: 2016-07-21 10:31:47
    :: Update Author: jfullmer
    :: Version: 3.4
    ::-----------------------------------------------------------------------------
     
     
    @ECHO OFF
    setlocal enableextensions enabledelayedexpansion
    rem set passed param of the share path to mount as mntPnt 
    set mntPnt=%1
    rem To use Persist you have to use a drive letter. Start with A and B
    set name=%2
    set mounted=0
    call :main
    GOTO :EOF
    
    :main
    	rem function to mount a share passed as param
    	call :funcHead "Mounting network share"
    	
    	call :setVars
    	call :mnt %login1% %pwFile1% %key1%
    	if !mounted!==1 call :success & EXIT /B
    	call :mnt %login2% %pwFile2% %key2%
    	if !mounted!==0 call :failed 
    	if !mounted!==1 call :success
    EXIT /B
    
    :setVars
    	rem Set vars to the domain and local share login names and key paths 
    	rem Path to encrypted password and key files
    	set pth=C:\Program Files (x86)\Fog\Keys
    
    	rem Domain Login
    	set domain1=Arrowhead
    	set user1=Scriptmin
    	set login1=%domain1%\%user1%
    	set pwFile1="%pth%\~"
    	set key1="%pth%\~.key"
    
    	rem Secondary local admin login
    	set login2=AdlAdmin
    	set pwFile2="%pth%\~2"
    	set key2="%pth%\~2.key"
    
    	rem variables to call the Powershell command cleaner
    	set psc=Powershell.exe -C
    	set PSDrive=New-PSDrive -Name '%name%' -PSProvider FileSystem -Persist -Root
    	set createCred=-Credential (New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList
    	set log="C:\logs\PS-mnt-%name%.log"
    	set log2="C:\logs\net-use.log"
    	set log3="C:\logs\net-use-delete.log"
    EXIT /B
    
    :mnt
    	rem function to call the New-PSDrive command with encrypted credentials
    	rem call :dots 
    	echo. Attempting to Mount drive to %name% with encrypted credentials for %~1 (log at %log%)...
    	rem Delete log to ensure its creation
    	del %log%
    	%psc% "%PSDrive% '%mntPnt%' %createCred% '%~1', (Get-Content '%~2' | ConvertTo-SecureString -Key (Get-Content '%~3')));" > %log%
    	call :mntCheck
    EXIT /B
    
    :mntCheck
    	rem echo mounted is !mounted!
    	if !mounted!==1 (
    		rem echo. already mounted!
    		EXIT /B
    	)
    	rem Device was mounted if log contains GB in description of mounted drive
    	call :check "GB" %log% 1
    
    	rem Device was already mounted...
    	call :check "The local device name is already in use" %log% 2
    
    	rem multiple connections exist, so it's already mounted via a different user
    	call :check "Multiple connections" %log% 3
    
    	rem Check with net use for mntPnt just in case
    	net use > %log2%
    	call :check %mntPnt% %log2% 4
    	if !mounted!==0 echo. The drive did not mount with this login...
    EXIT /B
    
    :check
    	if !mounted!==1 (
    		rem echo. already mounted!
    		EXIT /B
    	)
    	rem echo. Checking for %~1 string...
    	set varStr1="%%found%~3%%"
    	set varStr2=%varStr1:"%=%
    	set varStr=%varStr2:~0,6%
    	set %varStr%=
    	FOR /F "usebackq" %%i IN (`findstr /N /C:"%~1" %~2`) DO SET %varStr%=%%i
    	rem echo %varStr% is !%varStr%!
    	rem type %log%
    	if defined %varStr% set mounted=1
    EXIT /B
    
    :dots
    	REM just echoing dots in a Function instead of copy pasting them so that it's consistent
    	echo ......................................................................
    EXIT /B
    
    :funcHead
    	REM A simple function for displaying a consistent header at the start of functions
    	call :dots
    	echo. %~1
    	call :dots
    	rem @pause ::Uncomment to enable debugging mode for script 
    EXIT /B
    
    :success
    	echo. %mntPnt% Mounted successfully as %name% 
    	GOTO :EOF	
    EXIT /B
    
    :failed
    	echo. %mntPnt% Did not Mount as %name%!
    	GOTO :EOF
    EXIT /B
    

    Run once ps1 script to create encrypted key and password files for mounting shares (I make one for a domain login, and one for a local admin login for redundancy in this example) (more info found here http://www.adminarsenal.com/admin-arsenal-blog/secure-password-with-powershell-encrypting-credentials-part-2/)

    $pth="\path\to\securely\store\keys"
    $keyFile1="$pth\~.key"
    $keyFile2="$pth\~2.key"
    
    #Create aes key 1
    $AESkey1 = New-Object Byte[] 32
    [Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($AESkey1)
    $AESkey1 | out-file $keyFile1
    
    #create aes key 2
    $AESkey2 = New-Object Byte[] 32
    [Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($AESkey2)
    $AESkey2 | out-file $keyFile2
    
    $pwFile1 = "$pth\~"
    $pwFile2 = "$pth\~2"
    
    #create encrypted pw file with aes key
    $pw1 = "domainPassword" | ConvertTo-SecureString -AsPlainText -Force
    $pw1 | ConvertFrom-SecureString -key $AESkey1 | Out-File $pwFile1
    
    #create encrypted pw file with other aes key
    $pw2 = "localAdminPassword" | ConvertTo-SecureString -AsPlainText -Force
    $pw2 | ConvertFrom-SecureString -key $AESkey2 | Out-File $pwFile2
    
    #to create powershell credential objects (mntshare.bat does this already)
    $user1 = "domain\user"
    $user2 = ".\Administrator"
    $domainCredential = New-Object -TypeName System.Management.Automation.PSCredential `
     -ArgumentList $user1, (Get-Content $pwFile1 | ConvertTo-SecureString -Key $AESkey1)
    $administratorCredential = New-Object -TypeName System.Management.Automation.PSCredential `
     -ArgumentList $user2, (Get-Content $pwFile2 | ConvertTo-SecureString -Key $AESkey2)
    

    perms.bat (for setting windows permissions on a folder recursively, like chmod -R)

    ::-----------------------------------------------------------------------------
    :: Arrowhead Dental Lab admin_scripts
    :: Script Name: perms
    :: Original Author: jfullmer
    :: Created Date: 2016-07-07 09:45:55
    :: Last Updated Date: 2016-07-19 10:34:40
    :: Update Author: jfullmer
    :: Version: 1.4
    ::-----------------------------------------------------------------------------
     
     
    @ECHO OFF
    	rem This function gives full recursive access to authenticated users to a folder passed as parameter 1 and logs it to param 2
    set var1=%1
    set var2=%2
    set pth=%var1:"=%
    set log=C:\%var2:"=%.log
    call :perms
    rem @pause ::Uncomment to enable debugging mode for script 
    GOTO :EOF
    
    :perms
    	call :funcHead "Setting Permissions"
    	echo. Granting Full Access to Authenticated Users and LocalSystem to %pth%
    	cacls "%pth%" /T /E /G "Authenticated Users":F > "%log%"
    	cacls "%pth%" /T /E /G System:F > "%log%"
    
    EXIT /B
    	
    :dots
    	REM just echoing dots in a Function instead of copy pasting them so that it's consistent
    	echo ......................................................................
    EXIT /B
    
    :funcHead
    	REM A simple function for displaying a consistent header at the start of functions
    	call :dots
    	echo. %~1
    	call :dots
    	rem @pause ::Uncomment to enable debugging mode for script 
    EXIT /B
    

    regDlls.bat (for registering dll files, useful in some silent installations)

    ::-----------------------------------------------------------------------------
    :: Arrowhead Dental Lab admin_scripts
    :: Script Name: regDlls
    :: Original Author: jfullmer
    :: Created Date: 2016-07-08 11:21:24
    :: Last Updated Date: 2016-07-14 08:14:10
    :: Update Author: jfullmer
    :: Version: 1.1
    ::-----------------------------------------------------------------------------
     
     
    @ECHO OFF
    	REM This script loops through a given path and registers any and all dlls in that path
    set var1=%1
    set pth=%var1:"=%
    call :main
    rem @pause ::Uncomment to enable debugging mode for script 
    GOTO :EOF
    
    :main
    	for %%f in ("%pth%\*.dll") do ( 
    		regsvr32 /s "%pth%\%~nf.dll" 
    	)
    EXIT /B
    
    :dots
    	REM just echoing dots in a Function instead of copy pasting them so that it's consistent
    	echo ......................................................................
    EXIT /B
    
    :funcHead
    	REM A simple function for displaying a consistent header at the start of functions
    	call :dots
    	echo. %~1
    	call :dots
    	rem @pause ::Uncomment to enable debugging mode for script 
    EXIT /B
    

    regImport.bat (Import a single reg key file or import a folder of them)

    ::-----------------------------------------------------------------------------
    :: Arrowhead Dental Lab admin_scripts
    :: Script Name: regImport
    :: Original Author: jfullmer
    :: Created Date: 2016-06-24 15:45:34
    :: Last Updated Date: 2016-07-14 08:13:22
    :: Update Author: jfullmer
    :: Version: 1.9
    ::-----------------------------------------------------------------------------
     
     
    @ECHO OFF
    rem Parameter 2 for dir of file
    rem Can't pipe output of reg import to text file with >, otherwise would use that to stop once one succeeds
    set var1=%1
    set var2=%2
    rem Path to Folder or File
    set regs=%var1:"=%
    rem Folder or File
    set importMode=%var2:"=% 
    call :importReg_%importMode%
    GOTO :EOF
    
    
    :importReg_Folder
    	call :funcHead "Importing regkeys from directory"
    	for %%f in ("%regs%\*.reg") do (
    		echo. "Importing %%~nf registry key with every possible syntax..."
    		REG IMPORT "%regs%\%%~nf.reg" /reg:64
    		REG IMPORT "%regs%\%%~nf.reg" /reg:32
    		REG IMPORT "%regs%\%%~nf.reg"
    		REG IMPORT %regs%\%%~nf.reg
    		REG IMPORT %regs%\%%~nf.reg /reg:64
    		REG IMPORT %regs%\%%~nf.reg /reg:32
    	)
    	echo. Done Importing registry keys
    EXIT /B
    
    :importReg_File
    	call :funcHead "Importing reg keys from File"
    	echo. Importing %regs% with every possible syntax...
    	REG IMPORT "%regs%" /reg:64
    	REG IMPORT "%regs%" /reg:32
    	REG IMPORT "%regs%"
    	REG IMPORT %regs%
    	REG IMPORT %regs% /reg:64
    	REG IMPORT %regs% /reg:32
    	echo. Done importing reg key
    EXIT /B
    
    :dots
    	REM just echoing dots in a Function instead of copy pasting them so that it's consistent
    	echo ......................................................................
    EXIT /B
    
    :funcHead
    	REM A simple function for displaying a consistent header at the start of functions
    	call :dots
    	echo. %~1
    	call :dots
    	rem @pause ::Uncomment to enable debugging mode for script 
    EXIT /B
    

    syncTime.bat (syncs the time with the preconfigured ntp server)

    ::-----------------------------------------------------------------------------
    :: Arrowhead Dental Lab admin_scripts
    :: Script Name: syncTime
    :: Original Author: jfullmer
    :: Created Date: 2016-07-08 10:25:58
    :: Last Updated Date: 2016-07-14 08:13:06
    :: Update Author: jfullmer
    :: Version: 1.2
    ::-----------------------------------------------------------------------------
    	
     
    @ECHO OFF
    	rem Function to sync time to auto domain and manual ntp server that is the domain
    call :main
    rem @pause ::Uncomment to enable debugging mode for script 
    GOTO :EOF
    
    :main
    	call :funcHead "Syncing Clock"
    
    	rem Function that makes sure the time is synced to time.arrowheaddental.computer
    	rem Simply runs a resync 5 times to be sure, since if it's off due to a snapshot, it takes a couple tries
    	echo. stopping w32time service, configuring it, and resyncing it...
    	net stop w32time
            rem optionally configure a ntp server 
            set ntp=time.nist.gov
    	w32tm /config /syncfromflags:ALL /manualpeerlist:%ntp%
    	net start w32time
    	w32tm /config /update
    	for /l %%i in (1, 1, 5) do (
    		echo. time sync %%i
    		w32tm /resync
    	)
    EXIT /B
    	
    :dots
    	REM just echoing dots in a Function instead of copy pasting them so that it's consistent
    	echo ......................................................................
    EXIT /B
    
    :funcHead
    	REM A simple function for displaying a consistent header at the start of functions
    	call :dots
    	echo. %~1
    	call :dots
    	rem @pause ::Uncomment to enable debugging mode for script 
    EXIT /B
    

    wget.bat (Download a file from a url with powershell)

    ::-----------------------------------------------------------------------------
    :: Arrowhead Dental Lab admin_scripts
    :: Script Name: wget
    :: Original Author: jfullmer
    :: Created Date: 2016-07-08 11:43:56
    :: Last Updated Date: 2016-07-14 08:12:51
    :: Update Author: jfullmer
    :: Version: 1.2
    ::-----------------------------------------------------------------------------
     
     
    @ECHO OFF
    	REM This function uses powershell to download a given web url to a given path/file
    
    set var1=%1
    set var2=%2
    set url=%var1:"=%
    set file=%var2:"=%
    
    call :main
    rem @pause ::Uncomment to enable debugging mode for script 
    GOTO :EOF
    
    :main
    	call :funcHead "downloading file"
    	echo. downloading %file% from %url%...
    	powershell -Command "wget %url% -OutFile %file%;"
    EXIT /B
    	
    :dots
    	REM just echoing dots in a Function instead of copy pasting them so that it's consistent
    	echo ......................................................................
    EXIT /B
    
    :funcHead
    	REM A simple function for displaying a consistent header at the start of functions
    	call :dots
    	echo. %~1
    	call :dots
    	rem @pause ::Uncomment to enable debugging mode for script 
    EXIT /B	
    

    InstallFogService.bat (used in firstlogoncommands.bat to ensure latest version of fog service install, and to ensure setting some useful environment variables as fog service troubleshooting command shortcuts)

    ::-----------------------------------------------------------------------------
    :: Arrowhead Dental Lab admin_scripts
    :: Script Name: installFogService
    :: Original Author: jfullmer
    :: Created Date: 2016-02-18 16:39:27
    :: Last Updated Date: 2016-07-15 15:51:54
    :: Update Author: jfullmer
    :: Version: 2.10
    ::-----------------------------------------------------------------------------
    
    @ECHO off
    
    call :main
    GOTO :EOF
    
    :main
    	call :funcHead "Installing Latest FOGService"
    	call :setVars
    	call :downloadInstall
    	call :settings
    	call :func delShare.bat B:
    	echo. Done!
    EXIT /B
    
    :setVars
    	rem Must be run as domain admin for key copy to work....
    	call :funcHead "Setting vars and mounting dirs"
    
    	set fogip=fog-server
    	set dUrl=http://%fogip%/fog/client/download.php?newclient
    	set dFile=C:\FOGService.msi
    	set pth=C:\Program Files (x86)\Fog\Keys
    	set includes=\\arrowfs4.arrowheaddental.com\includes
    	net use %includes%
    	set secretKeyPath=\\path\to\secure\keys
    	call :func mntShare.bat %secretKeyPath% B
    EXIT /B
    
    :downloadInstall
    	call :funcHead "downloading and installing client"
    
    	echo. downloading latest client...
    	call :func wget.bat %dUrl% %dFile%
    
    	echo. installing client...
    	call :func installMsi.bat %dFile% C:\fogInstall.log install
    EXIT /B
    
    
    :settings
    	call :funcHead "Configuring settings"
    
    	echo. Setting environment variables...
            rem makes it so a auto-updating fog log can be viewed with the command %flog%
    	setx flog "powershell.exe -C \"cat -wait C:\fog.log;\"" /M
            rem makes it so you can restart the fog service with the command %refog%
    	setx refog "net stop fogservice & net start fogservice" /M
    
    	echo. starting service...
    	net start FOGService
    
    	echo. deleting downloaded file
    	del %dFile% /F /Q
    
    	rem This part will only work when run by an IT admin account...
    	echo. Copying Keys
    	mkdir "%pth%"
    
    	call :func copyDir.bat "Secure Keys" %secretKeyPath% "%pth%" Mir
    
    EXIT /B
    
    :func
    	rem Function to call external shared functions
    	call :funcHead "Calling %~1 and waiting"
    	set params="%~2" "%~3" "%~4" "%~5" "%~6" "%~7" "%~8" "%~9"
    	CALL %includes%\%~1 %params%
    	if %~1==copySelf.bat if NOT %~dp0==C:\ GOTO :EOF
    EXIT /B	
    
    :dots
    	REM just echoing dots in a Function instead of copy pasting them so that it's consistent
    	echo ......................................................................
    EXIT /B
    
    :funcHead
    	REM A simple function for displaying a consistent header at the start of functions
    	call :dots
    	echo. %~1
    	call :dots
    	rem @pause ::Uncomment to enable debugging mode for script 
    EXIT /B
    

    I intend to eventually make a public git with universalized versions of all this and keep it updated with my stable versions.
    But that will take some work, because I’m me and I would want to automate the process of making them universal and without my share names and such. Have to make a script to take out personal information from all the scripts. Which means putting any and all variable information in a standardized form and location too. So that idea might take a while. But when that does happen, it’ll be pretty cool. I update these scripts almost daily, kinda like how often the fog dev/trunk branch is updated. When I do that, I would put my instructions on branching from it and using sublime text and sublime text package manager to use sublime add ons like git and fileheader to do all the file header versioning stuff and committing and such straight from the text editor.


  • Testers

    @jayrob86 said in Image Prep Script:

    @JJ-Fullmer would you mind sharing howith you are able to have a firstlogin and Setup Complete without sysprep. I am thinking of using the pnputil to install driver cabs after PC is imaged.

    That would be these functions in the image prep script…

    :setupFirstLogon
    	rem Function to enable autologon for Administrator
    	echo... apply General Profile on base images...
    	if %hn%==baseImageVM (
    		start %afterScripts%\Apply-Default-Profile-args.bat General
    	) else if %hn%==BASEIMG-32 (
    		start %afterScripts%\Apply-Default-Profile-args.bat General-32
    	) else (
    		echo. do not apply anything here...
    	)
    	echo. wait for profile to apply...
    	timeout /t 60
    
    	echo. loop through and import all keys...
    	REG IMPORT %afterScripts%\autologon-keys\admin-autologon.reg
    	REG IMPORT "%afterScripts%\autologon-keys\admin-autologon.reg" /reg:32
    	REG IMPORT "%afterScripts%\autologon-keys\admin-autologon.reg" /reg:64
    	
    	echo. Create the script to run the logon script via echos...and create in both possible spots...
    
    	call :createScript AdlAdmin
    	call :createScript Administrator
    
    	EXIT /B
    
    :createScript
    	rem Function to create the script to start the logon script, takes user Parameters...
    	call :funcHead "Creating startup script for %~1"
    	set firstLoginBatPath=AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\firstLogin.bat
    	echo @ECHO OFF > "C:\Users\%~1\%firstLoginBatPath%"
    	echo net use %scriptShare% /USER:%domain%\%user% %passwd% >> "C:\Users\%~1\%firstLoginBatPath%"
    	echo start %afterScripts%\firstLogonCommands.bat >> "C:\Users\%~1\%firstLoginBatPath%"
    
    	EXIT /B
    

    And this is the registry key .reg file it imports

    Windows Registry Editor Version 5.00
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon]
    "DefaultDomainName"=""
    "DefaultUserName"="Administrator"
    "AutoAdminLogon"="1"
    "DefaultPassword"="plainTextPassword"
    

    And here is the key to disable it

    Windows Registry Editor Version 5.00
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon]
    "DefaultDomainName"=""
    "DefaultUserName"=""
    "AutoAdminLogon"="0"
    "DefaultPassword"=""
    

    Fun fact, this is what sysprep does to do it too if you don’t use the encrypted password option, that I never figured out how to use anyway. I am trying to find a way.

    But wait, there’s more!
    Here is my firstLogonCommands.bat (some call it setupcomplete, to each their own.) Followed by a few of the shared functions it calls.

    ::-----------------------------------------------------------------------------
    :: Arrowhead Dental Lab admin_scripts
    :: Script Name: firstLogonCommands
    :: Original Author: jfullmer
    :: Created Date: 2016-04-15 16:27:16
    :: Last Updated Date: 2016-07-21 07:36:57
    :: Update Author: jfullmer
    :: Version: 5.3
    ::-----------------------------------------------------------------------------
     
    @ECHO OFF
    
    rem start by setting path
    set pwd=%~dp0
    set fPath=%~f0
    set fName=%0
    set drivers=C:\Windows\System32\DriverStore\FileRepository
    set slmgr=cscript C:\Windows\System32\slmgr.vbs
    rem set kms server address and port. i.e. 
    set kms=kms.domain.com:1688
    rem set login info for public share if needed
    set publicShareOwner=user
    set publicSharePassword=password
    set afterScripts=\\arrowfs4.arrowheaddental.com\scripts\Automating-Imaging\After-Image
    call :main
    rem @pause ::Uncomment this to enable debugging mode
    GOTO :EOF
    
    :main
    	REM Function to call other functions and run the installation process
    
    	rem Includes is a public share that only contains shared functions, like included files in code
    	set includes=\\arrowfs4.arrowheaddental.com\includes
    	net use %includes% /USER:%publicShareOwner% %publicSharePassword%
    	call :func copySelf.bat %pwd% %fPath% %fname%
    	call :funcHead "firstLogonCommands"
    	call :func syncTime.bat
    	rem call :restoreGroupPolicy
        call :perms
        if %PROCESSOR_ARCHITECTURE%==x86 (
        	call :fixRDP32
        ) else (
        	call :fixRDP
        )
    	call :configFogSvc
    	call :fixBootMgr
    	call :disableAutologon
        call :deleteStuffAndSelf 
    EXIT /B
    
    :perms
    	call :funcHead "Changing permissions"
    
    	rem Change permissions on folder containing desktop, lockscreen, and account images
    	rem Note, you can copy over the files in C:\ProgramData\Microsoft\AccountPictures with the same names and sizes to make custom account pictures
        call :func perms.bat C:\img imgFolderPerms
        rem Give permissions on windows installer store
        call :func perms.bat C:\Windows\Installer "Windows Installer perms"
        rem Some program paths unique to my organization, can add your own
        call :func perms.bat "C:\Program Files\Inventrix" "Inventrix perms"
        call :func perms.bat "C:\Program Files (x86)\Sage" "sage perms"
        call :func perms.bat "C:\Program Files (x86)\Sage Software" "sage Software perms"
    	rem Give System and authenticated users full access to the fog path 
        call :func perms.bat "C:\Program Files (x86)\FOG" "Fog perms"
    EXIT /B
    
    :fixRDP32
    	call :funcHead "Fix remote desktop"
    
    	echo. Put the remote desktop devices back...
    	call :addDriver "NDIS Virtual Network Adapter Enumerator" %drivers%\ndisvirtualbus.inf_x86_1fa29bcc35ca8834\ndisvirtualbus.inf ROOT\NdisVirtualBus
    	call :addDriver "UMBus Root Bus Enumerator" %drivers%\umbus.inf_x86_c0f8109e25343b64\umbus.inf ROOT\umbus
    	call :addDriver "Remote Desktop Device Redirector Bus" %drivers%\rdpbus.inf_x86_8c65bb1c8e29599b\rdpbus.inf ROOT\RDPBUS
    	call :addDriver "Remote Desktop USB HUB" %drivers%\tsusbhub.inf_x86_3cb0aab868426cda\tsusbhub.inf ROOT\tsusbhub
    EXIT /B
    
    :fixRDP
    	call :funcHead "Fix remote desktop"
    
    	echo. Put the remote desktop devices back...
    	call :addDriver "NDIS Virtual Network Adapter Enumerator" %drivers%\ndisvirtualbus.inf_amd64_c420021ea374b6f3\ndisvirtualbus.inf ROOT\NdisVirtualBus
    	call :addDriver "UMBus Root Bus Enumerator" %drivers%\umbus.inf_amd64_b5911c04e2dae8d2\umbus.inf ROOT\umbus
    	call :addDriver "Remote Desktop Device Redirector Bus" %drivers%\rdpbus.inf_amd64_e1a9f2699d349149\rdpbus.inf ROOT\RDPBUS
    	call :addDriver "Remote Desktop USB HUB" %drivers%\tsusbhub.inf_amd64_560cadd4ed8a56be\tsusbhub.inf ROOT\tsusbhub
    EXIT /B
    
    
    :addDriver
    	echo. installing %~1...	
    	C:\Windows\System32\devcon.exe install %~2 %~3
    	rem Could also do...
    	rem pnputil -i -a %~2
    	echo. done!
    EXIT /B
    
    :disableAutologon
    	rem Function to disable disableAutologon and delete reg keys
    	call :funcHead "Disable autologon"
    	call :func regImport.bat "%afterScripts%\autologon-keys\Disable-autologon.reg" File
    EXIT /B
    
    :configFogSvc
    	call :funcHead "Configure Fog Service"
    	echo. install fog Service...
    	CALL %afterScripts%\installFogService.bat
    	echo. make sure FOGService is set to auto and restart it. 
        sc config FOGService start= auto
        net stop FOGService
        net start FOGService
        echo. just to be sure do it again...
        net start FOGService
    
        echo. open another command prompt with updating fog log...
        start %flog%
    EXIT /B
    
    :fixBootMgr
    	call :funcHead "Fixing boot manager"
    	bcdedit /delete {current}
    	bcdedit /delete {default}
    	bcdboot C:\Windows
    EXIT /B
    
    :deleteStuffAndSelf
    	call :funcHead "Clean Up"
    
    	rem echo. delete unattend files...
        rem del /Q /F c:\windows\system32\sysprep\unattend.xml
        rem del /Q /F c:\windows\Panther\unattend.xml
        echo. Change directory to delete folder and close the script.
        set scriptPath=AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\firstLogin.bat
        del "C:\Users\Administrator\%scriptPath%"
        del "C:\Users\AdlAdmin\%scriptPath%"
        rem ImgSetup.exe is a program that requires trend micro office scan, it resets GUIDs
        rem I beleive that simply having rearmed before imaging and then activating here does the same idea
        del C:\ImgSetup.exe
        echo. Fog will restart this computer in 2-3 minutes or this script will reboot it in 30 minutes in case snapins are installing...
        cd C:\
        rem rmdir C:\policies /S /Q & timeout /T 300 & devcon reboot & GOTO :EOF
        rem Make sure license was rearmed.
        rem If you don't have LogCleanup.bat at the end of imageprep, check for it at C:\rearmed.log instead
        if not exist C:\logs\rearmed.log (
    		%slmgr% -rearm > c:\rearmed.log
    	) else (
    		echo. Setting kms server...
    		%slmgr% /skms %kms%
    		echo. Activating windows via kms...
    		%slmgr% /ato
    	)
    	call :func LogCleanup.bat
    	call :func delShare.bat B:
    	rem delete self, restart after 30 minutes to avoid interupting any fog snapins installing, then exit script
        del C:\firstLogonCommands.bat & timeout /T 1800 & shutdown /r /t 00 & GOTO :EOF
    EXIT /B
    
     :func
    	rem Function to call external shared functions with up to 8 parameters.
    	rem Could do more with shift
    	call :funcHead "Calling %~1 and waiting"
    	set params="%~2" "%~3" "%~4" "%~5" "%~6" "%~7" "%~8" "%~9"
    	rem echo net use %includes%
    	CALL %includes%\%~1 %params%
    	rem If the function called was copyself and the script isn't being run from C:\ then the script has already run and should exit
    	if %~1==copySelf.bat if NOT %~dp0==C:\ GOTO :EOF
    EXIT /B	
    
    :dots
    	REM just echoing dots in a Function instead of copy pasting them so that it's consistent
    	echo ......................................................................
    EXIT /B
    
    :funcHead
    	REM A simple function for displaying a consistent header at the start of functions
    	call :dots
    	echo. %~1
    	call :dots
    	rem @pause ::Uncomment to enable debugging mode for script 
    EXIT /B
    


  • @Wayne-Workman said in Image Prep Script:

    @JJ-Fullmer said in Image Prep Script:

    pnputil

    Can you tell us more about that? I’m thinking I’m going to have to build a universal image now.

    PNP Utility can install drivers that match the hardware for the device.
    Here is an article that I found that discusses using PNPutil and Forfiles.

    https://deploymentbunny.com/2011/05/07/adding-drivers-using-pnputil-and-forfiles/
    https://deploymentbunny.com/2016/02/26/powershell-is-king-export-drivers-from-windows/ link text


  • Moderator

    @JJ-Fullmer said in Image Prep Script:

    pnputil

    Can you tell us more about that? I’m thinking I’m going to have to build a universal image now.



  • @JJ-Fullmer would you mind sharing howith you are able to have a firstlogin and Setup Complete without sysprep. I am thinking of using the pnputil to install driver cabs after PC is imaged.


  • Moderator

    @JJ-Fullmer Well, those were some refreshing things you just said. I’ll have to try this when I find some time.


  • Testers

    @Wayne-Workman I should add that it doesn’t remove driver files that are ready for plug n play.
    It just uninstalls all devices to make it hardware independent, just like sysprep does. So if you use sysprep you would use the sysprep function instead of the hardware independence function.

    Something else I do is when I do find a driver that is missing from windows 10 I get the inf file for it and add it to my image’s plug n play store with the command pnputil -a path/to/driver.inf I try to limit doing this to only network drivers because once you get that far windows update in windows 10 usually takes care of the rest.


  • Testers

    @Wayne-Workman Well before windows 10 I would make a batch script that I would deploy as a snapin that did silent installs of all the drivers for a specific model.
    Granted if I made that same script now I would just get the infs and their associated linked files and use pnputil -i -a *.inf to install all the drivers from a organized driver network share. Rather than silent installs of their setup.exe’s that install random little services with the drivers.

    But windows 10 has like 99% of the drivers built in or available in windows update, so I just don’t even worry about it anymore.

    Granted, removing all the drivers with this method does break Remote Desktop. So in my firstlogin script I have the following lines to add remote desktop back. The driver files needed stay in the store. These exact ones only work for windows 10 64 and 32 bit respectively. It’s similar for windows 7 and 8, you just have to find the exact name of the folder. Maybe using wildcards would work, not sure, just thought of that.

    set drivers=C:\Windows\System32\DriverStore\FileRepository
        if %PROCESSOR_ARCHITECTURE%==x86 (
        	call :fixRDP32
        ) else (
        	call :fixRDP
        )
    :fixRDP32
    	call :funcHead "Fix remote desktop"
    
    	echo. Put the remote desktop devices back...
    	call :addDriver "NDIS Virtual Network Adapter Enumerator" %drivers%\ndisvirtualbus.inf_x86_1fa29bcc35ca8834\ndisvirtualbus.inf ROOT\NdisVirtualBus
    	call :addDriver "UMBus Root Bus Enumerator" %drivers%\umbus.inf_x86_c0f8109e25343b64\umbus.inf ROOT\umbus
    	call :addDriver "Remote Desktop Device Redirector Bus" %drivers%\rdpbus.inf_x86_8c65bb1c8e29599b\rdpbus.inf ROOT\RDPBUS
    	call :addDriver "Remote Desktop USB HUB" %drivers%\tsusbhub.inf_x86_3cb0aab868426cda\tsusbhub.inf ROOT\tsusbhub
    	
    	EXIT /B
    
    :fixRDP
    	call :funcHead "Fix remote desktop"
    
    	echo. Put the remote desktop devices back...
    	call :addDriver "NDIS Virtual Network Adapter Enumerator" %drivers%\ndisvirtualbus.inf_amd64_c420021ea374b6f3\ndisvirtualbus.inf ROOT\NdisVirtualBus
    	call :addDriver "UMBus Root Bus Enumerator" %drivers%\umbus.inf_amd64_b5911c04e2dae8d2\umbus.inf ROOT\umbus
    	call :addDriver "Remote Desktop Device Redirector Bus" %drivers%\rdpbus.inf_amd64_e1a9f2699d349149\rdpbus.inf ROOT\RDPBUS
    	call :addDriver "Remote Desktop USB HUB" %drivers%\tsusbhub.inf_amd64_560cadd4ed8a56be\tsusbhub.inf ROOT\tsusbhub
    	
    	EXIT /B
    
    
    :addDriver
    	echo. installing %~1...	
    	C:\Windows\System32\devcon.exe install %~2 %~3
    	echo. done!
    
    	EXIT /B
    

  • Moderator

    @JJ-Fullmer since the script deletes drivers, would you be interested in sharing how you deploy drivers?



  • Ah ok, that makes sense.

    The way I was reading it was that this would make it so you didn’t need to sysprep , almost as a replacement, which is why i got confused. Even more so with the fun of SIDS and such.


  • Testers

    @Bob-Henderson Well just sysprep is one method. I just add in a lot of extra stuff. Like cleaning up windows update, making sure chkdsk isn’t going to need to run when you upload. Cleaning up various temporary files, creating a imageversion log, making sure the time is synced properly to prevent possible domain join issues, rearming windows activation, defragging the hard drive, removing all drivers manually. Sometimes sysprep doesn’t work, or sometimes it removes more than you want. I’ve done both with an without sysprep. I have found without sysprep and utilizing the methods in this script to make my image hardware independent to be much faster and smoother.
    But to each their own I just thought some other people might find something useful in it because It’s full of little snippets that answer questions and problems I had for years.


  • Moderator

    @Bob-Henderson The way I understand it it’s used to prep images regardless of whether or not you use sysprep. As such, it’s not a replacement for your current method, just a way to help you prepare for it.

    I have something similar to this, although much more simple and extremely specific to my environment.



  • Forgive me for ignorance, but why wouldn’t I just sysprep? I mean, it works, has worked for years, so…


  • Testers

    Oh how to use the thing,
    Copy paste into your favorite text editor (sublime text, notepad++, scite, or what have you) and save as ImagePrep.bat (or whatever you want as long as it’s .bat) I reccomend having it on a file share so you can run it from there and always have the most up to date version ready to run on a computer you want to upload a hardware independent image.

    I have many other scripts I’ve implemented into my FOG imaging workflow that I am happy to share if people want to see them.
    Like a firstLogon or a one time automatic admin login so you can have a firstLogon/setupcomplete script without sysprep.
    Backup and restore scripts for user files and settings when migrating a user’s local files to a new image
    And so many more. I’m still working to make them more universal and I really really want to find a way to not have plain text passwords in them for mounting shares with net use. (Virtual Smart Cards maybe, but they currently look complicated)



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