1

I am trying to import a scheduled task XML into the Windows Task Scheduler by executing schtasks from Java. Before my program runs the schtasks command, it inserts a file path in the <Command> element. The task scheduler command works before I edit the XML, but not afterwards. It keeps giving me the same error:

ERROR: The task XML is malformed.

(1,2)::ERROR: incorrect document syntax

Interestingly enough, taskschd.msc imports my task with no trouble. It's only schtasks that is giving me trouble. If I manually enter the file path using the taskschd.msc and then export it, it perfectly matches the XML my program outputs, but schtasks accepts it. This makes me believe that it has something to do with the file encoding. That being said, I encode the file with the same UTF-16 format that taskschd.msc produces, so I also suspect it may have something to do with the way the javax.xml library processes documents. I poked around the internet for some answers, but the only results I could find were for flawed powershell scripts and actually malformed XML documents. So what exactly is causing this problem and how can I fix it?

This is how my program is editing the XML document and executing 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();

And here is the final XML file that is passed to schtasks:

<?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>
Cardinal System
  • 2,749
  • 3
  • 21
  • 42

2 Answers2

1

I think this MSDN page can provide valuable information to solve your problem.

As you also indicated, that post suggests that the problem is related to the encoding of your XML file (see the latest answers):

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").

In your code, you are indicating UTF-16 as the desired output encoding. In my machine, with macOS, with that configuration the Transformer will generate a file in UTF-16 Big Endian.

As stated in the post mentioned above, this encoding appears to be unsupported:

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

Unfortunately, this last answer doesn't provide much help. See this post.

Nevertheless, you can try and modify your program to output UTF-8.

To do that, apparently, you would just need to change this line in your code:

transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");

Unfortunately, again, it could also be tricky.

If that is your case, you can try something like:

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();

If it doesn't work either, you can try a different encoding, like the default on your machine, or a different serialization approach for your document:

Writer writer = new FileWriter("C:\\Users\\Cardinal System\\Desktop\\output.xml");
XMLSerializer xml = new XMLSerializer(writer, null);
xml.serialize(document);

Please, be aware that under the hood this code snippet uses FileWriter which in turn will apply the default character encoding to your XML. Please, see this stack overflow question for more information.

So my best guest is that probably applying your machine's default encoding one way or another will do the trick.

Cardinal System
  • 2,749
  • 3
  • 21
  • 42
jccampanero
  • 50,989
  • 3
  • 20
  • 49
  • I like that you are thinking outside of the box. Unfortunately, this solution does not work. – Cardinal System Sep 15 '20 at 15:30
  • I am sorry the solution does not work. @Cardinal-ReinstateMonica, and ```schtasks``` is able to process the XML file if you invoke the application directly from the command line? I mean, if you invoke from ```cmd``` the command passed to ```ProcessBuilder```. – jccampanero Sep 15 '20 at 15:39
  • No, using the command line directly does not work. If I import the task using using `taskschd.msc` (Task Scheduler, Microsoft Management Console) instead of `schtasks.exe` (command line utility), it works. If I export it from taskschd without editing it afterwards, schtasks will accept the file and successfully schedule the task. After editing the XML, however, schtasks will no longer accept the file, while taskschd does. – Cardinal System Sep 15 '20 at 15:51
  • I understand. And, have you try to use ```utf-8``` encoding instead of ```utf-16``` in your transformation? Maybe the problem could be that when you edit the file you are changing the encoding as well. – jccampanero Sep 15 '20 at 15:56
  • I have tried using `UTF-8` as well. However, the original file *is* encoded with `UTF-16`. – Cardinal System Sep 15 '20 at 15:58
  • It is ok @Cardinal-ReinstateMonica, although I think the change in encoding should not be a problem. And, if you compare both files, the one before editing the XML, and the one after editing, the content of the ```command``` element is the only difference? And, are there any differences if you compare the file obtained after exporting it from ```taskschd``` and the one before editing the content? – jccampanero Sep 15 '20 at 16:09
  • None whatsoever – Cardinal System Sep 15 '20 at 16:41
  • One last thing, I do not want to bother you: have you tried to not set any output property on ```Transformer```? Also, if you are using java 8, you can try to serialize the ```document``` in a different way: ```java.io.Writer writer = new java.io.FileWriter("C:\\Users\\Cardinal System\\Desktop\\output.xml"); XMLSerializer xml = new XMLSerializer(writer, null); xml.serialize(doc);``` where ```XMLSerializer``` references ```com.sun.org.apache.xml.internal.serialize.XMLSerializer```. Please, can you try and generate your document in this way and see if it works? – jccampanero Sep 15 '20 at 16:53
  • @Cardinal-ReinstateMonica I included in my answer a reference to a MSDN post which describes a similar problem to the one you are facing in your code. I hope it helps. – jccampanero Sep 15 '20 at 21:53
  • Changing to `UTF-8` did not work. Your XMLSerializer example *did* work. Add that to your answer, and the bounty is yours. – Cardinal System Sep 15 '20 at 23:13
  • Nice @Cardinal-ReinstateMonica! I expanded my answer with further information. – jccampanero Sep 16 '20 at 08:44
1

I had a similar issue, and found that SCHTASKS does not respect any encoding apart from what it deems are the "right ones": ANSI and UTF16 Little Endian. It does not matter if xmllint says it's OK.

It does not matter what you put into encoding=<your encoding>, nothing will make SCHTASKS accept UTF8 with or without BOM, UTF-16 Big Endian or anything else than its two preferred encodings.

Two fixes:

  • remove the encoding attribute if you only have ANSI characters (and just save it as ANSI using Notepad)
  • save it as UTF-16 LE and set the encoding to "UTF-16".
oligofren
  • 20,744
  • 16
  • 93
  • 180