I'm using powershell script to run a few *.sql file. I can get the output value by using the script below..
$return_value = sqlcmd -S ServerName -i "MyAwesome.sql" -v parameter1="par1"
The problem is that I will have to extract out the output text to determine whether there is any error in SQL file or not..
Is there any best practice to handle the exceptions in powershell file and *.sql file?
Do I have to catch the error in each and every SQL files to produce the pre-defined output?
Might not be an option for you, but the Invoke-SqlCmd cmdlet has a parameter called "-ErrorVariable" to trap error messages.
You can use sqlcmd's exit code to determine whether there was an error or not.
$output = sqlcmd -S ServerName -i "MyAwesome.sql" -v parameter1="par1"
if ($LASTEXITCODE -ne 0) {
Write-Error $output
}
If the exit code is not 0 you will usually find the error message either in stdout or stderr. You can put both in the output variable like this:
$output = sqlcmd -S ServerName -i "MyAwesome.sql" -v parameter1="par1" 2>&1
If there was anything in stderr it will be combined with whatever is in stdout.
In your SQL script you will also want to implement best practice error handling techniques such as using try/catch constructs and using transactions where warranted.
http://msdn.microsoft.com/en-us/library/ms179296.aspx
If you catch an exception in your SQL script print the error message and set the return code so you can handle the error in PowerShell.
Related
I have written following commands:
$env:Path += "C:\Program Files (x86)\Java\jre6\bin"
& "C:\Program Files (x86)\Java\jre6\bin\java" -version
I am trying to store output of second line in a variable but unable to do so. Also tried to export output in some file, that also did not work. Please assist.
java.exe might be writing the version output to stderr.
You can merge the error stream (2) into the standard output stream (1) with a stream redirection operator (>&) like so:
& "C:\program files(x86)\java\jre6\bin\java" -version 2>&1
PowerShell will try to be helpful and wrap the error output in an ErrorRecord. Since we just need the plaintext output, grab the Message value from the Exception wrapped by it:
$jversion = (& "C:\program files(x86)\java\jre6\bin\java" -version 2>&1).Exception.Message
$jversion will now contain one or more strings as output by java.exe
See the about_Redirection help file for more information
My command line is this (powershell):
$7z ="`"c:\Program Files\7-Zip\7z.exe`""
&$7z a -r -ttar -bd -so . | &$7z a -r -txz -bd $archive -si
The produced archive file indeed contains a tar file, but that tar file is corrupt.
Note, that breaking the pipe into two commands works correctly:
&$7z a -r -ttar -bd ${archive}.tmp .
&$7z a -r -txz -bd $archive ${archive}.tmp
The produced archive is perfectly valid.
So, what is wrong with my pipeline?
(I am using Powershell)
Nothing is wrong with your pipeline it is the way that the pipeline works that's causing the error.
PowerShell pipe works in an asynchronous way. Meaning that output of the first command is available to the second command immediately one object at the time even if the first one has not finished executing, See here.
Both Unix and PowerShell pipes operate in the same way. The reason why you might be seeing a difference from Unix to PowerShell is the way in which they go about it is different.
Unix passes Strings between the commands. Where as a Powershell pipe will pass full-fledged .net object between commands. This difference in the data type being past between command will be why it works on unix and not in PowerShell. If 7z.exe can not huddle these .net objects correctly the files will be come corrupt, See here.
Try adding | %{ "$_" } in between the pipes like
&$7z a -r -ttar -bd -so . | %{ "$_" } | &$7z a -r -txz -bd $archive -si
The point is that the second call to 7z expects unmodified data on STDIN, but PowerShell is converting the output from the first call to 7z to (multiple) (string) objects. % is an alias for foreach-object, so what the additional command does is to loop over each object and convert it to a plain string before passing it on to the second call to 7z.
Edit: Reading through PowerShell’s Object Pipeline Corrupts Piped Binary Data it looks to me now as if my suggestion would not work, and there's also no way to fix it. Well, other than wrapping the whole pipeline into a cmd /c "..." call to make cmd and not PowerShell handle the pipeline.
Edit2: I also was trying this solution from the PowerShell Cookbook, but it was very slow.
In the end, I created a .cmd script with the 7z pipes that I'm calling from my PowerShell script.
I've searched everywhere, but I can't seem to find a solution for my issue. Probably, it is code related.
I'm trying to catch the exit code from a novell program called DXCMD, to check whether certain "drivers" are running. This is no problem in bash, but I need to write a more complex perl script (easier working with arrays for example).
This is the code:
#Fill the driverarray with the results from ldapsearch (in ldap syntax)
#driverarray =`ldapsearch -x -Z -D "$username" -w "$password" -b "$IDM" -s sub "ObjectClass=DirXML-Driver" dn | grep ^dn:* | sed 's/^....//' | sed 's/cn=//g;s/dc=//g;s/ou=//;s/,/./g'`;
#iterate through drivers and get the exit code:
foreach $driverdn (#driverarray)
{
my $cmd = `/opt/novell/eDirectory/bin/dxcmd -user $username -password $password -getstate "$driverdn"`;
my $driverstatus = $?>>8;
}
I've come this far; the rest of the code is written (getting the states).
But the $?>>8 code always returns 60. When I copy the command directly into the shell and echo the $?, the return code is always 2 (which means the driver is running fine). In bash, the code also works (but without the >>8, obviously).
I've looked into the error code 60, but I cannot find anything, so I think it is due to my code.
How can I rectify this error? Or how can I track the error? Anyone? :)
Wrong value passed to -getstate. You didn't remove the newline. You're missing
chomp(#driverarray);
I have a command line executable that I need to call repeatedly in PowerShell with different options.
On every occassion I wish to check that the exit code is 0.
Is there a way for wrapping the call and the parameters as a function?
& bob.bat -b
... error handling
& bob.bat -a -m "a path"
... error handling
Goes to something like:
function callBob ($paramList)
{
& bob.bat $paramList
... error handling
}
callBob -b
callBob -a -m "a path"
etc...
Unfortunately the above code doesn't appear to handle multiple parameters - I can't get things like the second to work, as callBob only takes a single parameter so I end up having to pass in a single string which seems to get quoted on being passed to & bob.bat.
You can do something like this:
function callBob{
bob.bat $args
}
callBob -b
Also, try this wrapper if you want ( from PSAKE):
function Exec
{
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)][scriptblock]$cmd,
[Parameter(Position=1,Mandatory=0)][string]$errorMessage = ($msgs.error_bad_command -f $cmd)
)
& $cmd
if ($lastexitcode -ne 0) {
throw ("Exec: " + $errorMessage)
}
}
You can user $args to access parameters:
function callBob
{
Write-Host "Length: $($args.Length)"
Write-Host "arg0: $($args[0])"
Write-Host "arg1: $($args[1])"
Write-Host "arg2: $($args[2])"
}
callBob -b
callBob -a -m "a path"
There are few ways to do it.
1)Create a batch file and call the powershell script from it.
2)Create an exe and then invoke the powershell from it. You can get the exit code in the WPF application and then verify it.
It depends on the complexity and need of your application. I have used a WPF application to wrap the powershell, because we did not want others to run the script by going to powershell and executing. And also we provided a security login in WPF application.
Let me know if you need help if you decided to use WPF Applicaiton.
I am connecting to Oracle/DB2 databases through shell script/ Perl program. Databases that i am connecting will need password change every 60 days. This is according to our security policy and cannot be changed. But this is creating problem when connecting to Databases through shell script or perl program. To connect to oracle DB we use below through shell script:
sqlplus -s ${USER_NAME}/${PASSWD}#${DATABASE_NAME} <<EOF > $SQL_LOG/SITE_SQL.log
set echo off
set trimspool on
set pages 0
set linesize 1500
set feedback off
set head off
spool ${ETL_DIR}/SITE.txt
select LTRIM(RTRIM(COLUMN1))||'|'||LTRIM(RTRIM(COLUMN2)) from TABLE where COLUMN2 IN (${SITES});
exit
EOF
grep -i 'error' $SQL_LOG/SITE_SQL.log
if [ $? -ne 0 ]
then
echo "\n\n---------------------------->>`date`extraction successful\n\n---------------------------->>" >> $log
else
echo "\n\n---------------------------->>`date` Error with extraction from Table\n\n---------------------------->>" >> $log
exit -5
fi
But SITE_SQL.log which holds the log for database connectivity part is getting below error message in it.
ERROR:
ORA-28002: the password will expire within 13 days
which is making scripts to fail. but connecting happens to Database and we get required data in spool file. When script checks for error in log file SITE_SQL.log its failing. I dont want to change the error handling part but to suppress this message to be displayed/logged into logfile, so that script will not see this error message in logfile.
Also we have got a perl script which is facing same problem.Below is the code used.
my $l_Var_SQL_Statement="Select to_date('$Var_Data_Date_1','YYYY-MM-DD')-max(load_date) from TABLE where LOAD_STATUS='Success'";
$RetVal=SubExecuteSQL($Var_REP_TMP,$Var_USER_DB,$Var_USER_DBUSER,$Var_USER_DBPASSWORD,$l_Var_SQL_Statement);
if($RetVal eq "ERROR") {
$system_date=`date`;
chomp($system_date);
$Message="$system_date:Error Executing Query :$l_Var_SQL_Statement\n$system_date:Database Details:DB=$Var_USER_DB,Use
r ID=$Var_USER_DBUSER, Password= $Var_USER_DBPASSWORD for $my_filename Repository";
SubWriteLogMsg("$Var_REP_LOG","$Var_REP_LOGFILE","$Message");
$Message="Error Executing Query :$l_Var_SQL_Statement. Check log file for connection details.";
SubWriteMailMsg("$Var_INFA_MAILFOLDER","$Var_INFA_MAILFILE","$Message");
SubLogLoadAbort("$Var_REP_LOG","$Var_REP_LOGFILE","$Var_INFA_MAILFOLDER","$Var_INFA_MAILFILE");
exit -1;
}
Here since we are getting the password expiry alert error message SubExecuteSQL function is returning "ERROR" as return value which is making perl script to fail.
DBA's are not agreeing to set password does not expire option as its against security policy. Password is set to change every 60 days. so this error message will start popuping up and causing failure.
Please let me know how can i suppress this error message from getting/ logging into logfile.
Thanks in advance
Before your redirection to the log file, put a grep command in a pipe such as:
| grep -v '^\s*\(ERROR:$\|ORA-\)'
ie:
sqlplus -s ${USER_NAME}/${PASSWD}#${DATABASE_NAME} <<EOF | grep -v '^\s*\(ERROR:|ORA-)' > $SQL_LOG/SITE_SQL.log
Verify first that it works with a sample file: not all versions of grep support \s. If yours does not, use [ \t] instead (yes, the space character must be there, it's not a typo).