Sql-Server

SQL 代理 powershell 上下文參考

  • November 27, 2019

在我的新工作中,我們在每台伺服器上都有多個命名實例。例如

  • 伺服器1\開發
  • Server1\DevIntegrated
  • 伺服器1 \ QA

我有一個呼叫作業系統的 SQL PowerShell 腳本,呼叫Foo.exe但需要傳遞命令行參數(連接字元串)。每個實例上都將存在一個 SQL 代理作業,其中包含一個 PowerShell 類型的步驟,它需要知道目前上下文是什麼。這個執行開始於 DevIntegrated。

我不想讓每個腳本都以…開頭

$thisInstance = "Dev"

…特別是因為當我們在接下來的幾個月遷移到環境(新伺服器和命名實例)時,我必須對其進行編輯。

如果我啟動 SQLPS,我可以通過對 Get-Location 或執行的結果進行切片和切塊來確定我的實例

(Invoke-Sqlcmd -Query "SELECT @@servername AS ServerName" -SuppressProviderContextWarning).ServerName

當 SQL 代理啟動 PowerShell 類型的作業時,它會在 C:\windows\system32 中啟動,並且Get-Location路由不起作用,因為它不在 SQLSERVER 上下文中。我可以更改為該上下文,但我將處於 SQL Server 的“根”並且不知道我應該在哪個實例中。Invoke-Sqlcmd出於同樣的原因,使用該路由也不起作用(從技術上講,它在那裡超時不是預設實例)

據我所知,我已經列舉了我可以進入工作日誌的所有基本“事情”,但似乎沒有任何顯示SQLSERVER:\SQL\Server1\DevIntegrated

Get-Process似乎我可以使用它和一些試圖通過點擊實例和匹配 spid 來拼湊東西的巫術,但這聽起來像是來自地獄的血腥黑客。我必須缺少一些基本的東西,有人可以解釋一下嗎?

調查了 PowerShell 的替代品

我曾使用其他工作類型進行調查,但沒有得到令人滿意的解決方案。研究表明 SQL 代理下列出的 PowerShell 是 SQLPS,通過右鍵點擊代理啟動它的實例自動將我放到正確的位置。只有當我將互動式程式碼粘貼到作業步驟中時,我才知道前面提到的差異。

作業系統的作業類型使我處於相同的狀態,因為我找不到方法來確定哪個實例將我放入命令 shell。當然,我可以使用 sqlcmd 並獲取值,@@servername但如果我知道啟動 sqlcmd 的連接,我就不需要查詢數據庫;)

如果我們啟用 TSQL 可能會工作,xp_cmdshell但我不確定他們是否打開了它——政府設施,而且他們在非預設設置上可能會很挑剔。即便如此,我仍被動態 SQL 所困擾,失去了 PowerShell 所提供的大量表現力和強大功能。

雖然有點笨拙,但我想在第一步定義一個變數並將其傳遞給後續步驟,但研究發現這篇文章處理多個作業步驟(BOL)

作業步驟必須是獨立的。也就是說,作業不能在作業步驟之間傳遞布爾值、數據或數值。但是,您可以使用永久表或全域臨時表將值從一個 Transact-SQL 作業步驟傳遞到另一個。您可以使用文件將執行可執行程序的作業步驟中的值從一個作業步驟傳遞到另一個作業步驟。

我不能使用常見的技巧,比如尋找的眾所周知的文件/環境變數/系統資料庫設置,Foo.exe因為這會阻止跨實例的並發執行。

TL; 博士:

在 PowerShell 類型的 SQL 代理作業步驟中,如何確定啟動程序的 SQL Server 實例?

如果您查看 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))"

您可能需要使用MACH(machine name) 和INST(just instance name) 代替,因為使用預設實例SRVR == MACH,但使用命名實例SRVR == MACH\INST

遺憾的是,我在 SQL Server 中呼叫 PowerShell 腳本方面做得併不多。我也不是現在可以玩的電腦。

我相信,如果您使用 CmdExec 並像從命令行“powershell ‘MyScript.ps1’”那樣呼叫腳本,而不是使用 PowerShell 類型步驟,那麼您可以傳遞一個包含您正在執行的實例的參數。像“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"

當您開始說明需要知道它在哪個實例上的一個步驟時,PowerShell 腳本才能正確呼叫 Foo.exe。但是,稍後您提到能夠將值傳遞給其他步驟。如果這是真的,您可能需要考慮創建一個小型 SSIS 包來呼叫您的 PowerShell 腳本並執行您需要的任何其他操作。使用 SSIS,您可以設置整個包可以使用的全域變數。

引用自:https://dba.stackexchange.com/questions/3484