Weird issues using IF NOT EXIST in Windows batch file - if-statement

I have created a couple of batch files using FOR and IF statements to query remote computers. If I use short paths for the IF statement it works as expected but if the path is long it doesn't
These work:
FOR /F %%i IN (workstations.txt) DO IF NOT EXIST \\%%i\c$\catalog.dat echo Hello
--> If the catalog.dat file exists on the remote workstation it does nothing
FOR /F %%I IN (workstations.txt) DO IF EXIST \\%%i\c$\catalog.dat echo Hello
--> If the catalog.dat file exists on the remote workstation it echo's Hello
But these do not work properly:
FOR /F %%I IN (workstations.txt) DO IF NOT EXIST \\%%i\"C:\Program Files\Common Files\Symantec Shared\VirusDefs\20140521.001\catalog.dat" echo Hello
--> If the catalog.dat file exists or doesn't exist on the remote workstation it always echo's Hello
FOR /F %%I IN (workstations.txt) DO IF EXIST \\%%i\"C:\Program Files\Common Files\Symantec Shared\VirusDefs\20140521.001\catalog.dat" echo Hello
--> If the catalog.dat file exists or doesn't exist on the remote workstation it always does nothing
I have tried making the path names shorter (for example - "C:\Program Files\catalog.dat")
I have tried using environment variable for Program Files - %PROGRAMFILES%
I have tried using single quotes or no quotes around the long path but that returns "system cannot find the path specified"
The echo Hello is just a test of these batch files.
I am trying to update an older unsupported version of Symantec on XP workstations from a 2003 server and I have already updated some workstations and therefore want to check if the 20140521.001\catalog.dat exists before running the Symantec Intelligent Updater file 20140521-001-i32.exe using PsExec as it takes 15 minutes to complete and there are hundreds of workstations.
The batch file command I used to update the workstations after copying the Intelligent Updater file to their C drive is:
FOR /F %%I in (workstations.txt) DO psexec.exe \\%%i c:\20140521-001-i32.exe /q
--> Note that for all these batch file commands the batch files (.cmd), Intelligent Updater file and workstations.txt exist in the same directory.
Any help would be much appreciated!
Thanks
Oki

Here is a simple script to test your logic if the machine is up and then check the hidden file share, then sub folders
#echo off
set MyPath=\Program Files\Common Files\Symantec Shared\VirusDefs\20140521.001
rem note the && means if the first command works i.e. returns exit /b 0 run the second cmd
for %%i in (localhost1 localhost) do call :ping %%i && call :checkDirs %%i
goto :EOF
rem dos function to ping a server return 0 is it's up 1 it is not up
:ping
set server=%1
echo ping %server%
ping.exe -n 1 %server% | findstr /i Reply >NIL
if not errorlevel 1 (
echo server %server% up
exit /b 0
) else (
echo server %server% down
exit /b 1
)
goto :EOF
:checkDirs
echo check dirs %1
if exist \\%1\c$\. (echo has share) else ( echo no share \\%1\c$\.)
if exist "\\%1\c$\Program Files\." (echo has program files) else (echo no program files)
if exist "\\%1\c$\Program Files\Common Files\." (echo has Common Files) else (echo no common files)
if exist "\\%1\c$%MyPath%" (echo has MyPath) else (echo no MyPath)
goto :EOF

Related

Informatica Command Task

