Java 为什么schtasks不识别XML语法?

Java 为什么schtasks不识别XML语法?,java,xml,windows,syntax-error,windows-task-scheduler,Java,Xml,Windows,Syntax Error,Windows Task Scheduler,我试图通过从Java执行schtasks将计划任务XML导入Windows任务调度器。在我的程序运行schtasks命令之前,它会在元素中插入一个文件路径。任务调度器命令在我编辑XML之前起作用,但在编辑XML之后不起作用。它总是给我同样的错误: ERROR: The task XML is malformed. (1,2)::ERROR: incorrect document syntax 有趣的是,taskschd.msc可以毫无困难地导入我的任务。给我带来麻烦的只是一些小任务。如果我使

我试图通过从Java执行schtasks将计划任务XML导入Windows任务调度器。在我的程序运行schtasks命令之前,它会在
元素中插入一个文件路径。任务调度器命令在我编辑XML之前起作用,但在编辑XML之后不起作用。它总是给我同样的错误:

ERROR: The task XML is malformed.

(1,2)::ERROR: incorrect document syntax
有趣的是,
taskschd.msc
可以毫无困难地导入我的任务。给我带来麻烦的只是一些小任务。如果我使用taskschd.msc手动输入文件路径,然后将其导出,它与我的程序输出的XML完全匹配,但schtasks接受它。这使我相信它与文件编码有关。也就是说,我使用taskschd.msc生成的相同UTF-16格式对文件进行编码,因此我还怀疑它可能与
javax.xml
库处理文档的方式有关。我在互联网上搜索了一些答案,但我能找到的唯一结果是有缺陷的powershell脚本和格式不正确的XML文档。那么到底是什么导致了这个问题,我该如何解决它呢

以下是我的程序编辑XML文档和执行任务的方式:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(f2); // f2 is the XML file
Node n = document.getElementsByTagName("Command").item(0);
// f is the target executable that this task will execute
n.setTextContent("\"" + f.getAbsolutePath() + "\"");

Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-16");
Result output = new StreamResult(f2);
Source input = new DOMSource(document);

transformer.transform(input, output);

ProcessBuilder builder = new ProcessBuilder("cmd", "/c", "schtasks", "/Create", "/TN", taskName, "/XML",
        "\"" + f2.getAbsolutePath() + "\"");
Process p = builder.start();
<?xml version="1.0" encoding="UTF-16" standalone="no"?>
<Task xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task" version="1.2">
  <RegistrationInfo>
    <Date>2020-09-11T16:33:30</Date>
    <Author>CardinalSystem</Author>
    <URI>\LOTHStartupScheduler</URI>
  </RegistrationInfo>
  <Triggers>
    <LogonTrigger>
      <StartBoundary>2020-09-11T16:33:00</StartBoundary>
      <Enabled>true</Enabled>
    </LogonTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <GroupId>S-1-5-32-545</GroupId>
      <RunLevel>LeastPrivilege</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>false</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <IdleSettings>
      <StopOnIdleEnd>true</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>"C:\Users\Cardinal System\Desktop\TaskScheduler.exe"</Command>
      <Arguments>-startup 1</Arguments>
    </Exec>
  </Actions>
</Task>
下面是传递给schtasks的最后一个XML文件:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(f2); // f2 is the XML file
Node n = document.getElementsByTagName("Command").item(0);
// f is the target executable that this task will execute
n.setTextContent("\"" + f.getAbsolutePath() + "\"");

Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-16");
Result output = new StreamResult(f2);
Source input = new DOMSource(document);

transformer.transform(input, output);

ProcessBuilder builder = new ProcessBuilder("cmd", "/c", "schtasks", "/Create", "/TN", taskName, "/XML",
        "\"" + f2.getAbsolutePath() + "\"");
Process p = builder.start();
<?xml version="1.0" encoding="UTF-16" standalone="no"?>
<Task xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task" version="1.2">
  <RegistrationInfo>
    <Date>2020-09-11T16:33:30</Date>
    <Author>CardinalSystem</Author>
    <URI>\LOTHStartupScheduler</URI>
  </RegistrationInfo>
  <Triggers>
    <LogonTrigger>
      <StartBoundary>2020-09-11T16:33:00</StartBoundary>
      <Enabled>true</Enabled>
    </LogonTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <GroupId>S-1-5-32-545</GroupId>
      <RunLevel>LeastPrivilege</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>false</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <IdleSettings>
      <StopOnIdleEnd>true</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>"C:\Users\Cardinal System\Desktop\TaskScheduler.exe"</Command>
      <Arguments>-startup 1</Arguments>
    </Exec>
  </Actions>
