Referência de contexto do PowerShell do SQL Agent

13

No meu novo trabalho, temos várias instâncias nomeadas em cada servidor. por exemplo

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

Eu tenho um script SQL PowerShell em andamento que chama o sistema operacional, chama, Foo.exemas precisa passar um parâmetro de linha de comando (a cadeia de conexão). Um trabalho do SQL Agent existirá em cada instância, com uma etapa do tipo PowerShell, que precisa saber qual é o contexto atual. ie Esta execução começou no DevIntegrated.

Não desejo que todo script comece com ...

$thisInstance = "Dev"

... especialmente porque eu teria que editar isso quando migrarmos para ambientes (novos servidores e instâncias nomeadas) nos próximos meses.

Se eu iniciar o SQLPS, posso determinar minha instância cortando e cortando os resultados de Get-Location ou executando

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

Quando o SQL Agent inicia um trabalho do tipo PowerShell, ele é iniciado em C: \ windows \ system32 e a Get-Locationrota não funciona, pois não está no contexto SQLSERVER. Posso mudar para esse contexto, mas estarei na "raiz" do SQL Server e não saberá em que instância devo estar. O uso da Invoke-Sqlcmdrota também não funcionará pelo mesmo motivo (tecnicamente, o tempo limite é excedido. não é uma instância padrão)

De acordo com o meu conhecimento, enumerei todas as "coisas" básicas que posso acessar no registro de tarefas, mas nada parece mostrar SQLSERVER:\SQL\Server1\DevIntegrated

Get-ProcessParece que eu poderia usar isso e algum vodu de tentar juntar as coisas, acertando as instâncias e os spids correspondentes, mas isso soa como um maldito hack do inferno. Deve haver algo básico que estou perdendo, alguém pode lançar alguma luz?

Alternativas ao PowerShell investigadas

Eu havia investigado o uso de outros tipos de trabalho e não obtive uma resolução satisfatória. A pesquisa indicou que o PowerShell listado no SQL Agent era SQLPS e iniciar uma instância clicando com o botão direito do mouse no agente me colocou automaticamente no local correto. Foi somente quando colei meu código interativo na etapa do trabalho que descobri a diferença, como mencionado anteriormente.

O tipo de trabalho do sistema operacional me colocou em um estado idêntico, pois não consegui encontrar uma maneira de determinar qual instância me colocou no shell de comando. Claro, eu poderia sqlcmd e obter o valor de, @@servernamemas se soubesse qual conexão iniciar o sqlcmd, não precisaria consultar o banco de dados;)

O TSQL provavelmente funcionaria se ativarmos, xp_cmdshellmas não tenho certeza se eles estão ativados --- instalação governamental e podem ser persnickety em configurações não padrão. Mesmo assim, estou empolgado com o SQL dinâmico e perdendo muita expressividade e poder que o PowerShell empresta.

Embora tenha sido um pouco desajeitado, pensei em definir uma variável na primeira etapa e passá-la para as etapas seguintes, mas a pesquisa apareceu neste artigo Manipulando várias etapas da tarefa (BOL)

As etapas do trabalho devem ser independentes. Ou seja, um trabalho não pode transmitir valores booleanos, dados ou valores numéricos entre as etapas do trabalho. No entanto, você pode passar valores de uma etapa da tarefa Transact-SQL para outra usando tabelas permanentes ou tabelas temporárias globais. Você pode passar valores de etapas do trabalho que executam programas executáveis ​​de um passo para outro, usando arquivos.

Não posso usar truques comuns, como uma configuração conhecida de arquivo / variáveis ​​de ambiente / registro que Foo.exeprocura, pois isso impediria a execução simultânea entre instâncias.

TL; DR:

Em uma etapa de trabalho do agente SQL do tipo PowerShell, como você pode determinar a instância do SQL Server que iniciou o processo?

billinkc
fonte
4
PowerShell é um requisito para o que você está fazendo?
Johndacostaa
O verdadeiro requisito seria ter um "algo" reutilizável no agente SQL que possa iniciar um processo DOS com um parâmetro da instância de chamada. O PowerShell parecia o melhor ajuste, dado o que não funcionava acima. Desculpe pela resposta tardia, eu estava no acampamento dos escoteiros.
billinkc

Respostas:

9

Se você procurar no BOL do SQL Server, o SQL Server Agent fornecerá um conjunto de "tokens" que serão substituídos no texto do comando da etapa da tarefa e no arquivo de saída (o mais recente impedirá o funcionamento do botão "visualização" da GUI). Esses tokens parecem funcionar para qualquer tipo de etapa, exceto o T-SQL.

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

Portanto, se você tiver uma etapa do SQL 2008 PowerShell, poderá iniciá-la com:

$sqlInstance = "$(ESCAPE_DQUOTE(SRVR))"

Você pode precisar usar MACH(nome da máquina) e INST(apenas o nome da instância), porque com a instância padrão SRVR == MACH, mas com instâncias nomeadas SRVR == MACH\INST.

David Lathrop
fonte
3

É triste dizer que não fiz muito com os scripts do PowerShell sendo chamados dentro do SQL Server. Também não estou em um computador que eu poderia jogar com ele agora.

Acredito que, em vez de usar a etapa do tipo PowerShell, se você usasse o CmdExec e chamasse seu script como faria em uma linha de comando "powershell 'MyScript.ps1'", poderia passar um parâmetro com a instância da qual está executando. Como "Powershell 'MyScript.ps1' MyInstanceName".

Portanto, no início do seu script, você tem uma configuração param () para aceitar esse valor de MyInstanceName:


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

Quando você começou declarando a única etapa necessária para saber em que instância estava, o script do PowerShell poderia chamar Foo.exe corretamente. No entanto, mais tarde, você mencionou ser capaz de passar o valor para outras etapas. Se isso for verdade, convém criar um pequeno pacote SSIS que chame seu script do PowerShell e faça o que precisar. Com o SSIS, você pode configurar uma variável global que todo o pacote poderia usar.


fonte