1

I'm trying to create a script that runs multiple setup .exes silently and for whatever reason, when I finish executing the installation of 7zip silently in my batch file, no other commands execute after it.

Kinda at my wits end. I've tried pauses, echos, other subroutine that just echos (which works and executes commands after returning).

But for whatever reason, after I execute 7zip.exe /S it just quits executing commands even after returning from the subroutine I made to install it.

@echo OFF


SET 7ZipName=7z*.exe

SET x86SetupFilePath=C:\PSDARS-Setup\x86\
SET x64SetupFilePath=C:\PSDARS-Setup\x64\

SET x647ZipPath=C:\Program Files\7-Zip\
SET x867ZipPath=C:\Program Files (x86)\7-Zip\

:: 1. Check for OS architecture
reg Query "HKLM\Hardware\Description\System\CentralProcessor\0" | find /i "x86" > NUL && set OS=32BIT || set OS=64BIT

if %OS%==32BIT GOTO :32BIT

if %OS%==64BIT GOTO :64BIT

:32BIT

:: Check arguments 1 = Installation Directory Path. If not set use base above 
IF NOT %1.==. SET x86SetupFilePath=%~1

::Install 7zip
CALL :Install7Zip 

setx PATH "%PATH%;%x647ZipPath%" /m

GOTO :ProgramEnd


:64BIT

:: Check arguments 1 = Installation Directory Path 
IF NOT %1.==. SET x64SetupFilePath=%~1

::Install 7zip
CALL :Install7Zip 

CALL :Test

Echo 7zip Installation Complete

::setx PATH "%PATH%;%x647ZipPath%" /m

GOTO :ProgramEnd

:Test
Echo a
GOTO :EOF

:: Author: Jacob Howarth
:: Date: 07/20/18
:: Description: This procedure will install the correct version of
:: the 7zip installer silent based on the architecture of the OS
::
:Install7Zip
IF %OS%==32BIT cd "%x86SetupFilePath%"

IF %OS%==64BIT cd "%x64SetupFilePath%"

for %%f in (%7ZipName%) do SET File=%~f     

%File% /S

ECHO.%ERRORLEVEL%

GOTO :EOF
:: End of Install7Zip

echo 7zip Installation Complete

:ErrorInstall7Zip
echo Error installing 7zip for %OS% OS. x64 path = %x64SetupFilePath%, x86 path =%x86SetupFilePath%.

