How to catch the exit code of a CMDEXEC SQL Server

2019-07-05 03:09发布

The following SQL Server job always exits with return code 0 indicating success, when in fact it does not do its job, i.e. it does not delete "test.txt". How can I catch the actual exit code (something like %ERRORLEVEL%, or a 'permission denied'-like message, or any meaningful response indicating success or failure of @command at msdb.dbo.sp_add_jobstep)?

Remarks:

  • {DBname} is the name of the database I am the owner of
  • {proxyName} is the name of the SQL Server Agent Proxy (that is active to the 'Operating system (CmdExec)' subsystem) belonging to a credential that maps to a Windows domain login in SQL Server that has full control to {folderUNC}
  • {folderUNC} is the full UNC path to the folder where "test.txt" is

A few details that might be useful:

  • Server: Microsoft SQL Server Enterprise Edition (64-bit) version 9.00.4060.00
  • OS: Microsoft Windows NT 5.2 (3790)
  • I am not a sysadmin, but only the owner of database {DBname}

CODE:

USE {DBname}
GO

DECLARE @returnCode AS INT
DECLARE @jobName NVARCHAR(128)
DECLARE @jobStep1Name SYSNAME

SET @jobName = 'CMDEXEC Test Job' 
SET @jobStep1Name = 'CMDEXEC Test Job Step 1'

EXEC @returnCode = msdb.dbo.sp_add_job 
    @job_name = @jobName,
    @enabled = 1,
    @start_step_id = 1,
    @notify_level_eventlog = 2,
    @delete_level = 0;

 IF (@@ERROR <> 0 OR @returnCode <> 0)
     PRINT N'Error @ sp_add_job. @@ERROR = ' + CONVERT(VARCHAR(10), @@ERROR) + 
          N' @returnCode = ' + CONVERT(VARCHAR(10), @returnCode

EXEC @returnCode = msdb.dbo.sp_add_jobstep
    @job_name = @jobName, 
    @step_id = 1, 
    @step_name = @jobStep1Name, 
    @subsystem = 'CMDEXEC', 
    @command = 'DEL {folderUNC}\test.txt',
    @cmdexec_success_code = 0,
    @on_success_action = 1,
    @on_fail_action = 2,
    @proxy_name = '{proxyName}';

 IF (@@ERROR <> 0 OR @returnCode <> 0)
     PRINT N'Error @ sp_add_job. @@ERROR = ' + CONVERT(VARCHAR(10), @@ERROR) + 
          N' @returnCode = ' + CONVERT(VARCHAR(10), @returnCode

EXEC @returnCode = msdb.dbo.sp_add_jobserver 
    @job_name = @jobName;

 IF (@@ERROR <> 0 OR @returnCode <> 0)
     PRINT N'Error @ sp_add_job. @@ERROR = ' + CONVERT(VARCHAR(10), @@ERROR) + 
          N' @returnCode = ' + CONVERT(VARCHAR(10), @returnCode

EXEC @returnCode = msdb.dbo.sp_start_job 
    @job_name = @jobName,
    @step_name = @jobStep1Name;

 IF (@@ERROR <> 0 OR @returnCode <> 0)
     PRINT N'Error @ sp_add_job. @@ERROR = ' + CONVERT(VARCHAR(10), @@ERROR) + 
          N' @returnCode = ' + CONVERT(VARCHAR(10), @returnCode

EXEC @returnCode = msdb.dbo.sp_delete_job 
    @job_name = @jobName;

 IF (@@ERROR <> 0 OR @returnCode <> 0)
     PRINT N'Error @ sp_add_job. @@ERROR = ' + CONVERT(VARCHAR(10), @@ERROR) + 
          N' @returnCode = ' + CONVERT(VARCHAR(10), @returnCode

1条回答
来,给爷笑一个
2楼-- · 2019-07-05 03:36

The trouble seems to be that del does not set the errorlevel when it fails. There are several ways to 'work around' this, but personally I'd go for either writing my own delete.exe, or via a .bat file.

Example : (delete.bat)

@echo off

del "%1"
if exist "%1" GOTO FAIL
EXIT /B 0

:FAIL
ECHO "File still there ! (%1)"
EXIT /B 1

And you can call it like this (@command):

delete.bat c:\test.txt

it will return as failed when the file is still there after supposedly being deleted.

查看更多
登录 后发表回答