![在 Windows 7 中以域用户身份从服务执行 BAT 文件](https://linux22.com/image/1415846/%E5%9C%A8%20Windows%207%20%E4%B8%AD%E4%BB%A5%E5%9F%9F%E7%94%A8%E6%88%B7%E8%BA%AB%E4%BB%BD%E4%BB%8E%E6%9C%8D%E5%8A%A1%E6%89%A7%E8%A1%8C%20BAT%20%E6%96%87%E4%BB%B6.png)
首先是一些基础知识:
- 我正在运行一个作为服务 ServiceA 运行的数据库服务器应用程序。
- ServiceA安装在Server1和Server2上
- ServiceA 每次只在两台服务器中的一台上运行(它们是冗余服务器,如果一台服务器出现故障,另一台服务器上的 ServiceA 将自动启动)
- 我无法控制代码 ServiceA
- ServiceA 以本地系统帐户登录
- ServiceB 需要同时在 Server1 和 Server2 上运行
- ServiceB 以本地系统帐户登录
- 我可以在 ServiceA 数据库中创建配置对象。一种类型的对象就像 ServiceA 执行的脚本语言
- 脚本语言具有允许在本地系统上操作文件和执行命令的功能 - OPEN_FILE()、WRITE_FILE()、CLOSE_FILE() 和 SYSTEM()
- 执行这些命令时,它们将使用本地系统帐户的凭据运行
- ServiceA使用上述文件操作命令为ServiceB生成配置文件
- 在创建新的配置文件之前需要关闭 ServiceB(我实际上在临时文件夹中创建它们,关闭 ServiceB,复制文件,然后启动 ServiceB)
- Server1 和 Server2 都是 Windows 7 Enterprise
- Server1 和 Server2 都位于同一个域中
我正在尝试让 ServiceA 执行以下操作:
- 关闭 Server1 和 Server2 上的 ServiceB
- 将一些文件复制到Server1和Server2
- 在 Server1 和 Server2 上启动 ServiceB
我做了什么:
- 创建域帐户 (DomainX/UserY) 和密码 (PasswordZ)
- 在两台服务器上创建共享 (ShareW)
- 授予 DomainX/UserY 在两台服务器上访问 ShareW 的权限
- 使用 OPEN_FILE()、WRITE_FILE() 和 CLOSE_FILE() 创建 INSTALL.BAT 文件
- 使用 SYSTEM('C:\Temp\INSTALL.BAT >> C:\Temp\INSTALL.LOG 2>&1') 运行 INSTALL.BAT(由服务 A 作为本地系统运行)并创建调试日志
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
因此共享和权限设置正确
我的问题是尝试从 INSTALL.BAT 中停止并启动服务 B
我努力了:
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
SC 命令对本地计算机有效,但对远程计算机无效。这是在 Server2 上运行 INSTALL.BAT 的输出:
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.
(我尝试在 Server1 和 Server2 上运行 ServiceA - 结果相同 - 在本地有效,在远程失败)
如果我使用“以不同用户身份运行”以 DomainX/UserY 身份运行 CMD.EXE,则 SC 命令可以完美运行。因此在 Server2 上,以 DomainX/UserY 身份从 CMD.EXE 运行 INSTALL.BAT,我得到:
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 :
因此,DomainX/UserY 具有停止和启动远程服务器上服务的必要权限。这似乎是对本地系统帐户特权升级的某种阻止。
我已阅读有关将 HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\ 中的 LocalAccountTokenFilterPolicy 设置为 1 并重新启动的信息。我已这样做,但结果没有任何变化。
我尝试使用 psservice.exe,结果几乎相同(由 Server2 上的 ServiceA 运行的 INSTALL.BAT 的输出)
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:
然后我尝试使用 psexec(以一种相当复杂的方式捕获所有日志)
安装2.BAT
C:\Utilities\psexec -accepteula -u DomainX/UserY -p PasswordZ C:\Temp\INSTALL3.BAT >> C:\Temp\INSTALL3.LOG 2>&1
安装3.BAT
C:\Temp\INSTALL.BAT >> C:\Temp\INSTALL.LOG 2>&1
当我从命令行运行 INSTALL2.BAT(以 DomainX/UserY 身份运行)时,一切正常。
但是从 ServiceA 运行,在 INSTALL3.LOG 中我得到:
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:
因此,我明确将 DomainX/UserY 的完全控制权限添加到所有三个 BAT 文件的安全性中。结果是一样的(在 INSTALL3.LOG 中访问被拒绝。)
我也尝试过关闭 UAC,但没有发现什么影响
所以我现在很困惑-如何才能让以本地系统运行的服务执行 BAT 文件来模拟另一个用户并允许它在远程计算机上停止和启动服务?
答案1
答案其实很简单——使用 psexec 的 -h 选项
ServiceA 运行的脚本的 SYSTEM() 命令现在是:
C:\Utilities\psexec -accepteula -h -u DomainX/UserY -p PasswordZ C:\Temp\INSTALL.BAT >> C:\Temp\INSTALL.LOG 2>&1
完美运行