I asked this question on the Informatica forums, but no one knew the answer, so now I'm coming here for some help.
To my understanding, anything in a "post-session success command" field should be passed to the appropriate command interface and executed. However, when I use an IF statement, it fails. Any ideas?
"IF 1==1 echo.bob >> f:\filename.txt"
This works when I type it manually into the terminal (DOS in this case). But when I throw it into a reusable command task, I get this:
ERROR
POST-SESS
CMN_1949
Error: [Pre/Post Session Command] Process id 2996. The shell command failed with exit code 1.
PS: Using 9.5.1 Hotfix 1
I think the problem is not in how Informatica executes commands. The problem lies in how DOS return error codes, and specifically that some commands, like IF and ECHO does'nt. (The return code Informatica picks up from DOS can be seen with echo %ERRORLEVEL% in DOS, and I'll use the name DOS here for convenience even though under Windows now this is'nt strictly correct)
Run these commands in succession:
REM "cd" sets ERRORLEVEL => ERRORLEVEL is set to 0
cd c:\
echo %ERRORLEVEL%
REM "echo" does not set ERRORLEVEL => ERRORLEVEL is left unchanged
echo.bob >> c:\filename.txt
echo %ERRORLEVEL%
REM "echo" does not set ERRORLEVEL => ERRORLEVEL is left unchanged
echo.bob >> c:\thisdirdontexist\filename.txt
echo %ERRORLEVEL%
The first CD set a return code, in this case to 0.
The following ECHO (with or without the IF test) does not change the return code, thus it remains 0 even though the last ECHO fails.
If the first CD command would have returned an error;
#echo off
REM "cd" sets ERRORLEVEL => ERRORLEVEL is set to 1
cd xxxxxx
echo %ERRORLEVEL%
then all the subsequent ECHO would return 1 and Informatica would fail them both.
This said it is still strange since each post-session success command in Informatica is executed under its own cmd-shell, so the initial ERRORLEVEL for every command should allways be 0. I can't explain that and unfortunately I can't actually test this in Informatica as we run under UNIX, but I'm pretty sure this is at least part of the problem.
To get around the problem you should make sure that you set the "Fail task if any command fails" option on the property-tab. This makes Informatica use the cmd/c option and since this set a proper return code Informatica should be able to pick up the error (or success) correctly. If this still doesn't work properly try change the command yourself to:
cmd /c "IF 1==1 echo.uncle >> c:\filename.txt"

batch file to check existance of directory if not exists then use alternate directory for file copy

I am trying to write a batch file that copies an exe file from a network location to a local location. It currently works but depending on windows version (xp or win7) the user has to select the correct .bat file due to different local paths needed for the copy. (they are going to the startup folder to be ran every time user starts machine). This is the first time i've ever worked with writing batch files and am completely lost when looking at the syntax for if statements. If i could get some help figuring this out it would be great.
Here is what I currently have that works for XP:
REM #ECHO OFF
ECHO STARTING MOVEFILES
SET EXITRC=0
SET EXITMSG=EXITRC INITIALIZED
ECHO %EXITRC% -- %EXITMS
COPY "\\networkDrive\install\Individual\program\MOVEFILES.EXE" "C:\DOCUMENTS AND SETTINGS\ALL USERS\START MENU\PROGRAMS\STARTUP\"
ECHO COPIED FILES TO YOUR PC
SET EXITRC=%ERRORLEVEL%
IF NOT %EXITRC% == 0 GOTO :EXIT
SET EXITMSG=PROCESSING COMPLETE
:EXIT
ECHO STEP: %EXITMSG% RC: %EXITRC%
ECHO FINISHING MOVEFILES
PAUSE
EXIT %EXITRC%
Here is what I have for Windows 7:
#ECHO OFF
ECHO STARTING MOVEFILESWIN7
SET EXITRC=0
SET EXITMSG=EXITRC INITIALIZED
ECHO %EXITRC% -- %EXITMS
COPY "\\networkDrive\install\Individual\program\MOVEFILES.exe" "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup"
ECHO COPIED MOVEFILESWIN7 TO YOUR PC - All Users / Public Startup folder
SET EXITRC=%ERRORLEVEL%
IF NOT %EXITRC% == 0 GOTO :EXIT
SET EXITMSG=PROCESSING COMPLETE
:EXIT
ECHO STEP: %EXITMSG% RC: %EXITRC%
ECHO FINISHING MOVEFILESWIN7
PAUSE
EXIT %EXITRC%
I would like to have only one batch file that will cover both scenarios so there is no confusion to the user on which batch file to run.
You can utilise the environment variable %ALLUSERSPROFILE%.
On WinXP the default is C:\Documents and Settings\All Users
On Win7/2008 the default is C:\ProgramData
There is a table available here: http://ss64.com/nt/syntax-variables.html
I see you also copy a different file. Not sure why you do that. Maybe you could detect using a method here: https://stackoverflow.com/a/2788764/1553090 -- Otherwise perhaps you should take advantage of the %ProgramFiles% and %ProgramFiles(x86)% variables.
Just to elaborate on how you might choose to use these variables... You can test the Win7 startup folder for existence, and if it's not there just fallback to the XP (regardless of whether it exists).
set STARTUP_WIN7=%ALLUSERSPROFILE%\Microsoft\Windows\Start Menu\Programs\Startup
set STARTUP_WINXP=%ALLUSERSPROFILE%\Start Menu\Programs\Startup
if EXIST "%STARTUP_WIN7%" (
set STARTUP=%STARTUP_WIN7%
) else (
set STARTUP=%STARTUP_WINXP%
)

