Primeiramente, alguns princípios básicos:
- Estou executando um aplicativo de servidor de banco de dados que é executado como um serviço ServiceA.
- O ServiceA está instalado no servidor1 e no servidor2
- O ServiceA é executado somente em um dos dois servidores ao mesmo tempo (eles são servidores redundantes, se um servidor falhar, o ServiceA no outro servidor será iniciado automaticamente)
- Eu não tenho controle sobre o código ServiceA
- ServiceA efetua logon como a conta do sistema local
- O ServiceB precisa ser executado no Server1 e no Server2
- ServiceB faz logon como a conta do sistema local
- Eu posso criar objetos de configuração no banco de dados do ServiceA. Um tipo de objeto é como uma linguagem de script que o ServiceA executa
- A linguagem de script tem funções para permitir a manipulação de arquivos e a execução de comandos no sistema local - OPEN_FILE (), WRITE_FILE (), CLOSE_FILE () e SYSTEM ()
- Quando esses comandos são executados, eles são executados com as credenciais da conta do sistema local
- ServiceA gera arquivos de configuração para o ServiceB usando os comandos de manipulação de arquivos acima
- O ServiceB precisa ser encerrado antes que os novos arquivos de configuração sejam criados (na verdade, criei-os em uma pasta temporária, encerrei o ServiceB, copiei os arquivos e iniciei o ServiceB)
- Server1 e Server2 são ambos do Windows 7 Enterprise
- Server1 e Server2 estão no mesmo domínio
Estou tentando obter o ServiceA para:
- Shutdown ServiceB no servidor1 e no servidor2
- Copie alguns arquivos para Server1 e Server2
- Inicie o ServiceB no Server1 e no Server2
O que eu fiz:
- Criei uma conta de domínio (DomainX / UserY) com uma senha (PasswordZ)
- Criado um compartilhamento nos dois servidores (ShareW)
- Dada a permissão DomainX / UserY para acessar o ShareW em ambos os servidores
- Usou OPEN_FILE (), WRITE_FILE () e CLOSE_FILE () para criar um arquivo INSTALL.BAT
- Usado SYSTEM ('C: \ Temp \ INSTALL.BAT > > C: \ Temp \ INSTALL.LOG 2 > & 1') para executar o INSTALL.BAT (executado pelo Serviço A como Sistema Local) e crie um log de depuração
O que funciona dentro do arquivo BAT
NET USE \Server1\ShareW PasswordZ /USER:DomainX/UserY
NET USE \Server2\ShareW PasswordZ /USER:DomainX/UserY
DEL /F /Q "\Server1\ShareW\*.*
DEL /F /Q "\Server2\ShareW\*.*
XCOPY /Y "C:\Temp\*.*" "\Server1\ShareW\"
XCOPY /Y "C:\Temp\*.*" "\Server2\ShareW\"
NET USE \Server1\ShareW /DELETE
NET USE \Server2\ShareW /DELETE
Assim, o compartilhamento e as permissões são configurados corretamente
Meu problema é tentar parar e iniciar o serviço B de dentro de INSTALL.BAT
Eu tentei:
NET USE \Server1\IPC$ PasswordZ /USER:DomainX/UserY
SC \Server1 STOP "Service B"
NET USE \Server1\IPC$ /DELETE
NET USE \Server2\IPC$ PasswordZ /USER:DomainX/UserY
SC \Server2 STOP "Service B"
NET USE \Server2\IPC$ /DELETE
O comando SC funciona para a máquina local, mas falha na máquina remota. Esta é a saída do INSTALL.BAT em execução no Server2:
C:\Windows\system32>NET USE \Server1\IPC$ PasswordZ /USER:DomainX/UserY
The command completed successfully.
C:\Windows\system32>SC \Server1 STOP ServiceB
[SC] OpenService FAILED 5:
Access is denied.
(Eu tentei com o ServiceA rodando em Server1 e Server2 - os mesmos resultados - Funciona localmente, falha remotamente)
Se eu usar 'Executar como usuário diferente' para executar o CMD.EXE como DomainX / UserY, o comando SC funcionará perfeitamente. Então, no Server2, executando o INSTALL.BAT do CMD.EXE como DomainX / UserY eu recebo:
C:\Temp>NET USE \Server1\IPC$ PasswordZ /USER:DomainX/UserY
The command completed successfully.
C:\Temp>SC \Server1 START ServiceB
SERVICE_NAME: ServiceB
TYPE : 110 WIN32_OWN_PROCESS (interactive)
STATE : 2 START_PENDING
(NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x1
WAIT_HINT : 0xbb8
PID : 4856
FLAGS :
Assim, o DomainX / UserY possui as permissões necessárias para interromper e iniciar o serviço no servidor remoto. Parece ser algum tipo de bloqueio de escalonamento de privilégios da conta do Sistema Local.
Eu li sobre a configuração de LocalAccountTokenFilterPolicy em HKLM \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Policies \ System \ para 1 e reinicializando. Eu fiz isso sem alterações no resultado.
Eu tentei usar psservice.exe com resultados praticamente idênticos (saída de INSTALL.BAT executada pelo ServiceA no Server2)
C:\Windows\system32>C:\Utilities\psservice.exe \Server1 -u DomainX/UserY -p PasswordZ -accepteula stop ServiceB
PsService v2.24 - Service information and configuration utility
Copyright (C) 2001-2010 Mark Russinovich
Sysinternals - www.sysinternals.com
Access is denied.
Access is denied.
Error querying services on Server1:
Error opening ServiceB on Server1:
Eu então tentei usar psexec (de uma maneira bastante complicada para capturar todo o registro)
INSTALL2.BAT
C:\Utilities\psexec -accepteula -u DomainX/UserY -p PasswordZ C:\Temp\INSTALL3.BAT >> C:\Temp\INSTALL3.LOG 2>&1
INSTALL3.BAT
C:\Temp\INSTALL.BAT >> C:\Temp\INSTALL.LOG 2>&1
Quando executo o INSTALL2.BAT a partir da linha de comando (executando como DomainX / UserY), tudo funciona bem.
Mas corra do ServiceA, no INSTALL3.LOG eu recebo:
PsExec v2.11 - Execute processes remotely
Copyright (C) 2001-2014 Mark Russinovich
Sysinternals - www.sysinternals.com
Access is denied.
PsExec could not start C:\Temp\INSTALL3.BAT:
Então eu adicionei explicitamente DomainX / UserY com Controle Total à segurança de todos os três arquivos BAT. O resultado foi o mesmo (Acesso negado. Em INSTALL3.LOG)
Eu também tentei desativar o UAC sem impacto perceptível
Então estou praticamente preso agora - como posso obter um arquivo BAT executado por um serviço em execução como sistema local para representar outro usuário e permitir que ele pare e inicie serviços em uma máquina remota?