I'd say the easiest possible way to do this is through PowerShell and SMO. Take the following code for instance:
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") |
Out-Null
$SqlServerNames = "Server1", "Server2"
$SqlJobName = "YourJob"
foreach ($SqlServerName in $SqlServerNames) {
$SqlServer = New-Object Microsoft.SqlServer.Management.Smo.Server($SqlServerName)
$SqlServer.JobServer.Jobs[$SqlJobName].Start()
}
All this does it loop through a list of servers (explicitly stated at as string array variable, but can easily be obtained also from a SQL Server database table, a text file, etc.), connects to the current server, and then starts the job with the job named whatever you set the $SqlJobName
variable to.
It's also worth noting that the Start()
function will not wait for the job to complete before continuing code execution.
As you can see, in very few lines of PowerShell code you are able to accomplish this task. But I'd take it a step further, such as error handling. You don't want this to bomb out and not know what failed, when it failed, and what servers it did/didn't run on.
foreach ($SqlServerName in $SqlServerNames) {
try {
$SqlServer = New-Object Microsoft.SqlServer.Management.Smo.Server($SqlServerName)
$SqlServer.JobServer.Jobs[$SqlJobName].Start()
}
catch {
# add your error handling code here
## for instance, write the error to a text file
}
}
And, as always with any code, test this out in a non-production environment to ensure that it does what you think it will and should do. Re-work it for your needs/environment.
As per RoKa's comment:
Can this be edited to check for whether the job is currently running, error handling?
Great point, and definitely something to check for (as well as if the job actually exists by checking for a non-null value):
foreach ($SqlServerName in $SqlServerNames) {
try {
$SqlServer = New-Object Microsoft.SqlServer.Management.Smo.Server($SqlServerName)
$SqlJob = $SqlServer.JobServer.Jobs[$SqlJobName]
if (($SqlJob) -and ($SqlJob.CurrentRunStatus -eq [Microsoft.SqlServer.Management.Smo.Agent.JobExecutionStatus]::Idle)) {
$SqlJob.Start()
}
else {
# handle/log accordingly if the job doesn't exist or it's not idle
}
}
catch {
# add your error handling code here
## for instance, write the error to a text file
}
}
EDIT: While re-reading your question, I see SQL Server 2000. Are those going to be the target instances? If that is the case, and you do decide to go with the PowerShell/SMO answer I provided, then definitely definitely definitely test and ensure it is going to do what you want. Test this out very far from production and be 100% sure it does what you think it will.
EDIT: It looks like SMO versions before SQL Server 2012 (i.e. 2005, 2008, and 2008 R2) support managing SQL Server 2000 instances. I'm finding this information through this BOL reference.
The answer, it turned out, is something no one in forum land would have been able to guess at, no matter how good with SQL Server they were. It was application-level security that no one here was aware of.
The CRM database which was the source of the data for insert, contains a table of system users managed on the front end of the application. The vendor who developed the software set it up, but as they left no documentation, no one here was aware of the security layer on the back-end. It was confusing, largely, because the security only affects certain views - so all those other jobs that were working were calling for information from tables and views that were not influenced by the security.
When testing logged in as me, the procedure worked because I am set up in the CRM table as an administrator, but the credentials used to run SQL Server agent don't even exist in the CRM user table.
Had nothing to do with SQL Server security, but everything to do with permissions (didn't see that coming)...
Best Answer
Would something like this work?