How to check if a service is running via batch file and stop it if it is not running?

I want a batch file to check if the service "MyServiceName" is running. If the service is running, I want the batch file to disable it and then display a message. If it isn't running, and is disabled, I want the batch file to display a message and then to exit. Thanks for the help.
sc query MyServiceName| find "RUNNING" >nul 2>&1 && echo service is runnung
sc query MyServiceName| find "RUNNING" >nul 2>&1 || echo service is not runnung
To stop service:
net stop MyServiceName
If tried to come up with a little script that makes use of the SC-command, which seems to have some limitations though (and I couldn't test it):
#echo off
setlocal enabledelayedexpansion
:: Change this to your service name
set service=MyServiceName
:: Get state of service ("RUNNING"?)
for /f "tokens=1,3 delims=: " %%a in ('sc query %service%') do (
if "%%a"=="STATE" set state=%%b
)
:: Get start type of service ("AUTO_START" or "DEMAND_START")
for /f "tokens=1,3 delims=: " %%a in ('sc qc %service%') do (
if "%%a"=="START_TYPE" set start=%%b
)
:: If running: stop, disable and print message
if "%state%"=="RUNNING" (
sc stop %service%
sc config %service% start= disabled
echo Service "%service%" was stopped and disabled.
exit /b
)
:: If not running and start-type is manual, print message
if "%start%"=="DEMAND_START" (
echo Start type of service %service% is manual.
exit /b
)
:: If start=="" assume Service was not found, ergo is disabled(?)
if "%state%"=="" (
echo Service "%service%" could not be found, it might be disabled.
exit /b
)
I don't know if this gives the behavior you wanted. It seems like SC does not list services, that are disabled. But since you don't want to do anything if it's disabled, my code simply prints a message if the service wasn't found.
However, you can hopefully use my code as a framework/toolbox for your purposes.
EDIT:
Given npocmaka's answer, you could probably change the for-sections to something like:
sc query %service%| find "RUNNING" >nul 2>&1 && set running=true
This script takes the service name as the first (and only) parameter, or you can hardcode it into the SVC_NAME assignment. The output of the sc commands is thrown away. I don't know if you actually want to see it or not.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET SVC_NAME=MyServiceName
IF NOT "%~1"=="" SET "SVC_NAME=%~1"
SET SVC_STARTUP=
FOR /F "skip=1" %%s IN ('wmic path Win32_Service where Name^="%SVC_NAME%" get StartMode') DO (
IF "!SVC_STARTUP!"=="" SET "SVC_STARTUP=%%~s"
)
CALL :"%SVC_STARTUP%" "%SVC_NAME%"
CALL :StopService "%SVC_NAME%"
GOTO :EOF
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:"Boot"
:"System"
:"Auto"
:"Manual"
#ECHO Disabling service '%~1'.
sc.exe config "%~1" start= disabled > NUL
IF NOT ERRORLEVEL 1 #ECHO Service '%~1' disabled.
EXIT /B
:"Disabled"
#ECHO Service '%~1' already disabled.
EXIT /B
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:StopService
SETLOCAL
SET SVC_STATE=
FOR /F "skip=1" %%s IN ('wmic path Win32_Service where Name^="%~1" get State') DO (
IF "!SVC_STATE!"=="" SET "SVC_STATE=%%~s"
)
CALL :"%SVC_STATE%" "%~1"
EXIT /B
:"Running"
:"Start Pending"
:"Continue Pending"
:"Pause Pending"
:"Paused"
:"Unknown"
#ECHO Stopping service '%~1'.
sc.exe stop "%~1" > NUL
IF NOT ERRORLEVEL 1 #ECHO Service '%~1' stopped.
EXIT /B
:"Stop Pending"
:"Stopped"
#ECHO Service '%~1' is already stopping/stopped.
EXIT /B

If statement in Batch file gives error

The below simple steps in the batch script is giving me errors. It says
'else' is not recognized as an internal or external command,
operable program or batch file.
) was unexpected at this time.
Can some please help?
set var_machine64 = 0
if exist "C:\Program Files (x86)" ( set var_machine64 = 1 )
if !var_machine64! == 1 (
If exist "C:\Program Files (x86)\Microsoft" (
echo Microsoft folder not available
goto End ) )
else (
If exist "C:\Program Files \Microsoft" (
echo Microsoft folder not available
goto End ) )
:End
Exit
The else has to be on the same line where you close the last block, i.e. the ):
if !var_machine64! == 1 (
If exist "C:\Program Files (x86)\Microsoft" (
echo Microsoft folder not available
goto End
)
) else (
If exist "C:\Program Files\Microsoft" (
echo Microsoft folder not available
goto End
)
)
I took the liberty of fixing indenting and a superfluous space in a folder name as well.
This fixes your immediate problem of the syntax error but won't help since the batch file won't work anyway. You cannot use any whitespace around the = in set statements because otherwise you're creating a variable that ends in a space with a value that begins with one. So:
set var_machine64=0
if exist "C:\Program Files (x86)" ( set var_machine64=1 )
will make things work nicer. Also note that to use delayed expansion you need either setlocal enabledelayedexpansion before that in your batch file or start cmd with /v:on. I just guess you're not showing the whole file (which is ok, but given the error rate in this short snippet I'd say you should double-check everything else).
Random side note: It's not nice to include exit in a batch file because, when run from an interactive session it will kill it. If you just want to exit the batch file (and not the whole command processor with it) use exit /b or goto :eof.

