Firstly a few basics:
- I am running a database server application which runs as a service ServiceA.
- ServiceA is installed on Server1 and Server2
- ServiceA only runs on one of the two servers at any one time (they are redundant servers, if one server fails, ServiceA on the other server automatically starts)
- I have no control over the code ServiceA
- ServiceA logs on as the Local System account
- ServiceB needs to run on both Server1 and Server2
- ServiceB logs on as the Local System account
- I can create configuration objects in the ServiceA database. One type of object is like a scripting language which ServiceA executes
- The scripting language has functions to allow file manipulation and execution of commands on the local system - OPEN_FILE(), WRITE_FILE(), CLOSE_FILE(), and SYSTEM()
- When these commands are executed, they run with the credentials of the Local System account
- ServiceA generates configuration files for ServiceB using the above file manipulation commands
- ServiceB needs to be shutdown before the new configuration files are created (I actually create them in a temporary folder, shutdown ServiceB, copy the files, and then start ServiceB)
- Server1 and Server2 are both Windows 7 Enterprise
- Server1 and Server2 are both on the same domain
I'm trying to get ServiceA to:
- Shutdown ServiceB on both Server1 and Server2
- Copy some files to Server1 and Server2
- Start ServiceB on both Server1 and Server2
What I have done:
- Created a Domain Account (DomainX/UserY) with a password (PasswordZ)
- Created a share on both servers (ShareW)
- Given DomainX/UserY permission to access ShareW on both servers
- Used OPEN_FILE(), WRITE_FILE(), and CLOSE_FILE() to create an INSTALL.BAT file
- Used SYSTEM('C:\Temp\INSTALL.BAT >> C:\Temp\INSTALL.LOG 2>&1') to run the INSTALL.BAT (run by Service A as Local System) and create a debug log
What works from within the BAT file
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
So the share and permissions are setup correctly
My problem is trying to Stop and Start Service B from within INSTALL.BAT
I have tried:
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
The SC command works for the local machine, but fails for the remote machine. This is the output from INSTALL.BAT running on 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.
(I've tried with ServiceA running on Server1 and Server2 - same results - Works locally, fails remotely)
If I use 'Run as different user' to run CMD.EXE as DomainX/UserY, the SC command works perfectly. So on Server2, running INSTALL.BAT from CMD.EXE as DomainX/UserY I get:
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 :
So the DomainX/UserY has the necessary permissions to Stop and Start the service on the remote server. It appears to be some kind of blocking of privilege escalation from the Local System account.
I have read about setting LocalAccountTokenFilterPolicy in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\ to 1 and rebooting. I've done this with no changes to the outcome.
I've tried using psservice.exe with practically identical results (output from INSTALL.BAT run by ServiceA on 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:
I then tried to use psexec (in a rather convoluted manner to trap all the logging)
C:\Utilities\psexec -accepteula -u DomainX/UserY -p PasswordZ C:\Temp\INSTALL3.BAT >> C:\Temp\INSTALL3.LOG 2>&1
C:\Temp\INSTALL.BAT >> C:\Temp\INSTALL.LOG 2>&1
When I run INSTALL2.BAT from the command line (running as DomainX/UserY), everything works fine.
But run from ServiceA, In INSTALL3.LOG I get:
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:
So I explicitly added DomainX/UserY with Full Control to the security of all three BAT files. The result was the same (Access is denied. in INSTALL3.LOG)
I've also tried turning off UAC with no perceivable impact
So I'm pretty much stuck now - How can I get a BAT file executed by a service running as Local System to impersonate another user and allow it to Stop and Start services on a remote machine?