Why does makensis.exe return errorlevel 1 even though it worked? - nsis

I have a NSIS script that works. It compiles, the produced installer works fine. And yet, makensis.exe returns 1 instead of 0. This is a real pain because I use it in a continuous integration setup and now my CI thinks the build failed.
This just started when I switched my project from SVN to Git, and made one tiny change in the NSIS script (I changed a path in two places).
There are NO compile errors printed (even with /V4) that I can find.
There are 6 warnings but they are the same 6 it had in the old repo where makensis returned 0.
I diffed the previous, "errorlevel=0" output with the new "errorlevel=1" output and found no significant differences.
It produces an installer that works fine.
I'm still using the same exact copy of makensis.exe.
And yet, it returns errorlevel 1.
I am certain that I had this problem a couple years ago, but I can't remember how I solved it. I think I just upgraded to the latest version of NSIS, but I can't do that this time (I'm already using the latest).

Nevermind.
The problem was in my batch file that executed makensis.exe. It had something like this:
for %%A in (*.nsi) do (
makensis.exe "%%A"
if %errorlevel% neq 0
echo %%A Failed.
)
)
The problem is that %errorlevel% was being evaluated to a constant value at the beginning of the loop. In order to actually check the errorlevel within the loop, you have to use !errorlevel! not %errorlevel%. Also you have to have SETLOCAL ENABLEDELAYEDEXPANSION at the top of your batch file (I had that already).
So evidently some prior unimportant step (possibly mkdiring a dir that already existed) was returning errorlevel 1 and then my check was thinking it was from the makensis call. Of course this begs the eternal question: "how did this ever work?"

Related

How WinSCP determined Errors? [duplicate]

I'm new to WinSCP. I'm trying to set an Errorlevel for the batch IM running. If the Errorlevel= 0 PRINT SUCCESS and transfers those files with Errorlevel 0 to folder call success.
if the error not equal to 0 moves the file with the error level to different folder call errors. Any suggestions.
HERE IS MY.bat
WinSCP.exe /console /script="c:\users\PDP\script.txt" /log="c:\users\PDP\lastrun.txt"
if %ERRORLEVEL% equ 0
echo Success
sendmail.exe -t < success_mail.txt
move OPTTXM* c:\users\PDP\sent ( the files in the batch start with OPTTXM*)
exit /b 0
if %ERRORLEVEL% neq 0 goto error
echo Error!
sendmail.exe -t < error_mail.txt
move ????????????????????????????????? ( how you can get inside each file and check the status
)
exit /b 1
Thanks in advance
You can make WinSCP create XML log with files that were and were not transferred. But it would be difficult (if possible at all) to parse/process those XML files in a batch file.
You better use a more powerful scripting language, like PowerShell.
See for example Move files after upload using PowerShell/WinSCP Script.
(there are many other similar questions here)
There's also WinSCP article on this topic:
Moving local files to different location after successful upload

Why is an error output on parsing a line within a FOR loop? [duplicate]

This question already has an answer here:
Variables are not behaving as expected
(1 answer)
Closed 4 years ago.
I'm currently trying to write a batch file to automatically detect if a VPN is logged in or not. However, the code is not working as expected.
set VAR=SUCCESS
for /f "delims=: tokens=1" %%i in ('"C:\Program Files (x86)\F5 VPN\f5fpc.exe" -info') do (
set str=%%i
set rep=%str:logged out=%
echo %str%
echo %rep%
if not "%str%"=="%rep%" (
set VAR=FAIL
)
echo %VAR%
)
echo %VAR%
Running "C:\Program Files (x86)\F5 VPN\f5fpc.exe" -info will give exactly the following (will have spaces before the start of each line):
Command arguments:
INFO result:
session: code: status:
xxxxxx 64 logged out
There is 1 active session(s)!
The status can be either logged out or session established. What I'm trying to determine is that I'd have run the VPN. If the user has successfully logged into the VPN, then I need to do something, otherwise, have to execute some other code.
VAR=FAIL means the VPN failed to log in successfully and would be in logged out state. The problem I'm facing is that the str and rep variables are not assigned any value. I can determine it by the echo statements.
Can somebody help me out in this?
There is a much more simple way to work around this. The way you have the for statement setup will cause it to perform echo's and set strings for each new line of the output string.
A very easy way is to use the | FIND /I after your command. This will filter and search for a statement or text your looking for without any loops.
"C:\Program Files (x86)\F5 VPN\f5fpc.exe" -info | FIND /I "logged out">Nul && (Echo.logged out) || (Echo.session established)
To use the setup, simply put your command in the front (Before the pipe) and use the find /I "" to search for that within the output. Please keep in mind that >Nul will silence the command from being shown on console, which is great for this use.