Windows Batch Commands - Advanced Error Suppression Issue

I'm programming a very large purpose-driven Windows command prompt batch program.
The problem is that I can't suppress the error's text. I could "cls" but that means that almost every command will cls the prompt and I don't want to force that on users. I also tried using >nul after it, and 2>nul in front of the command. The problem with 2>nul CMDOW.EXE /RUN is that then it doesn't store the error in the ERRORLEVEL environment variable.... I also can't have this error info showing up almost every time they use a command in the prompt.
My console does tons of things, including quick navigation and web-page/program/folder access. Recently I have been trying to implement a basic wrapper around the central batch program so that if you type something that is an unrecognized command, it will first check to see if the text string you input is the beginning of a folder's name within your current directory. If so, it will auto-move you into the folder. If not, it will display the usual error message.
I made it so that the input is no longer standard dos input, but a set /p command with a prompt that imitates the usual interface. I got it so it doesn't wait when typing a program name when not preceded by "start" if its in a PATH using CMDOW.
Everything functions now except I have a small issue that's a large visual nuisance. I prompt the user and store the input to an environment variable, then use CMDOW.exe /RUN to first attempt to execute the input text and see if it's an executable file (this covers paths, as well as .exes in the current directory). I then check ERRORLEVEL to see if this resulted in an error. If so, I move on to the next method.
I've also tried writing a little C++ program to execute for me, it works easily with winexec but idk how to obtain error code to confirm the process started sucessfully. If I can do that, then I can just send that result to an environment variable. CreateProcess() doesn't work without being absolute with the location. I can't just plug in the input text and have it work but it pauses until termination anyway I believe. ShellExecute() works but doesn't seem as simple as plugging it in from input... though it appears to have a ready method of obtaining the output. I might add I'm not great at C++, I learn what I need to to get by.
I'm not sure how to get around this issue. I'm also not sure if there exists some special method to bypass that error output while still gaining the knowledge that it didn't execute properly.
Here is my code:
#SETLOCAL ENABLEDELAYEDEXPANSION
#ECHO OFF
#for /L %%i in (0,0,0) do #(
set zinput=
set /p zinput=^%time%[%cd:~0,1%]^>
call :EXECUTE
set zinput=
)
:EXECUTE
IF ("%zinput%")==("") GOTO :EOF
cmdow /run "%zinput%"
set ERRCODE=%ERRORLEVEL%
IF ("%ERRCODE%")==("1") call :UNDEFINED
GOTO :EOF
:UNDEFINED
%zinput%
set ERRCODE=%ERRORLEVEL%
IF %ERRCODE%==9009 GOTO ZDIR
GOTO :EOF
:ZDIR
set zDIR=
DIR /B /AD-H|sed -n "/^%zinput%/"Ip>"%aicnspath%\etc\dump.txt"
set /p zDIR=<"%aicnspath%\etc\dump.txt"
IF NOT DEFINED zDIR GOTO UNDEFINED2
cd %zDIR%
call "%aicnspath%\etc\update.bat"
cls
echo AUTO-MOVED INTO: %CD%|tr '[a-z]' '[A-Z]'|sed "s/^/%_hc%%_bc2%/"|sed "s/$/%_bc%/"
echo -----------------------------------------
echo/
GOTO :EOF
:UNDEFINED2
cls
echo/
echo The string %_hc%%_bc2%^'%zinput%^'%_bc% is not recognized by AICNS as any internal or external command, operable program or batch file.
echo/
GOTO :EOF
Try this...
CMDOW /run "%zinput%" >nul 2>&1
You should still have access to the ERRORLEVEL after this.
I don't see any reason because 2>nul CMDOW.EXE /RUN don't return the ErrorLevel value whereas CMDOW.EXE /RUN return it, unless CMDOW.EXE was written this way; this sound very strange to me.
The Batch file below check if a command is an executable file and return these values via ErrorLevel: 0 if not found, 1 if found in current directory, and 2 if found in a directory of PATH variable. I hope you can use a modified version of this Batch file instead of CMDOW.EXE program to solve your problem.
PATHOF.BAT:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
REM CREATE A LIST OF FILE NAMES ADDING THE EXECUTABLE EXTENSIONS
SET NAMEEXT=!PATHEXT:.=%1.!
REM SEARCHES FILE NAMES IN CURRENT DIRECTORY, IF FOUND: ERRORLEVEL=1
FOR %%N IN (%NAMEEXT%) DO IF EXIST %%N ECHO %%N & EXIT /B 1
REM SEARCHES FILE NAMES IN DIRECTORIES OF PATH VARIABLE, IF FOUND: ERRORLEVEL=2
FOR %%N IN (%NAMEEXT%) DO IF NOT "%%~$PATH:N" == "" ECHO %%~$PATH:N & EXIT /B 2
REM IF FILE NOT FOUND, ERRORLEVEL=0
ECHO '%1' is not an external command or batch file located in PATH & EXIT /B 0
Please, let me know if this method worked or if you got an additional problem using it.