Executando um arquivo BAT como usuário de domínio de um serviço no Windows 7

Executando um arquivo BAT como usuário de domínio de um serviço no Windows 7

Em primeiro lugar, alguns princípios básicos:

  • Estou executando um aplicativo de servidor de banco de dados que é executado como um serviço ServiceA.
  • ServiceA está instalado em Server1 e Server2
  • O ServiceA só é executado em um dos dois servidores por vez (eles são servidores redundantes; se um servidor falhar, o ServiceA no outro servidor será iniciado automaticamente)
  • Não tenho controle sobre o código ServiceA
  • ServiceA faz logon como conta do Sistema Local
  • ServiceB precisa ser executado no Servidor1 e no Servidor2
  • ServiceB faz logon como conta do sistema local
  • Posso criar objetos de configuração no banco de dados ServiceA. Um tipo de objeto é como uma linguagem de script que o ServiceA executa
  • A linguagem de script possui funções para permitir a manipulação de arquivos e 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 ServiceB usando os comandos de manipulação de arquivo acima
  • O ServiceB precisa ser encerrado antes que os novos arquivos de configuração sejam criados (na verdade, eu os crio em uma pasta temporária, encerro o ServiceB, copio os arquivos e, em seguida, inicio o ServiceB)
  • Server1 e Server2 são ambos Windows 7 Enterprise
  • Server1 e Server2 estão no mesmo domínio

Estou tentando fazer com que o ServiceA:

  • Desligue o ServiceB no Servidor1 e no Servidor2
  • Copie alguns arquivos para Server1 e Server2
  • Inicie o ServiceB no Servidor1 e no Servidor2

O que eu fiz:

  • Criou uma conta de domínio (DomainX/UserY) com uma senha (PasswordZ)
  • Criou um compartilhamento em ambos os servidores (ShareW)
  • Dada permissão DomainX/UserY para acessar ShareW em ambos os servidores
  • Usado OPEN_FILE(), WRITE_FILE() e CLOSE_FILE() para criar um arquivo INSTALL.BAT
  • Usei 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 criar um log de depuração

O que funciona no 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

Portanto, o compartilhamento e as permissões estão configurados corretamente

Meu problema é tentar parar e iniciar o serviço B de dentro do 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 para a 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.

(Tentei com o ServiceA em execução no Servidor1 e no Servidor2 - mesmos resultados - Funciona localmente, falha remotamente)

Se eu usar 'Executar como usuário diferente' para executar CMD.EXE como DomainX/UserY, o comando SC funciona perfeitamente. Portanto, no Server2, executando INSTALL.BAT do CMD.EXE como DomainX/UserY, 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              :

Portanto o DomainX/UserY possui as permissões necessárias para parar 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 como definir LocalAccountTokenFilterPolicy em HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\ como 1 e reinicializar. Eu fiz isso sem alterações no resultado.

Tentei usar psservice.exe com resultados praticamente idênticos (saída de INSTALL.BAT executado por 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:

Então tentei usar o psexec (de uma maneira bastante complicada para capturar todos os registros)

INSTALAR2.BAT

C:\Utilities\psexec -accepteula -u DomainX/UserY -p PasswordZ C:\Temp\INSTALL3.BAT >> C:\Temp\INSTALL3.LOG 2>&1

INSTALAR3.BAT

C:\Temp\INSTALL.BAT >> C:\Temp\INSTALL.LOG 2>&1

Quando executo INSTALL2.BAT na linha de comando (executando como DomainX/UserY), tudo funciona bem.

Mas execute a partir do ServiceA, em 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:

Portanto, 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)

Também tentei desligar o UAC sem nenhum impacto perceptível

Então, estou praticamente preso agora - como posso fazer com que um arquivo BAT seja executado por um serviço executado como sistema local para representar outro usuário e permitir que ele interrompa e inicie serviços em uma máquina remota?

Responder1

A resposta é muito simples - use a opção -h do psexec

O comando SYSTEM() do script executado pelo ServiceA agora é:

C:\Utilities\psexec -accepteula -h -u DomainX/UserY -p PasswordZ C:\Temp\INSTALL.BAT >> C:\Temp\INSTALL.LOG 2>&1

Funciona perfeitamente

informação relacionada