SQL 代理 powershell 上下文参考

bil*_*nkc 14 sql-server-2005 sql-server-2008 sql-server powershell

在我的新工作中,我们在每台服务器上都有多个命名实例。例如

  • 服务器 1\开发
  • Server1\DevIntegrated
  • 服务器 1\QA

我在工作中有一个 SQL PowerShell 脚本,它调用操作系统,调用Foo.exe但需要传递命令行参数(连接字符串)。每个实例上都将存在一个 SQL 代理作业,带有 PowerShell 类型的步骤,需要知道当前上下文是什么。此执行在 DevIntegrated 上开始。

我不想让每个脚本都以...开头

$thisInstance = "Dev"
Run Code Online (Sandbox Code Playgroud)

...特别是因为当我们在接下来的几个月中迁移到环境(新服务器和命名实例)时,我必须对其进行编辑。

如果我启动 SQLPS,我可以通过切片和切块 Get-Location 的结果或运行来确定我的实例

(Invoke-Sqlcmd -Query "SELECT @@servername AS ServerName" -SuppressProviderContextWarning).ServerName
Run Code Online (Sandbox Code Playgroud)

当 SQL 代理启动 PowerShell 类型的作业时,它会在 C:\windows\system32 中启动,并且Get-Location路由不起作用,因为它不在 SQLSERVER 上下文中。我可以切换到该上下文,但我将处于 SQL Server 的“根”,并且不知道我应该在哪个实例中。Invoke-Sqlcmd出于相同的原因,使用该路由也不起作用(从技术上讲,它在那里超时不是默认实例)

据我所知,我已经列举了我可以进入工作日志的所有基本“事情”,但似乎没有任何显示 SQLSERVER:\SQL\Server1\DevIntegrated

Get-Process似乎我可以使用它和一些尝试通过击中实例和匹配 spid 来拼凑东西的巫术,但这听起来像是来自地狱的血腥黑客。一定有一些基本的东西我错过了,有人能解释一下吗?

研究 PowerShell 的替代方案

我曾调查过使用其他工作类型,但没有得到令人满意的解决方案。研究表明,SQL 代理下列出的 PowerShell 是 SQLPS,通过右键单击代理启动它的实例会自动将我放到正确的位置。只有当我将交互式代码粘贴到作业步骤中时,我才知道前面提到的差异。

操作系统的作业类型使我处于相同的状态,因为我找不到确定哪个实例将我放入命令外壳的方法。当然,我可以使用 sqlcmd 并获取 的值,@@servername但是如果我知道启动 sqlcmd 的连接,我就不需要查询数据库;)

如果我们启用 TSQL 可能会工作,xp_cmdshell但我不确定他们是否打开了它——政府机构,他们可能对非默认设置很挑剔。即便如此,我还是被动态 SQL 困住了,失去了 PowerShell 提供的很多表现力和功能。

虽然有点笨拙,但我认为在第一步定义一个变量并将其传递给后续步骤,但研究发现了这篇文章处理多个作业步骤(BOL)

作业步骤必须是独立的。也就是说,作业不能在作业步骤之间传递布尔值、数据或数值。但是,您可以使用永久表或全局临时表将值从一个 Transact-SQL 作业步骤传递到另一个步骤。您可以使用文件将值从运行可执行程序的作业步骤从一个作业步骤传递到另一个作业步骤。

我不能使用常见的技巧,比如Foo.exe寻找一个众所周知的文件/环境变量/注册表设置,因为这会阻止跨实例的并发执行。

特尔;博士:

在 PowerShell 类型的 SQL 代理作业步骤中,如何确定启动该进程的 SQL Server 实例?

小智 10

如果您查看 SQL Server BOL,SQL Server 代理会提供一组“令牌”,它将替换为作业步骤命令文本和输出文件(后者将阻止 GUI“查看”按钮工作)。这些令牌似乎适用于除 T-SQL 之外的任何类型的步骤。

https://docs.microsoft.com/en-us/sql/ssms/agent/use-tokens-in-job-steps#sql-server-agent-tokens

因此,如果您有 SQL 2008 PowerShell 步骤,则可以使用以下命令启动它:

$sqlInstance = "$(ESCAPE_DQUOTE(SRVR))"
Run Code Online (Sandbox Code Playgroud)

您可能需要使用MACH(machine name) 和INST(just instance name) 来代替,因为使用默认实例SRVR == MACH,但使用命名实例SRVR == MACH\INST


小智 3

遗憾的是,我还没有对在 SQL Server 内部调用 PowerShell 脚本做太多事情。我现在也没有一台可以玩的电脑。

我相信,虽然不使用 PowerShell 类型步骤,但如果您使用 CmdExec 并像从命令行“powershell 'MyScript.ps1'”一样调用脚本,那么您可以传递一个包含您正在运行的实例的参数。例如“Powershell 'MyScript.ps1' MyInstanceName”。

因此,在脚本的开头,您有一个 param() 设置来接受 MyInstanceName 的值:


param(
   [Parameter(Position=0,Mandatory=$True)]
   [string]$InstanceName
)
#so if I wanted to use sqlcmd
sqlcmd -S $InstanceName -Q "SELECT @@VERSION"
Run Code Online (Sandbox Code Playgroud)

正如您一开始所说的,需要知道它所在的实例,以便 PowerShell 脚本可以正确调用 Foo.exe。但是,稍后您提到能够将值传递给其他步骤。如果这是真的,您可能需要考虑创建一个小型 SSIS 包来调用您的 PowerShell 脚本并执行您需要的任何其他操作。使用 SSIS,您可以设置整个包可以使用的全局变量。