Start Excel file from Windows batch script in safemode, use default file association

Question Summary:
Can I start Excel file Installer.xlsm from Windows batch script in safemode, without providing EXCEL.EXE installation path?
Details
I have a windows batch script which downloads the latest versions of a family of Excel Add-ins from a remote server, places them in a directory (C:\appname\AddIns) and calls the Excel file Installer.xlsm.
Upon loading, Installer.xlsm executes a VBA macro, which uninstalls older versions of the add-ins and installs their newer version.
Currently I start Installer.xlsm using the command:
start "Launching installer file" /wait "<Path to file>\Installer.xlsm"
What's great about it is that it uses Windows' file association to open Excel, and I don't have to provide the EXCEL.EXE installation path (multiple users with different machine images and MS Office versions).
Now I'd like to load Installer.xlsm in safemode, to make sure that no add-ins are loaded and no other code is run while Installer.xlsm tries to work with the add-ins.
I know I can use "<PathToExcel>excel" /safemode "<PathToXls>Installer.xlsm" as described in this answer, but this method doesn't use Windows' file association and requires that I provide a path.
We have users with various machine images, using different versions of MS Office, so I do not want to get into hardcoding all possible Excel installation locations.
Can I do something of the following form:
start "Launching installer file" /wait "<Path to file>\Installer.xlsm /safemode"
I tried different possible combinations without success. How would you do it?
First I suggest to read the Microsoft documentation page Application Registration. It explains how the installer of an application or an application suite like Microsoft Office should register the installed application(s) so that the executable(s) of the application(s) can be found by other applications.
Recommended is creating under registry key
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
a subkey with name of the executable file like excel.exe with default string value being name of the executable with full path and optionally adding one more string value with name Path containing just the path to the executable. The Path string can but most not exist and it can but must not end with a backslash.
The command START uses also this key to find an application as explained in answer on Where is “START” searching for executables?
The installers of the various versions of Microsoft Office register excel.exe key under this key too.
So the easiest method on Windows Vista and later Windows versions to get installation location of Microsoft Excel is:
#echo off
for /F "skip=1 tokens=2*" %%A in ('%SystemRoot%\System32\reg.exe QUERY "HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths\excel.exe" /ve 2^>nul') do set "ExcelApp=%%~B"
echo ExcelApp=%ExcelApp%
pause
But on Windows XP the output of reg.exe is different and requires for that reason this batch code:
#echo off
for /F "skip=3 tokens=3*" %%A in ('%SystemRoot%\System32\reg.exe QUERY "HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths\excel.exe" /ve 2^>nul') do set "ExcelApp=%%~B"
echo ExcelApp=%ExcelApp%
pause
The different outputs are explained in answer on Read words separated by space & string value also contains space in a batch script in batch code written to get string value of a default string of a registry key containing spaces.
And it is good coding practice to add extra code which handles an error case like registry key does not exist at all because Microsoft Excel is not installed at all.
But is it possible with batch code to do what command START respectively the Windows shell function ShellExecuteEx does on using in a command prompt window the command line?
start "Launching installer file" "C:\Path to file\Installer.xlsm"
Yes, it is possible as the commented batch code below demonstrates.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem First query default string value of HKEY_CLASSES_ROOT\.xlsm from registry.
call :GetDefaultRegValue "HKCR\.xlsm"
rem Is there no key HKEY_CLASSES_ROOT\.xlsm or was the default string empty?
if not defined RegValue goto GetFromAppPaths
SET RegValue
rem Get the shell command line used for opening a *.xlsm file.
call :GetDefaultRegValue "HKCR\%RegValue%\shell\open\command"
rem Could the command line not read successfully from Windows registry?
if not defined RegValue goto GetFromAppPaths
SET RegValue
rem The command line contains as first string usually enclosed in double
rem quotes EXCEL.EXE with full path enclosed in double quotes. And there
rem can be even more arguments on the command line which are not needed
rem here. The command line below is used to get just first string of
rem the command line which should be EXCEL.EXE with full path.
for %%I in (%RegValue%) do set "RegValue=%%~I" & goto CheckExcelExistence
rem It is not good when both registry queries above fail. This means
rem either Microsoft Excel is not installed at all or a version of
rem Excel is installed which does not support *.xlsm files like Excel
rem of MS Office 2003, MS Office 2000 or MS Office 97.
rem However, perhaps just *.xlsm is not correct registered and therefore
rem get full path to excel.exe from application registration key.
:GetFromAppPaths
call :GetDefaultRegValue "HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths\excel.exe"
if defined RegValue goto CheckExcelExistence
echo Failed to determine installation location of Microsoft Excel.
echo/
endlocal
pause
goto :EOF
:CheckExcelExistence
SET RegValue
rem Remove surrounding double quotes if the Excel executable file name
rem read from Windows registry is still enclosed in double quotes.
set "RegValue=%RegValue:"=%"
if exist "%RegValue%" goto :RunInstall
echo Registered "%RegValue%" does not exist.
echo/
endlocal
pause
goto :EOF
:RunInstall
SET RegValue
ECHO start "Launching installer file" /wait "%RegValue%" "%~dp0Installer.xlsm" /safemode
endlocal
goto :EOF
rem This subroutine queries from Windows registry the default string value of
rem the key passed to the subroutine as first and only parameter and assigns
rem this value to environment variable RegValue. Environment variable RegValue
rem is deleted and therefore is not defined after subroutine exits on failure
rem to get the registry value or when the default value is an empty string.
rem This subroutine works for Windows XP and all later versions of Windows.
:GetDefaultRegValue
set "TypeToken=2"
:Reg3Run
for /F "skip=1 tokens=%TypeToken%*" %%A in ('%SystemRoot%\System32\reg.exe QUERY "%~1" /ve 2^>nul') do (
if "%%A" == "REG_SZ" (
if not "%%~B" == "" (
set "RegValue=%%B"
goto :EOF
)
) else if "%%A" == "NAME>" (
set "TypeToken=3"
goto Reg3Run
)
)
set "RegValue="
goto :EOF
This batch code is just a demonstration. It does not start Excel when really found. Instead it just outputs the command line which would start Excel because of ECHO left of start ... in block below label RunInstall.
Further this batch code contains 4 lines with just SET RegValue. Those 4 lines output just the string value queried successfully from Windows registry and stored in environment variable RegValue. Those 4 commands help to understand what happens on execution of the batch file. Those four command lines should be deleted finally from batch file and also the single ECHO written in upper case.
Note: It is quite easy to test what happens if an expected registry key does not exist or its default value is an empty string. Just insert a single character like # before last double quote on a line starting with call :GetDefaultRegValue and the modified registry key is not found anymore.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
echo /?
endlocal /?
for /?
goto /?
if /?
pause /?
reg /?
reg query /?
rem /?
setlocal /?
start /?
Read also the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded reg.exe command line with using a separate command process started in background.