</Task>

2020-09-11T16:33:30
基数系统
\LOTHStartupScheduler
2020-09-11T16:33:00
真的
S-1-5-32-545
租赁权
无知的新
假的
真的
真的
假的
假的
真的
假的
真的
真的
假的
假的
假的
PT0
7.
“C:\Users\Cardinal System\Desktop\TaskScheduler.exe”
-启动1
我认为可以提供有价值的信息来解决您的问题

正如您所指出的,该帖子表明问题与XML文件的编码有关(请参阅最新答案):

即使任务调度器将任务文件导出为UTF-16编码,它也拒绝读取它,除非它是UTF-8。使用文本编辑器(如TextPad或记事本+)将XML保存为UTF-8编码文件,任务计划程序将正确导入它(即使主XML标记显示encoding=“UTF-16”)

在代码中,您将
UTF-16
指示为所需的输出编码。在我的机器中,使用macOS,通过该配置,
转换器将生成一个UTF-16 Big-Endian格式的文件

如上所述,这种编码似乎不受支持:

是的,这些编码与导入xml文件(编码为
Notepad
names)一起使用:Unicode Ansi,而不是Unicode big-endian,UTF-8

不幸的是,这最后一个答案没有提供多少帮助。见下文

不过,您可以尝试修改程序以输出
UTF-8

显然,要做到这一点,您只需更改代码中的这一行:

transformer.setOutputProperty(OutputKeys.ENCODING,“UTF-8”);
不幸的是,它也可能是

如果是这样,您可以尝试以下方法:

String taskName=“taskName”;
文件f=新文件(“C:\\Users\\Cardinal System\\Desktop\\TaskScheduler.exe”);
文件f2=新文件(“C:\\Users\\Cardinal System\\Desktop\\input.xml”);
DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
DocumentBuilder db=dbf.newDocumentBuilder();
Document Document=db.parse(f2);//f2是XML文件
节点n=document.getElementsByTagName(“命令”).item(0);
//f是此任务将执行的目标可执行文件
n、 setTextContent(“\”+f.getAbsolutePath()+“\”);
Transformer Transformer=TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT,“是”);
setOutputProperty(OutputKeys.METHOD,“xml”);
transformer.setOutputProperty(OutputKeys.ENCODING,“UTF-8”);
setOutputProperty(OutputKeys.OMIT_XML_声明,“yes”);
File fout=新文件(“/Users/jccampanero/Desktop/output.xml”);
Writer out=null;
试一试{
out=新的OutputStreamWriter(新的FileOutputStream(fout),Charset.forName(“UTF-8”);
输出。写入(“\n”);
源输入=新的DOMSource(文档);
结果输出=新的StreamResult(输出);
变压器。变换(输入、输出);
out.flush();
}最后{
if(out!=null){
试一试{
out.close();
}捕获(ioe异常ioe){
ioe.printStackTrace();
}
}
}
ProcessBuilder=newProcessBuilder(“cmd”、“/c”、“schtasks”、“/Create”、“/TN”、taskName、“/XML”,
“\”+fout.getAbsolutePath()+“\”);
进程p=builder.start();
如果它也不起作用,您可以尝试不同的编码,如计算机上的默认编码,或者对
文档使用不同的序列化方法:

Writer-Writer=newfilewriter(“C:\\Users\\Cardinal System\\Desktop\\output.xml”);
XMLSerializer xml=新的XMLSerializer(writer,null);
序列化(文档);
请注意,在后台,此代码段使用
FileWriter
,这将对XML应用默认字符编码。请参阅以了解更多信息


因此,我最好的嘉宾是,可能以某种方式应用您的机器的默认编码会起到作用。

我也有类似的问题,并发现
SCHTASKS
不尊重任何编码,除了它认为是“正确的”:ANSI和UTF16 Little Endian。无论
xmllint
是否表示可以

无论您在
编码中输入了什么=
,都不会使
SCHTASKS
接受UTF8(带或不带BOM)、UTF-16 Big-Endian或其两种首选编码以外的任何内容

两个修正:

  • 如果只有ANSI字符,请删除“编码”属性(并使用记事本将其另存为ANSI)
  • 将其另存为UTF-16 LE,并将编码设置为“UTF-16”

我喜欢你的想法