I am using a batch file my.bat as given below:
#echo off
setlocal enabledelayedexpansion
for /F "tokens=*" %%A in (user.txt) do (
sqlplus -s -l %%A #fetch.sql
) >> output.txt
where user.txt (list of all user details for which I need expiry date. this list may have around 40-50 rows) is:
dbuser/password#database1
readuser/p#ssw0rd#database1
adminuser/Pa$$word#database2
.......
.......
.......
and fetch.sql is:
set pagesize 200
set linesize 200
select username, expiry_date from user_users;
exit;
The problem I am facing is, script my.bat captures here all the required details in output.txt along with SQL ERRORS (ORA-01017: invalid username/password; logon denied ,ORA-12154: TNS:could not resolve the connect identifier specified, ORA-28000: the account is locked ) but its getting hanged at the point whenever it encounteres below error message :
ERROR:
ORA-28001: the password has expired
Changing password for readuser
Please can you let me know how I can ignore this ERROR message too and keep my script running further ?
You can have whenever sqlerror exit failure in your SQL script, but because you only run that after a successful connection it won't catch this error.
You could instead launch SQL*Plus without logging in, using the /nolog switch, and then connect explicitly:
#echo off
setlocal enabledelayedexpansion
for /F "tokens=*" %%A in (user.txt) do (
(
echo whenever sqlerror exit failure
echo connect %%A
echo #fetch.sql
) | sqlplus -s /nolog
) >> output.txt
This also means your credentials aren't supplied on the command line; not sure about Windows so much but on other platforms that is a considerable security risk. Of course you still have them stored in a plain text file which itself isn't very secure, so that's more of a general point.
You could put your fetch.sql statements directly in the batch file if you prefer, by echoing those instead of the # start command; same effect but one less file to maintain.
Related
I have looked at many SO questions/answers and though some seem similar to my issue they do not seem to be. The answers given fix issues the questions were asking about but will not solve my issue.
I have a batch file...
#ECHO ON
ECHO Disabling the following... >> C:\App\Debug.log
ECHO - V1 >> C:\Apps\Debug.log
FOR /F "tokens=* USEBACKQ" %%F IN (`sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1'"`) DO (
Echo %%F >> C:\Apps\Debug.log
)
EXIT /B
When I run this file at the command prompt it works perfectly fine. When I run it as a scheduled task it show me the echos but nothing for the for loop as expected.
Yes I have made sure the username (using whoami) is the same for the scheduled task set up as the manual run that I do.
Yes I know the user running the script has rights to everything (file access as well as DB access) because it works fine running it from the command prompt.
Scheduled task is set to run wither user is logged on or not.
Any ideas what might be wrong or what I can try for debugging purposes?
Thanks!
sqlcmd is perhaps not enough. cmd.exe in environment of scheduled task may fail to find the executable using local PATHEXT and local PATH environment variables. The executable should be specified with full qualified file name, i.e. drive + path + name + extension. Then the batch file does not anymore depend on the environment variables PATH and PATHEXT because of all files are referenced with full qualified file name.
for executes the specified command line with starting in background one more command process with %ComSpec% /c and the specified command line appended. This means executed is following with Windows installed on drive C::
C:\Windows\System32\cmd.exe /c sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1'"
for captures everything written to handle STDOUT of started command process. The lines of captured output are processed line by line by for after started cmd.exe terminated itself. Error messages output by started cmd.exe or the commands/executables executed by Windows command processor in background to handle STDERR are redirected to handle STDERR of command process processing the batch file and printed to console. But there is no console window on running a batch file as scheduled task. So error messages cannot be seen in this case.
The for command line can be modified easily here to get also error messages written into the C:\Apps\Debug.log.
FOR /F "tokens=* USEBACKQ" %%F IN (`sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1' 2^>^&1"`) DO (
The Microsoft article Using command redirection operators explains 2>&1. The two operators > and & must be escaped with ^ to be interpreted as literal characters on Windows command processor parsing the for command line before executing finally for which executes next %ComSpec% /c with the specified command line on which 2^>^&1 is changed already to 2>&1.
Does the log file C:\App\Debug.log contain with this modification following two lines?
'sqlcmd' is not recognized as an internal or external command,
operable program or batch file.
Yes, then no executable with file name sqlcmd is found by started cmd.exe. The best solution is referencing this executable with full qualified file name. See also: What is the reason for "X is not recognized as an internal or external command, operable program or batch file"?
Otherwise sqlcmd outputs perhaps an error message which should be now also in the log file C:\App\Debug.log.
It would be also possible to use following command line to let background cmd.exe write the error messages into a separate error log file C:\App\Error.log:
FOR /F "tokens=* USEBACKQ" %%F IN (`sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1'" 2^>C:\App\Error.log`) DO (
"tokens=* usebackq" results in first deleting all leading horizontal tabs and normal spaces on non-empty lines by for, then checking if the remaining line starts with ; in which case the line is also ignored and finally assigning the captured line not starting with ; and with leading tabs/spaces removed to loop variable F for further processing.
Better would be using the options usebackq^ delims^=^ eol^= not enclosed in double quotes which requires escaping the two spaces and the two equal signs with caret character ^ to be interpreted as literal characters by cmd.exe on parsing the command line before executing for. The line splitting behavior is disabled completed with delims= because of the definition of an empty list of delimiters. And no line except an empty line is ignored anymore because of end of line character modified from default ; to no character.
Finally a space on an echo line left to redirection operator >> is also output by echo and for that reason written as trailing space into the log file. Therefore no space should be used left to > or >> on printing a line with echo redirected into a file. But care must be taken on omitting the space character left to the redirection operator. The word left to redirection operator should not be 1, 2, ..., 9 as this would result in redirecting the output to these numbered handles into the specified file instead of the character 1, 2, etc. So if unknown text should be written into a file, it is better to specify first the redirection operator > or >> and the full qualified file name and next the echo command with the text to output. See also: Why does ECHO command print some extra trailing space into the file?
The three command lines with echo would be for this batch file:
ECHO Disabling the following...>> C:\App\Debug.log
ECHO - V1>> C:\Apps\Debug.log
>>C:\Apps\Debug.log ECHO %%F
following... is safe for being correct written into the file as also V1. %%F could be just 1 or a string ending with a space and a single digit and so it is better to specify the redirection first on the last echo command line to get finally executed by cmd.exe the command line ECHO %%F 1>>C:\Apps\Debug.log.
I want to develop a batch script which will execute each .sql SQL scripts present in the folder where the batch file is placed to and record the logs to a filename_sqloutput.txt file .
The condition is : If any script gives any error message like column name incorrect , or table name etc. The script execution should stop immediately and further scripts should not executed .
I tried with the below code: But its not working as even if the script is giving errors in the output file . The script execution is not stopping ..
Need your help !!!
#echo off
for /f %%a IN ('dir /b *.sql') do (call sqlcmd -S AMRVSP000000318 -i %%a -o"%%~na_sqloutput.txt"
findstr "Msg" %%~na_sqloutput.txt >nul & if %errorlevel% EQU 1 (exit) else (echo Successfully executed %%~na_sqloutput.txt)
)
pause
FINDSTR will set %ERRORLEVEL% as follows:
0 (False) a match is found in at least one line of at least one file.
1 (True) if a match is not found in any line of any file, (or if the file is not found at all).
2 Wrong syntax
An invalid switch will only print an error message in error stream.
Moreover, follow EnableDelayedExpansion article and rewrite the script to more readable structure:
#echo off
SETLOCAL EnableExtensions EnableDelayedExpansion
for /f %%a IN ('dir /b *.sql') do (
call sqlcmd -S AMRVSP000000318 -i %%a -o"%%~na_sqloutput.txt"
findstr "Msg" "%%~na_sqloutput.txt" 2>NUL
if !errorlevel! EQU 0 (
echo error occured %%~na_sqloutput.txt
rem pause to see error
pause
exit /B
) else (
echo Successfully executed %%~na_sqloutput.txt
)
)
pause
.... if errorlevel 1 (exit...
%errorlevel% is the initial value of errorlevel as it stands when the for is encountered.
See endless SO articles about using delayed expansion as another solution.
This syntax means "if the current errorlevel is 1 or greater dothis else dothat"
How to run a command in vmware using vmrun, command is (echo %PROGRAMFILES%) on the guest machine..
and the guest machine should return a value of the command result... how to do this??? please suggest
I needed to do something similar and found this unanswered question. Here's my solution.
#ECHO OFF
REM Set up abbreviations that we'll be using a lot.
SET VMRUN="C:\Program Files (x86)\VMware\VMware VIX\vmrun.exe" -T ws -gu Administrator -gp password
SET VMX="C:\Users\whoever\Documents\Virtual Machines\Windows\Windows.vmx"
SET GUEST_COMSPEC="C:\WINDOWS\system32\cmd.exe"
REM Tried to do this in one line, but couldn't figure out the quoting.
%VMRUN% CreateTempfileInGuest %VMX% >%TEMP%\GuestTmp.txt || GOTO :CantCreate
FOR /F "delims=;" %%F IN ( %TEMP%\GuestTmp.txt ) DO SET GTEMP=%%F
REM The batch file is a one-liner that echos the variable into a file.
REM It could be generated dynamically and copied to the guest
REM but I didn't want to complicate things any further.
%VMRUN% runProgramInGuest %VMX% %GUEST_COMSPEC% "/c C:\echo-ProgramFiles.bat %GTEMP%"
%VMRUN% CopyFileFromGuestToHost %VMX% %GTEMP% %TEMP%\GuestOut.txt
%VMRUN% DeleteFileInGuest %VMX% %GTEMP%
REM Do something with the result and delete the temp files.
TYPE %TEMP%\GuestOut.txt
DEL %TEMP%\GuestOut.txt %TEMP%\GuestTmp.txt
GOTO :EOF
:CantCreate
REM Provide details on any problems.
TYPE %TEMP%\GuestTmp.txt 1>&2
DEL %TEMP%\GuestTmp.txt
EXIT 100
And here's the batch file on the guest host. As you can see, it's pretty simple. I couldn't get redirection to work in runProgramInGuest (probably didn't experiment enough)
so I just pass the file as a command line argument.
#echo %PROGRAMFILES% >%1
Have a look at the vmrun commands here. You need the Guest OS Command runScriptInGuest.
I have not checked the command , but it should look like this. Please verify it.
vmrun -T server -h https://xps:8333/sdk -u user -p mypassword -gu administrator -gp guestpaswd
runScriptInGuest "[Vol1] win2008-1/win2008-1.vmx" "echo %PROGRAMFILES%"
I had to use runProgramInGuest
capture the output to a file
copy the file back to my host and use it
Thats the soln I used.
I am trying to install an application and a group of services using PSTools, but I want to take into account that the computer I am trying to connect to may be turned off or on a different network, which is not reachable from the internal network.
Basically if the machine is not able to be accessed through the admin share, this is the message that I am getting:
Couldn't access MachineName:
The network path was not found.
Make sure that the default admin$ share is enabled on MachineName.
This is the syntax I am using to try to capture the "Error Message" and then report back that if installation was successful or not (depending on if it can contact the machine)
#echo off
set /p name=What is the machine name?:
psexec.exe \\%name% -u *useraccount* -p *password* \\ServerName\installation.bat
FOR /F "tokens=*" %%A IN ('COMMAND ^| FIND "Couldn't access"') DO SET Error=%%A
If "%Error%"=="Couldn't access"
ECHO Installation Failed.
Else
ECHO Installtion complete.
Pause
exit
Currently it hangs right at the point it's defining the Error Variable. Can't quite figure out what I am going wrong here.
'COMMAND ^| FIND "Couldn't access"' opens a command shell, which is why it hangs. It will not proceed until that shell is exited.
You will need to look at redirecting the error messages to another file. 2>Errors.txt on the psexec line will give you a file to search in the next line.
this will make the batch file look something like this:
#echo off
set /p name=What is the machine name?:
psexec.exe \\\%name% ... \\\ServerName\installation.bat 1>Error.txt 2>&1
for /f "tokens=*" %%A in ('FIND /i error.txt "Couldn't Access"') do SET Error=%%A
If not x%ERROR:Couldn=%==x%ERROR% (
ECHO Installation Failed.
) Else (
ECHO Installtion complete.
)
Pause
exit
(Also, notice the use of brackets to make a multi line IF)
the check for if will see if Couldn is part of the string, as a direct comparison will not work, as you would have to check against the whole string including the machine name
I have this simple little batch file program that I wrote but it fails if I enter a database name that contains a "-" character. Im not exactly sure why but I wish I could figure out a way around this?
:: open DB batch file
#echo off
:: starts Sql Server Management Studio Express 2005
:: and opens it to a specific database with query
:: window already open
cls
:SHOWDBNAMES
echo Database names detected on this system:
echo.
"%PROGRAMFILES%\Microsoft SQL Server\90\Tools\Binn\OSQL.EXE" -h-1 -S . -E -Q "SELECT CAST(name AS VARCHAR(30)) FROM sysdatabases"
#echo.
set DBNAME=
set /P DBNAME=What database name would you like to open (choose from list)?
if "%DBNAME%" == "" (
echo.
echo I don't recognize your selection. Try again.
goto SELECTDB
)
:SHOWTABLES
cls
echo.
echo Tables that you can query from %DBNAME% are:
echo.
"%PROGRAMFILES%\Microsoft SQL Server\90\Tools\Binn\OSQL.EXE" -h-1 -S . -E -Q "use [%DBNAME%];SELECT CAST(name AS VARCHAR(30)) FROM sys.Tables ORDER BY name"
echo.
:RUNIT
sqlwb.exe -nosplash -S . -E -d %DBNAME%
pause
:EOF
Try enclosing the database name in square brackets:
[database-name]
EDIT
The following should work - you need to quote the database name in the call to sqlwb.exe:
:SHOWTABLES
cls
echo.
echo Tables that you can query from %DBNAME% are:
echo.
"%PROGRAMFILES%\Microsoft SQL Server\90\Tools\Binn\OSQL.EXE" -h-1 -S . -E -Q "SELECT CAST(name AS VARCHAR(30)) FROM [%DBNAME%].sys.Tables ORDER BY name"
echo.
:RUNIT
sqlwb.exe -nosplash -S . -E -d "%DBNAME%"
I've got to ask though - what's the point of this script? The built-in SSMS object explorer gives you all this information for free.
Also, your script doesn't take account of SQL server instances other than the default - SQL Server Express is installed as <machine_name>\SQLEXPRESS by default.
Why don't you just try an underscore (_)?
Is it failing on the sqlwb.exe line when the dash is the first letter in the database name? If so, your problem is that sqlwb is misinterpreting the database name as a command line option. There should be some way to make it not do that; check the manual.