diff --git a/doc/XXL-JOB官方文档.md b/doc/XXL-JOB官方文档.md index ed91c899..b8131d3e 100644 --- a/doc/XXL-JOB官方文档.md +++ b/doc/XXL-JOB官方文档.md @@ -1139,7 +1139,8 @@ public XxlJobSpringExecutor xxlJobExecutor() { GLUE模式(Python):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "python" 脚本; GLUE模式(PHP):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "php" 脚本; GLUE模式(NodeJS):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "nodejs" 脚本; - GLUE模式(PowerShell):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "PowerShell" 脚本; + GLUE模式(PowerShell):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "PowerShell 5.x (powershell)" 脚本; + GLUE模式(Pwsh):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "PowerShell 7+ (pwsh)" 脚本; - JobHandler:运行模式为 "BEAN模式" 时生效,对应执行器中新开发的JobHandler类“@XxlJob”注解自定义的value值; - 执行参数:任务执行所需的参数; @@ -1376,7 +1377,7 @@ dify.api-key={自行获取并修改} ### 3.6 GLUE模式(PHP) 同上 -### 3.7 GLUE模式(PowerShell) +### 3.7 GLUE模式(PowerShell / Pwsh) 同上 @@ -1654,7 +1655,7 @@ xxl-job-admin#com.xxl.job.admin.controller.JobApiController.callback 开发步骤:可参考 "章节三" ; 原理:每个 "GLUE模式(Java)" 任务的代码,实际上是“一个继承自“IJobHandler”的实现类的类代码”,“执行器”接收到“调度中心”的调度请求时,会通过Groovy类加载器加载此代码,实例化成Java对象,同时注入此代码中声明的Spring服务(请确保Glue代码中的服务和类引用在“执行器”项目中存在),然后调用该对象的execute方法,执行任务逻辑。 -#### 5.5.3 GLUE模式(Shell) + GLUE模式(Python) + GLUE模式(PHP) + GLUE模式(NodeJS) + GLUE模式(Powershell) +#### 5.5.3 GLUE模式(Shell) + GLUE模式(Python) + GLUE模式(PHP) + GLUE模式(NodeJS) + GLUE模式(Powershell/Pwsh) 开发步骤:可参考 "章节三" ; 原理:脚本任务的源码托管在调度中心,脚本逻辑在执行器运行。当触发脚本任务时,执行器会加载脚本源码在执行器机器上生成一份脚本文件,然后通过Java代码调用该脚本;并且实时将脚本输出日志写到任务日志文件中,从而在调度中心可以实时监控脚本运行情况; @@ -1664,7 +1665,9 @@ xxl-job-admin#com.xxl.job.admin.controller.JobApiController.callback - python脚本:任务运行模式选择为 "GLUE模式(Python)"时支持 "Python" 脚本任务; - php脚本:任务运行模式选择为 "GLUE模式(PHP)"时支持 "PHP" 脚本任务; - nodejs脚本:任务运行模式选择为 "GLUE模式(NodeJS)"时支持 "NodeJS" 脚本任务; - - powershell:任务运行模式选择为 "GLUE模式(PowerShell)"时支持 "PowerShell" 脚本任务; + - powershell:任务运行模式选择为 "GLUE模式(PowerShell)" 时支持 "Windows PowerShell 5.x (powershell)" 脚本任务; + - pwsh:任务运行模式选择为 "GLUE模式(Pwsh)" 时支持 "PowerShell 7+ (pwsh)" 脚本任务; + 两者都要求目标机器已安装对应命令并且 PATH 可访问; 脚本任务通过 Exit Code 判断任务执行结果,状态码可参考章节 "5.15 任务执行结果说明"; diff --git a/xxl-job-admin/src/main/resources/templates/business/job.code.ftl b/xxl-job-admin/src/main/resources/templates/business/job.code.ftl index 5ddd5ea5..b1d2c59f 100644 --- a/xxl-job-admin/src/main/resources/templates/business/job.code.ftl +++ b/xxl-job-admin/src/main/resources/templates/business/job.code.ftl @@ -161,7 +161,7 @@ <#elseif jobInfo.glueType == "GLUE_NODEJS" > <#assign glueTypeModeSrc = "${request.contextPath}/static/plugins/codemirror/mode/javascript/javascript.js" /> <#assign glueTypeIdeMode = "text/javascript" /> -<#elseif jobInfo.glueType == "GLUE_POWERSHELL" > +<#elseif jobInfo.glueType == "GLUE_POWERSHELL" || jobInfo.glueType == "GLUE_PWSH" > <#assign glueTypeModeSrc = "${request.contextPath}/static/plugins/codemirror/mode/powershell/powershell.js" /> <#assign glueTypeIdeMode = "powershell" /> diff --git a/xxl-job-admin/src/main/resources/templates/business/job.list.ftl b/xxl-job-admin/src/main/resources/templates/business/job.list.ftl index 0680b61f..66cd27ab 100644 --- a/xxl-job-admin/src/main/resources/templates/business/job.list.ftl +++ b/xxl-job-admin/src/main/resources/templates/business/job.list.ftl @@ -1148,7 +1148,7 @@ exit 0 $("#addModal .form textarea[name='glueSource']").val( $("#addModal .form .glueSource_php").val() ); } else if ('GLUE_NODEJS'==glueType){ $("#addModal .form textarea[name='glueSource']").val( $("#addModal .form .glueSource_nodejs").val() ); - } else if ('GLUE_POWERSHELL'==glueType){ + } else if ('GLUE_POWERSHELL'==glueType || 'GLUE_PWSH'==glueType){ $("#addModal .form textarea[name='glueSource']").val( $("#addModal .form .glueSource_powershell").val() ); } else { $("#addModal .form textarea[name='glueSource']").val(""); diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/glue/GlueTypeEnum.java b/xxl-job-core/src/main/java/com/xxl/job/core/glue/GlueTypeEnum.java index 09875583..14f0c2ab 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/glue/GlueTypeEnum.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/glue/GlueTypeEnum.java @@ -12,6 +12,7 @@ public enum GlueTypeEnum { GLUE_PYTHON2("GLUE(Python2)", true, "python", ".py"), GLUE_NODEJS("GLUE(Nodejs)", true, "node", ".js"), GLUE_POWERSHELL("GLUE(PowerShell)", true, "powershell", ".ps1"), + GLUE_PWSH("GLUE(Pwsh)", true, "pwsh", ".ps1"), GLUE_PHP("GLUE(PHP)", true, "php", ".php"); private String desc; diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/util/ScriptUtil.java b/xxl-job-core/src/main/java/com/xxl/job/core/util/ScriptUtil.java index 12b7582d..71be8076 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/util/ScriptUtil.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/util/ScriptUtil.java @@ -7,6 +7,7 @@ import com.xxl.tool.io.IOTool; import java.io.FileOutputStream; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -28,6 +29,20 @@ public class ScriptUtil { * @throws IOException exception */ public static void markScriptFile(String scriptFileName, String scriptContent) throws IOException { + if (scriptFileName != null && scriptFileName.toLowerCase().endsWith(".ps1")) { + String powerShellEncodingHeader = "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8\r\n" + + "[Console]::InputEncoding = [System.Text.Encoding]::UTF8\r\n" + + "$OutputEncoding = [System.Text.Encoding]::UTF8\r\n"; + byte[] utf8Bom = new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}; + + try (FileOutputStream fileOutputStream = new FileOutputStream(scriptFileName)) { + fileOutputStream.write(utf8Bom); + fileOutputStream.write(powerShellEncodingHeader.getBytes(StandardCharsets.UTF_8)); + fileOutputStream.write((scriptContent != null ? scriptContent : "").getBytes(StandardCharsets.UTF_8)); + } + return; + } + // make file: filePath/gluesource/666-123456789.py FileTool.writeString(scriptFileName, scriptContent);