We have some SqlJobs that we run in our regression tests. To automate this we need something that can start the job and wait for it to finish.
Based on this post we know we need to poll the sysjobhistory table. Wrapping it in a powershell module lets us use it in all our regression tests. The code is listed below.
function Start-SqlJobAndWait {
param (
[string] $servername,
[string] $jobname
)
# connection to database
$connectionstring = "Data Source=$servername;Initial Catalog=msdb;Integrated Security=TRUE;"
$conn = New-Object System.Data.SqlClient.SqlConnection $connectionstring
$conn.Open()
# create temp stored procedure to start and wait for the job
$cmd = $conn.CreateCommand()
$cmd.CommandText = Get-StoredProcedureDropScript
$cmd.ExecuteNonQuery()
$cmd.CommandText = Get-StoredProcedureCreateScript
$cmd.ExecuteNonQuery()
$cmd.Dispose()
# call temp stored procedure
$cmd = $conn.CreateCommand()
$cmd.CommandTimeout = 600 # 10 minutes
$cmd.CommandText = "EXEC #usp_Start_And_Wait_For_Job N'$jobname'"
$cmd.ExecuteNonQuery()
$cmd.Dispose()
# connection close removes the temp stored procedure
$conn.Close()
$conn.Dispose()
}
function Get-StoredProcedureDropScript {
"
IF object_id(N'tempdb..#usp_Start_And_Wait_For_Job') is not null
DROP PROCEDURE #usp_Start_And_Wait_For_Job
"
}
function Get-StoredProcedureCreateScript {
"
CREATE PROCEDURE #usp_Start_And_Wait_For_Job (@jobName SYSNAME)
AS
SET NOCOUNT ON
DECLARE @jobID UNIQUEIDENTIFIER, @maxID INT, @status INT, @rc INT
IF @jobName IS NULL
BEGIN
RAISERROR('Parameter @jobName have no value.', 16, 1)
RETURN -100
END
SELECT @jobID = job_id FROM msdb..sysjobs WHERE name = @jobName
IF @@ERROR <> 0
BEGIN
RAISERROR('Error when returning jobID for job %s.', 18, 1, @jobName)
RETURN -110
END
IF @jobID IS NULL
BEGIN
RAISERROR('Job %s does not exist.', 16, 1, @jobName)
RETURN -120
END
SELECT @maxID = MAX(instance_id) FROM msdb..sysjobhistory WHERE job_id = @jobID AND step_id = 0
IF @@ERROR <> 0
BEGIN
RAISERROR('Error when reading history for job %s.', 18, 1, @jobName)
RETURN -130
END
SET @maxID = COALESCE(@maxID, -1)
EXEC @rc = msdb..sp_start_job @job_name = @jobName
IF @@ERROR <> 0 OR @rc <> 0
BEGIN
RAISERROR('Job %s did not start.', 18, 1, @jobName)
RETURN -140
END
WHILE COALESCE((SELECT MAX(instance_id) FROM msdb..sysjobhistory WHERE job_id = @jobID AND step_id = 0), -1) = @maxID
WAITFOR DELAY '00:00:01'
SELECT @maxID = MAX(instance_id) FROM msdb..sysjobhistory WHERE job_id = @jobID AND step_id = 0
IF @@ERROR <> 0
BEGIN
RAISERROR('Error when reading history for job %s.', 18, 1, @jobName)
RETURN -150
END
SELECT @status = run_status FROM msdb..sysjobhistory WHERE instance_id = @maxID
IF @@ERROR <> 0
BEGIN
RAISERROR('Error when reading status for job %s.', 18, 1, @jobName)
RETURN -160
END
IF @status <> 1
BEGIN
RAISERROR('Job %s returned with an error.', 16, 1, @jobName)
RETURN -170
END
RETURN 0"
}
Export-ModuleMember -function Start-SqlJobAndWait