背景:Windows计划任务调用jps.exe,达到的效果跟直接在命令行下调用不同,有时候又相同,摸不着规律
正常的:
代码语言:java复制2088 ResidencyProgram
34572 Jps -Dapplication.home=C:Program FilesMicrosoftjdk-21.0.1.12-hotspot -Xms8m -Djdk.module.main=jdk.jcmd
异常的:
代码语言:java复制34572 Jps -Dapplication.home=C:Program FilesMicrosoftjdk-21.0.1.12-hotspot -Xms8m -Djdk.module.main=jdk.jcmd
经研究,发现是java.exe 、jps.exe本身特性导致。
结论先行:
代码语言:actionscript复制jps.exe -v显示1行还是2行,看java程序跑在普通命令行下还是Administrator命令行下。
如果java程序跑在普通命令行下,那你想执行jps.exe -v显示2行就得在普通命令行下执行jps.exe -v,如果在Administrator命令行下执行则显示1行。
如果java程序跑在Administrator命令行下,那你想执行jps.exe -v显示2行就得在Administrator命令行下执行jps.exe -v,如果在普通命令行下执行则显示1行。
以上特点,跟当前用户是否Administrators用户无关。
并且通过计划任务调用jps.exe -v,不论什么用户级别、不论是否最高权限、不论怎么设置(绝对路径、.bat、.ps1),最终效果都是类似Administrator命令行下执行jps.exe -v,通过前面的介绍我们知道,要想Administrator命令行下执行jps.exe -v显示2行,那就得把java程序跑在Administrator命令行下,也就是说要想计划任务调用jps.exe -v显示2行,就得事先把java程序跑在Administrator命令行下。
关于结论,我有个10分钟的录屏演示:https://cloud.tencent.com/developer/video/79701
测试用例演示步骤:
代码语言:text复制一、创建用户mssql
如果已创建,忽略
net user mssql "密码" /ADD /Y
NET LOCALGROUP "Remote Desktop Users" "mssql" /ADD
cmd.exe /c "wmic.exe UserAccount Where Name='mssql' Set PasswordExpires='false'"
NET LOCALGROUP "Administrators" "mssql" /ADD
创建好后,用这个用户至少登录一次以完成新用户的初始化
二、准备业务代码
创建目录
mkdir C:sql_installdba_toolsMonitor -force
编辑业务.ps1脚本
notepad C:sql_installdba_toolsMonitorbackup_full_file_uploader.ps1内容如下:
mkdir c:testabc -force
date >> c:testabcrizhi.log
cmd.exe /c "echo %userprofile%" >> c:testabcrizhi.log
jps.exe -v >> c:testabcrizhi.log
三、检查业务目录权限是否对mssql有完全权限,没有的话,给完全权限
属性→ 安全→ 编辑→ 添加用户mssql,勾选权限
四、安装jps.exe命令(openjdk)
https://www.microsoft.com/openjdk
目前最新版是:
https://aka.ms/download-jdk/microsoft-jdk-21.0.1-windows-x64.msi
五、准备C:runps.ps1 创建计划任务
#创建计划任务
schtasks.exe /create /tn "runps" /ru Administrator /rl highest /sc ONLOGON /tr "powershell.exe 'C:runps.ps1'" /f
创建计划任务指定哪个用户触发计划任务,哪个用户得对相关脚本有权限
示例中是Administrator触发计划任务,如果想mssql触发计划任务,那就改成mssql,需要mssql用户对C:runps.ps1有访问权限(属性→ 安全→ 编辑→ 添加用户mssql,勾选权限)
schtasks.exe /create /tn "mssql_runps" /ru mssql /rl LIMITED /sc ONLOGON /tr "powershell.exe 'C:runps.ps1'" /f
/RL 即run level : 为作业设置运行级别。有效值为LIMITED 和 HIGHEST。默认值为 LIMITED。
#C:runps.ps1 的内容如下
$Username = 'mssql'
$Password = ConvertTo-SecureString '明文密码' -AsPlainText -Force #明文密码替换成实际密码
$Credential = New-Object System.Management.Automation.PSCredential($Username, $Password)
$ScriptPath = 'C:sql_installdba_toolsMonitorbackup_full_file_uploader.ps1'
Start-Process -FilePath "powershell.exe" -ArgumentList "-ExecutionPolicy Bypass -File $ScriptPath" -Credential $Credential -NoNewWindow -Wait
#触发计划任务执行
schtasks /Run /TN "runps"
schtasks /Run /TN "mssql_runps"
六、查看结果
c:testabcrizhi.log
%userprofile%会显示执行者的用户目录
命令行下执行java程序
C:sql_installdba_toolsMonitorResidencyProgram.java代码如下
public class ResidencyProgram {
public static void main(String[] args) {
while (true) {
// 这里是常驻程序的逻辑代码
System.out.println("Hello, Residency Program!");
}
}
}
编译:
javac C:sql_installdba_toolsMonitorResidencyProgram.java
执行:
cd C:sql_installdba_toolsMonitor
java ResidencyProgram
如果是计划任务执行java程序
程序:
"C:Program FilesMicrosoftjdk-21.0.1.12-hotspotbinjava.exe"
参数
-classpath "C:Program FilesMicrosoftjdk-21.0.1.12-hotspotbin" ResidencyProgram
java.exe、jps.exe的特点就是如此,通过计划任务调用,是类似在Administrator命令行下执行java.exe、jps.exe命令。手动执行的时候注意下是否是Administrator命令行操作的。
另外,手动执行的时候意味着当前已经看到图形界面了(至少看到命令行界面了),而计划任务执行的时候不一定有图形界面,因此有以下建议:
①确认业务是在普通命令行下效率高还是Administrator命令行下效率高,如果是普通命令行下效率高,那就不要用计划任务跑业务了,因为java.exe、jps.exe在计划任务里调用相当于在Administrator命令行下执行。
②如果业务是Administrator命令行下效率高或者无所谓哪种命令行(2种命令行效率相当),计划任务最好能在图形界面下运行(执行时间不定,意味着要一直有已登录状态的图形界面),比如一直远程登录状态不注销 不锁屏 不断连,这种不现实,因此只能是:一直只使用vnc操作,用autologon (https://learn.microsoft.com/zh-cn/sysinternals/downloads/autologon)设置自动登录,使vnc一直保持在不锁屏的登录状态。