:ProgramEnd
Jake
  • 341
  • 1
  • 3
  • 12
  • 3
    Every code path that I can see ends with `GOTO :ProgramEnd`, and there's nothing to do after `:ProgramEnd`. What do you expect to happen instead? – Ken White Jul 20 '18 at 22:02
  • 4
    Why are you checking the bitness of the CPU? _A 32bit Operating System can be installed on a 64bit CPU_. – Compo Jul 20 '18 at 22:39
  • 2
    Missing a percent symbol in this line if code: SET File=%~f. Also do not start variable names with a number. It can be seen as a command line argument. – Squashman Jul 21 '18 at 01:24
  • The command line `setx PATH "%PATH%;%x647ZipPath%" /m` is an absolute __NO GO - NEVER EVER__. You are corrupting the __system__ environment variable `PATH` with that command line for various reasons. See for example [Why are other folder paths also added to system PATH with SetX and not only the specified folder path?](https://stackoverflow.com/questions/25915767/) or [Adding the current directory to Windows path permanently](https://stackoverflow.com/questions/47070156/). There is really no need to add 7-Zip program files path to __system__ `PATH` as otherwise 7-Zip setup would do that. – Mofi Jul 21 '18 at 19:24
  • I appreciate the constructive changes but none of this really answers the question as to why it doesn't execute any commands after executing the setup for 7zip. @Mofi 7zip apparently does not get added to any path variable system or otherwise when installed silently. I've checking this and I don't see it. I'll check and see if it has anything to do with the for variables causing an error or something. – Jake Jul 22 '18 at 18:48

1 Answers1

1
@echo off
setlocal

:: Check for OS architecture.
set "SetupFilePath=%~1"

if not defined SetupFilePath (
    if defined ProgramFiles(x86^) (
        set "SetupFilePath=C:\PSDARS-Setup\x86"
    ) else (
        set "SetupFilePath=C:\PSDARS-Setup\x64"
    )
)

:: Change working directory.
cd /d "%SetupFilePath%" || (
    >&2 echo Failed to change directory.
    exit /b 1
)

:: Get setup file name.
set "SevenZipName=7z*.exe"
set "File="

for %%F in ("%SevenZipName%") do set "File=%%~F"

if not defined File (
    >&2 echo File not defined.
    exit /b 1
)

:: Install 7zip.
"%File%" /S

if errorlevel 1 (
    >&2 echo 7zip errorlevel: %errorlevel%
    exit /b 1
)

:: Add to PATH environment variable.
set "SevenZipPath=%ProgramFiles%\7-Zip"

if exist "%SevenZipPath%" (
    call :add_path "%SevenZipPath%" "%%ProgramFiles%%\7-Zip"
)

echo 7zip Installation Complete
exit /b 0


:add_path
set "main_key=HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
set "data="

:: Query the HKLM Path and get the key name, data type and data.
for /f "tokens=1,2,*" %%A in ('reg query "%main_key%" /v Path') do (
    if /i "%%~A" == "Path" (
        set "key_name=%%~A"
        set "data_type=%%~B"
        set "data=%%~C"
    )
)

if not defined data (
    >&2 echo Path data for write to registry is undefined.
    exit /b 1
)

:: Remove trailing semi-colon.
if "%data:~-1%" == ";" set "data=%data:~,-1%"

:: Check target is already in Path.
for %%A in ("%data:;=" "%") do for %%B in ("%~1" "%~2") do (
    if "%%~A" == "%%~B" (
        echo Directory "%%~B" is in Path.
        exit /b 0
    )
)

:: Set new_data to a value to suit data type.
if /i "%data_type%" == "REG_EXPAND_SZ" (
    set "new_data=%~2"
) else set "new_data=%~1"

if not defined new_data (
    >&2 echo Path new_data to write to registry is undefined.
    exit /b 1
)

:: Remove trailing backslash.
if "%new_data:~-1%" == "\" set "new_data=%data:~,-1%"

:: Backup and update Path.
if not exist "%~dp0Environment_Backup.reg" (
    echo Backing up key to Environment_Backup.reg.
    reg export "%main_key%" "%~dp0Environment_Backup.reg"
)

echo Adding "%new_data%" to Path.
>nul reg add "%main_key%" /v "Path" /t "%data_type%" /d "%data%;%new_data%" /f
exit /b 0

Code restructured to remove the goto flow.

Checking ProgramFiles(x86) for OS architecture.

The command setx is OK for simple variables though with the PATH variable, more code is needed to check the value of the key and add to the existing value only if needed. Considerations such as reg value type and possible variables in the value may need to be checked. A reg export file is created as a backup before the change is added.

Using user variable names not starting with a number. The reason for this is that a name such as %7ZipName% may be interpeted as %7 and ZipName%. The %7 is the 1st valid expansion as being the 7th argument. This may cause a syntax error.

Tested with a x64 OS. The OS environment may need a restart to update the changes or run SystemPropertiesAdvanced and click Environmental Variables and then OK twice to update.

michael_heath
  • 5,262
  • 2
  • 12
  • 22
  • How are you getting it to execute after the installation of 7Zip? I couldn't even get an echo to execute afterwards so I'm confused how `echo 7zip Installation Complete` was even able to work since its not all that different up to that point. Is because I didn't do setlocal? – Jake Jul 23 '18 at 16:20
  • In your source, the `%7` poisoned the `for` loop and the `echo` is after a `goto :eof` so it will actually go to the end of file and finish the script. – michael_heath Jul 23 '18 at 16:42
  • Okay understood about the for loop. However, does this mean that the section on this site is wrong about call? https://ss64.com/nt/call.html It says you can use `GOTO :EOF` to accomplish `exit /b` at the end of routines. – Jake Jul 23 '18 at 17:19
  • `goto :eof` and `exit /b` share similar behavior so can be interchanged. In your source, you call `:Install7Zip`, it proceeds down to `goto :eof`, then returns to caller line. The `:64bit` label has a echo though the `:32bit` label does not. The `reg query` may have `goto`ed to the `:32bit` label. – michael_heath Jul 23 '18 at 17:36