:: Title: Flexible Driver Launcher Script with Optional Silent Switch
:: Version: 1.1
:: Author: Tom Fichtner / t.fichtner@schenker-tech.de

@echo off
echo.
SETLOCAL

:: INTRODUCTION
::
:: This script jumps into the next sub-directory to run an executable
:: with admin privileges. To be more error tolerant, it will do this
:: for all sub-folders under its location, no matter what folder names
:: they have. The name of the executable to run will be pulled from a
:: text file "config.ini" which will be located in the same root folder
:: as the script itself. 
::
:: DEFINITION OF CONFIG.INI
::
:: config.ini contains up to 3 entries. Example:
::
:: ---------------------------------
:: [config]
:: exec=My Driver Installer.exe
:: silent=/verysilent /norestart
:: estimate=a moment of your time
:: reboot=0
:: ---------------------------------
::
:: DO NOT use any quotation marks in config.ini. Spaces and ASCII are OK.
::
:: If config.ini does not exist, the script will revert to the default
:: of running either "Setup.bat" or "Setup.exe" from the subfolder.
:: We don't need to write "Setup.bat" or "Setup.exe" here (keep it vague)
:: because the later command will be flexible enough to call either or.
:: If *both* .bat and .exe exist, ony .exe will be called.
::
:: FILE AND FOLDER NAME CONVENTION
::
:: Sub-folders and executable files are allowed to have spaces, periods,
:: brackets, commas, hypens, spaces and other common ASCII characters. 
:: However, random UTF-8 strings and Chinese characters might *not* work.

cd /D "%~dp0"

:: Changes directory to the current one. This is neccessary if the script
:: is invoked by double-click. Without this command, the working directory
:: might be the user's home folder, which we don't want.

if exist "config.ini" (
	call :ini "config.ini" exec %exec
	call :ini "config.ini" silent %silent
	call :ini "config.ini" estimate %estimate
	call :ini "config.ini" reboot %reboot
) else (
	set exec=
	set silent=
	set estimate=
	set reboot=
)


:: Reads settings from config.ini.
:: The function :ini is defined at the bottom of the batch file.
:: If no config.ini is found, all parameters will be set to null.

if "%exec%"=="" (
	set exec=Setup
)

:: Checks if %exec% has been set at all. If not, it will be reverted to "Setup".
:: This also includes cases where config.ini was found but is empty.

SET selfname=%~n0%~x0
:: This has to be outside of the following IF clause.

IF NOT "%~1"=="/s" (
	IF x%selfname:silent=%==x%selfname% (
		set silent=
	)
)

:: Checks if the filename of this batch contains the "silent" string.
:: If it does not, %silent% will be reverted back to null.
:: This procedure will be skipped if the script itself is run with the /s paramter.
:: This allows the user to run "Install-Package.bat /s" and still parse the silent
:: parameters, despite not having silent in the filename.

for /F "delims=" %%a in ('dir /ad /b') do CALL :RunExecutable "%%a"

:: Runs the main function for each sub-directory in the current work folder.
:: The variable %%a is the name of each sub-folder. It will be passed off 
:: to the RunExecutable function as its first (and only) parameter.
:: That parameter will be called as %~1 inside the function.

set exec
set silent
set estimate

:: After the for/in/do loop is complete, we unset our variables and exit.

IF NOT "%reboot%"=="" (
	IF NOT "%reboot%"=="0" (
		echo All finished. The system will reboot in 5 seconds.
		timeout 5
		shutdown /r /t 0
	)
)

:: If "reboot" in config.ini is anything except <empty> or "0", the system
:: will perform a timed reboot.

goto :eof

:: The script is finished at this point.
:: The following lines include the functions we are calling above.

:RunExecutable

cd %~1
if not exist "%exec%*" ( goto :noexecfound )
:: %~1 is the name of the folder that is currently called.
:: If the executable file cannot be found, we exit.

echo Starting %~1 driver installation...
IF NOT "%estimate%"=="" (
	echo This might take %estimate%...
)
:: If $estimate has been set in config.ini, we will display a little message here.

IF "%silent%"=="" (
	powershell -Command "Start-Process -FilePath '%exec%' -Verb runAs -Wait"
) else (
	powershell -Command "Start-Process -FilePath '%exec%' -ArgumentList '%silent%' -Verb runAs -Wait"
)
:: If %silent has been set in config.ini and confirmed by the name of the batch file
:: we will run an alternative powershell command with the "ArgumentList" parameter.
:: This parameter must not be empty, that's why we have to keep this seperate.
:: If %silent is emptythe command without "ArgumentList will be used.
:: "-Wait" is used to make sure that the batch will only continue after the executed command is complete.
:: "-Verb runAs" is the magic switch to prompt the user via UAC for Admin rights

echo.
echo Driver installation complete.
timeout 3
:: Timeout shows a 3 second timer that can be skipped with any key. This enables the user to appreciate
:: the success message.
cd ..
:: Before we close the function, we go back one folder up. In case the function gets called again with a second folder.
EXIT /B 0
:: Exit Function

:ini    
@for /f "tokens=2 delims==" %%a in ('find "%~2=" "%~1"') do @set %~3=%%a
:: Source: https://stackoverflow.com/a/4518146
EXIT /B 0

:noexecfound
echo The executable defined in config.ini could not be found. Please check if folder structure and filenames are correct.
echo.
pause
goto :eof

:eof