At my new job, we have multiple named instances on each servers. e.g.
- Server1\Dev
- Server1\DevIntegrated
- Server1\QA
I have a SQL PowerShell script in the works that calls out to the OS, invokes Foo.exe
but needs to pass a command line parameter (the connection string). A SQL Agent job will exist on each instance, with a step of type PowerShell, that needs to know what the current context is. i.e. This execution began on DevIntegrated.
I have no desire to have every script start with...
$thisInstance = "Dev"
...especially since I'd have to edit that when we migrate to environments (new servers and named instances) in the upcoming months.
If I start SQLPS, I can determine my instance by slicing and dicing the results of Get-Location or running
(Invoke-Sqlcmd -Query "SELECT @@servername AS ServerName" -SuppressProviderContextWarning).ServerName
When the SQL Agent starts a job of type PowerShell, it starts in the C:\windows\system32 and the Get-Location
route doesn't work as it's not in the SQLSERVER context. I can change into that context but I'll be at the "root" of SQL Server and won't know what instance I should be in. Using the Invoke-Sqlcmd
route won't work either for same reason (technically, it times out as there is no default instance)
To the best of my knowledge, I've enumerated all the basic "things" I can get into the job log but nothing seems to show SQLSERVER:\SQL\Server1\DevIntegrated
Get-ChildItem
Get-Host
Get-Location
Get-Process
Get-PSDrive
Get-PSProvider
Get-Service
Get-TraceSource
Get-Variable
Get-Process
seems like I could use that and some voodoo of trying to cobble things together by hitting the instances and matching spids but that just sounds like a bloody-hack from hell. There must be something basic that I'm missing, can anyone shed some light?
Alternatives to PowerShell investigated
I had investigated using other job types and didn't get a satisfactory resolution. Research indicated the PowerShell listed under SQL Agent was SQLPS and starting an instance of it by right clicking on the Agent automagically dropped me into the correct location. It was only when I pasted my interactive code into the job step that I learned of the difference as previously mentioned.
Job type of OS put me into an identical state in that I could not find a way to determine which instance dropped me into the command shell. Sure, I could sqlcmd and get the value of @@servername
but if I knew what connection to start sqlcmd, I wouldn't need to to query the database ;)
TSQL could probably work if we enable xp_cmdshell
but I'm not sure if they have it turned on---government facility and they can be persnickety on non-default settings. Even then, I'm stuck futzing with dynamic SQL and losing a lot of the expressiveness and power that PowerShell lends.
While a bit ungainly, I thought defining a variable at the first step and passing that to successor steps but research turned up this article Handling Multiple Job Steps (BOL)
Job steps must be self-contained. That is, a job cannot pass Boolean values, data, or numeric values between job steps. You can, however, pass values from one Transact-SQL job step to another by using permanent tables or global temporary tables. You can pass values from job steps that run executable programs from one job step to another job step by using files.
I can't use common tricks like a well-known file/environment variables/registry setting that Foo.exe
looks for since that would prevent concurrent execution across instances.
TL;DR:
In a SQL Agent Job step of type PowerShell, how can you determine the instance of SQL Server that launched the process?