Batch file fails when solution is built by Jenkis, but works when solution is built via command line

The problem
I have a batch file the is being called from a Pre-Build event.
When the solution is being built by Jenkins it fails.
When the solution is being built from MSBuild or visual studio in command line It works fine.
My question is, what could cause such a behaviour?
Details
In my solution (.Net 4.5 and C++ projects), I have a batch file that is called from one of the project's Pre-Build events.
It works fine, except when I am trying to build the solution via Jenkins (CI Server).
The error is :
The command ""C:\Jenkins\apps\jenkins\jenkins_home\jobs\Builld_SMW2\workspace\Autosync\CopySymAlignFiles.bat" "C:\Jenkins\apps\jenkins\jenkins_home\jobs\Builld_SMW2\workspace\" "C:\Jenkins\apps\jenkins\jenkins_home\jobs\Builld_SMW2\workspace\Autosync\" "Debug"" exited with code 1.
from the error report, I copied the command that was used for attempting to build the solution:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe /p:Platform=x86 /p:configuration=Debug /t:Rebuild /verbosity:quiet /p:WarningLevel=0 /p:Platform=x86 /p:configuration=Debug /t:Rebuild /verbosity:quiet /p:WarningLevel=0 ..\SMW2_Analysis.sln
(I am aware that the arguments are being passed twice, I have no Idea why jenkins does that, but this is not the issue...)
If I run this command from command line, the batch file works fine once the build event is triggered.
The content of CopySymAlignFiles.bat is:
Echo off
set solutionDir=%1
set projectDir=%2
set configuration=%3
REM Removing quotes
set solutionDir=%solutionDir:"=%
set projectDir=%projectDir:"=%
set configuration=%configuration:"=%
REM Does strings have a trailing slash? if so remove it
IF %solutionDir:~-1%==\ SET solutionDir=%solutionDir:~0,-1%
IF %projectDir:~-1%==\ SET projectDir=%projectDir:~0,-1%
IF %configuration:~-1%==\ SET configuration=%configuration:~0,-1%
REM This is just for easier debugging
Echo Solution Directory is: "%solutionDir%"
Echo Project Directory is: "%projectDir%"
Echo Configuration directory is: "%configuration%"
Echo Current Directory is: "%CD%"
Echo The batch file is executed at "%~dp0"
REM Copying sym_align files
copy /Y "%solutionDir%\SymAlignGlue\sym_align.dll" "%projectDir%"
copy /Y "%solutionDir%\SymAlignGlue\sym_align.ctf" "%projectDir%"
set isPV=%configuration%=="PV Release"
IF %isPV% copy /Y "%solutionDir%\SymAlignGlue\Release\SymAlignGlue.dll" "%projectDir%"
IF NOT %isPV% copy /Y "%solutionDir%\SymAlignGlue\%configuration%\SymAlignGlue.dll" "%projectDir%"
REM The result...
IF %ERRORLEVEL% EQU 0 (
REM Success
Echo Copied SymAlign files.
exit /b 0
)
IF NOT %ERRORLEVEL% EQU 0 (
REM Error
Echo An error was found while Copied SymAlign files. Error level was %ERRORLEVEL%
exit /b %ERRORLEVEL%
)
Some additional Information:
I am running Jenkins as a service and I have the service logon as An Administrator.
Does Anyone have an Idea how can this happen?
At the end, it seems that the issue was that there was a duplicate workspace folder.
1 was updated, and the other 1 was built, resulting the tested workspace did not get latest updates.
according to this link this was due to the way jenkins behaves with multiple configurations.

nmake: can a batch file run as part of a make command block, affect the environment of the nmake.exe process?

I think in nmake if I do this:
example :
set value=77
echo %%value%%
The result will display 77 on the console.
Is there a way for me to invoke a .cmd or .bat file that will affect the environment of the nmake.exe process? Suppose I put the statement set value=77 in a file called "setvalue.cmd". Then change the makefile to this:
example :
setvalue
echo %%value%%
I get:
%value%
Alternatively, if there's a way to set a macro within a command block, that would also work. Or, a way to set the value of a macro from a batch file, even outside a command block.
You can create an nmake snippet during makefile pre-processing, and read that in. Assuming batch.cmd outputs valid nmake syntax, then
!if [batch.cmd >makefile.auto]
!error *** Could not create makefile.auto
!endif
!include makefile.auto
You should ensure batch.cmd sets %errorlevel% appropriately (e.g., exit /b 22).
makefile.auto can contain anything, but you would probably want stuff like value=77. A couple of points:
Dereference value using nmake syntax ($(value))
You can pass parameters to batch.cmd if necessary ([batch.cmd $(OBJECTS) >makefile.auto])
No, I don't think so.

Resources