web-dev-qa-db-ja.com

SQLエージェントPowerShellコンテキストリファレンス

私の新しい仕事では、各サーバーに複数の名前付きインスタンスがあります。例えば.

  • Server1\Dev
  • Server1\DevIntegrated
  • Server1\QA

OSを呼び出し、Foo.exeを呼び出すSQL PowerShellスクリプトを作成していますが、コマンドラインパラメーター(接続文字列)を渡す必要があります。 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であり、エージェントを右クリックしてそのインスタンスを起動すると、自動的に正しい場所にドロップされました。前述の違いを知ったのは、インタラクティブコードをジョブステップに貼り付けたときだけです。

OSのジョブタイプは、どのインスタンスが私をコマンドシェルにドロップしたかを判断する方法を見つけることができなかったという点で、同じ状態に私を置きました。確かに、sqlcmdを実行して@@servernameの値を取得することはできますが、sqlcmdを開始するための接続がわかっていれば、データベースにクエリを実行する必要はありません;)

TSQLはおそらくxp_cmdshellを有効にすると機能する可能性がありますが、それが有効になっているかどうかはわかりません---政府機関であり、デフォルト以外の設定で永続的である可能性があります。それでも、動的SQLに悩まされ、PowerShellが提供する表現力と能力の多くを失っています。

少しおかしなことですが、最初のステップで変数を定義し、それを後続のステップに渡すことを考えましたが、調査によりこの記事が見つかりました 複数のジョブステップの処理 (BOL)

ジョブステップは自己完結型である必要があります。つまり、ジョブはブール値、データ、または数値をジョブステップ間で渡すことができません。ただし、永続テーブルまたはグローバル一時テーブルを使用して、1つのTransact-SQLジョブステップから別のジョブステップに値を渡すことができます。ファイルを使用して、あるジョブステップから別のジョブステップに実行可能プログラムを実行するジョブステップから値を渡すことができます。

インスタンス間での同時実行を防ぐため、Foo.exeが検索する既知のファイル/環境変数/レジストリ設定のような一般的なトリックを使用することはできません。

TL; DR:

PowerShellタイプのSQLエージェントジョブステップで、プロセスを起動したSQL Serverのインスタンスをどのように判断できますか?

13
billinkc

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(マシン名)とINST(インスタンス名のみ)を使用する必要があるかもしれません。デフォルトのインスタンスではSRVR == MACH、ただし名前付きインスタンスSRVR == MACH\INST

9
David Lathrop

悲しいことに、SQL Server内で呼び出されるPowerShellスクリプトをあまり使用していません。また、私が今それで遊ぶことができるコンピュータにいるわけでもありません。

ただし、PowerShellタイプのステップを使用する代わりに、CmdExecを使用してコマンドライン「powershell 'MyScript.ps1'」からスクリプトを呼び出す場合は、実行元のインスタンスを含むパラメーターを渡すことができると思います。 「Powershell 'MyScript.ps1' MyInstanceName」のように。

したがって、スクリプトの開始時に、MyInstanceNameの値を受け入れるようにparam()を設定します。


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

PowerShellスクリプトがFoo.exeを適切に呼び出すことができるように、インスタンスがどのインスタンスであるかを知るために必要な1つのステップを説明することから始めました。ただし、後で、値を他のステップに渡すことができることについて説明します。これが当てはまる場合は、PowerShellスクリプトを呼び出し、他に必要なことをすべて行う小さなSSISパッケージの作成を検討することをお勧めします。 SSISを使用すると、パッケージ全体で使用できるグローバル変数を設定できます。

3
user507