为什么 schtasks 无法识别 XML 语法?
Why does schtasks not recognize XML syntax?
我正在尝试通过从 Java 执行 schtasks 将计划任务 XML 导入到 Windows 任务计划程序中。在我的程序运行 schtasks 命令之前,它会在 <Command>
元素中插入一个文件路径。任务调度程序命令在之前 有效我编辑XML,但之后就不行了。它一直给我同样的错误:
ERROR: The task XML is malformed.
(1,2)::ERROR: incorrect document syntax
有趣的是,taskschd.msc
可以毫不费力地导入我的任务。只有 schtasks 给我带来了麻烦。如果我使用 taskschd.msc 手动输入文件路径,然后将其导出,它与我的程序输出的 XML 完全匹配,但 schtasks 接受它。这让我相信它与文件编码有关。也就是说,我使用 taskschd.msc 生成的相同 UTF-16 格式对文件进行编码,因此我也怀疑它可能与 javax.xml
库处理文档的方式有关。我在互联网上搜索了一些答案,但我能找到的唯一结果是有缺陷的 powershell 脚本和格式错误的 XML 文档。那么到底是什么导致了这个问题,我该如何解决?
这就是我的程序编辑 XML 文档和执行 schtasks 的方式:
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();
这是传递给 schtasks 的最终 XML 文件:
<?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>
我认为this MSDN page可以提供有价值的信息来解决您的问题。
正如您还指出的那样,post 表明问题与您的 XML 文件的编码有关(请参阅最新答案):
Even though the Task Scheduler exports a task file as UTF-16 encoded, it refuses to read it unless it's UTF-8. Use a text editor like TextPad or Notepad++ to save the XML as a UTF-8 encoded file, and the Task Scheduler will correctly import it (even if the main XML tag shows encoding="UTF-16").
在您的代码中,您将 UTF-16
指定为所需的输出编码。在我的机器上,使用 macOS,使用该配置 Transformer
将生成一个 UTF-16 Big Endian 文件。
如上文post所述,此编码似乎不受支持:
Yes, these encodings work with schtasks import xml files (encodings as Notepad
names them): Unicode Ansi, and these do not: Unicode big endian, UTF-8
不幸的是,最后一个答案没有提供太多帮助。参见 this post。
尽管如此,您可以尝试修改您的程序以输出 UTF-8
.
显然,要做到这一点,您只需要更改代码中的这一行:
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
不幸的是,它也可能是 tricky。
如果是这种情况,您可以尝试以下操作:
String taskName = "taskname";
File f = new File("C:\Users\Cardinal System\Desktop\TaskScheduler.exe");
File f2 = new File("C:\Users\Cardinal System\Desktop\input.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-8");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
File fout = new File("/Users/jccampanero/Desktop/output.xml");
Writer out = null;
try {
out = new OutputStreamWriter(new FileOutputStream(fout), Charset.forName("UTF-8"));
out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
Source input = new DOMSource(document);
Result output = new StreamResult(out);
transformer.transform(input, output);
out.flush();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
ProcessBuilder builder = new ProcessBuilder("cmd", "/c", "schtasks", "/Create", "/TN", taskName, "/XML",
"\"" + fout.getAbsolutePath() + "\"");
Process p = builder.start();
如果它也不起作用,您可以尝试不同的编码,例如您机器上的默认编码,或者为您的 document
:
使用不同的序列化方法
Writer writer = new FileWriter("C:\Users\Cardinal System\Desktop\output.xml");
XMLSerializer xml = new XMLSerializer(writer, null);
xml.serialize(document);
请注意,在幕后,此代码片段使用 FileWriter
,这反过来会将默认字符编码应用于您的 XML。请参阅 了解更多信息。
所以我最好的客人是,可能以一种或另一种方式应用您机器的默认编码就可以了。
我有一个类似的问题,发现 SCHTASKS
除了它认为是“正确的”:ANSI 和 UTF16 Little Endian 之外,不尊重任何编码。 xmllint
说没关系没关系
无论您在 encoding=<your encoding>
中输入什么,都不会使 SCHTASKS
接受带或不带 BOM 的 UTF8、UTF-16 Big Endian 或除其两种首选编码之外的任何其他编码。
两个修复:
- 如果您只有 ANSI 字符,请删除编码属性(并使用记事本将其保存为 ANSI)
- 将其保存为 UTF-16 LE 并将编码设置为“UTF-16”。
我正在尝试通过从 Java 执行 schtasks 将计划任务 XML 导入到 Windows 任务计划程序中。在我的程序运行 schtasks 命令之前,它会在 <Command>
元素中插入一个文件路径。任务调度程序命令在之前 有效我编辑XML,但之后就不行了。它一直给我同样的错误:
ERROR: The task XML is malformed.
(1,2)::ERROR: incorrect document syntax
有趣的是,taskschd.msc
可以毫不费力地导入我的任务。只有 schtasks 给我带来了麻烦。如果我使用 taskschd.msc 手动输入文件路径,然后将其导出,它与我的程序输出的 XML 完全匹配,但 schtasks 接受它。这让我相信它与文件编码有关。也就是说,我使用 taskschd.msc 生成的相同 UTF-16 格式对文件进行编码,因此我也怀疑它可能与 javax.xml
库处理文档的方式有关。我在互联网上搜索了一些答案,但我能找到的唯一结果是有缺陷的 powershell 脚本和格式错误的 XML 文档。那么到底是什么导致了这个问题,我该如何解决?
这就是我的程序编辑 XML 文档和执行 schtasks 的方式:
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();
这是传递给 schtasks 的最终 XML 文件:
<?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>
我认为this MSDN page可以提供有价值的信息来解决您的问题。
正如您还指出的那样,post 表明问题与您的 XML 文件的编码有关(请参阅最新答案):
Even though the Task Scheduler exports a task file as UTF-16 encoded, it refuses to read it unless it's UTF-8. Use a text editor like TextPad or Notepad++ to save the XML as a UTF-8 encoded file, and the Task Scheduler will correctly import it (even if the main XML tag shows encoding="UTF-16").
在您的代码中,您将 UTF-16
指定为所需的输出编码。在我的机器上,使用 macOS,使用该配置 Transformer
将生成一个 UTF-16 Big Endian 文件。
如上文post所述,此编码似乎不受支持:
Yes, these encodings work with schtasks import xml files (encodings as
Notepad
names them): Unicode Ansi, and these do not: Unicode big endian, UTF-8
不幸的是,最后一个答案没有提供太多帮助。参见 this post。
尽管如此,您可以尝试修改您的程序以输出 UTF-8
.
显然,要做到这一点,您只需要更改代码中的这一行:
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
不幸的是,它也可能是 tricky。
如果是这种情况,您可以尝试以下操作:
String taskName = "taskname";
File f = new File("C:\Users\Cardinal System\Desktop\TaskScheduler.exe");
File f2 = new File("C:\Users\Cardinal System\Desktop\input.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-8");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
File fout = new File("/Users/jccampanero/Desktop/output.xml");
Writer out = null;
try {
out = new OutputStreamWriter(new FileOutputStream(fout), Charset.forName("UTF-8"));
out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
Source input = new DOMSource(document);
Result output = new StreamResult(out);
transformer.transform(input, output);
out.flush();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
ProcessBuilder builder = new ProcessBuilder("cmd", "/c", "schtasks", "/Create", "/TN", taskName, "/XML",
"\"" + fout.getAbsolutePath() + "\"");
Process p = builder.start();
如果它也不起作用,您可以尝试不同的编码,例如您机器上的默认编码,或者为您的 document
:
Writer writer = new FileWriter("C:\Users\Cardinal System\Desktop\output.xml");
XMLSerializer xml = new XMLSerializer(writer, null);
xml.serialize(document);
请注意,在幕后,此代码片段使用 FileWriter
,这反过来会将默认字符编码应用于您的 XML。请参阅
所以我最好的客人是,可能以一种或另一种方式应用您机器的默认编码就可以了。
我有一个类似的问题,发现 SCHTASKS
除了它认为是“正确的”:ANSI 和 UTF16 Little Endian 之外,不尊重任何编码。 xmllint
说没关系没关系
无论您在 encoding=<your encoding>
中输入什么,都不会使 SCHTASKS
接受带或不带 BOM 的 UTF8、UTF-16 Big Endian 或除其两种首选编码之外的任何其他编码。
两个修复:
- 如果您只有 ANSI 字符,请删除编码属性(并使用记事本将其保存为 ANSI)
- 将其保存为 UTF-16 LE 并将编码设置为“UTF-16”。