Summary: Guest blogger, Jason Morgan, talks about using XML to work with the Task Scheduler.
Microsoft Scripting Guy, Ed Wilson, is here. Today I am proud to introduce Jason Morgan as the newest guest blogger for the Hey, Scripting Guy! Blog. I ran across Jason at the first meeting of the Northern Virginia (NOVA) PowerShell User Group meeting. The Scripting Wife and I were hanging out, and I asked him if he would like to contribute. Today’s excellent post is the result of that collaboration. First, a little bit about Jason…
Jason Morgan has been working in IT since 2004. He is an engineer for Verizon Enterprise Services and he works in their Integrated Solutions organization, providing fully managed infrastructure and application support services for hosted and customer premise solutions. He is a founding member of the NOVA PowerShell User Group.
Blog: Jason's PowerShell Blog
Thank you for the opportunity to contribute to the Hey, Scripting Guy! Blog. I’m here today to talk about working with XML, specifically working with XML as it relates to the Task Scheduler. I’ve found at my job that I often need to create the same tasks on multiple computers. Unfortunately, the raw functionality that comes with schtasks.exe is a little limited. For example, you can create a 2003- or 2008-level task, but you can’t create a 2008 R2 task, which in the XML, is v1.2. Luckily, schtasks and the Task Scheduler COM objects are able to create tasks directly from XML.
Ultimately, using XML is an easy and flexible way to create tasks and deploy them throughout your environment. It gives you extremely granular control of a task. After you try it, you’ll find it’s nearly as easy as using the GUI—and it’s a heck of a lot faster.
For those of you who aren’t familiar with working with XML in Windows PowerShell, there are a ton of great articles and blogs that cover the subject. In this post, I’m going to largely skip the fundamentals and get right in to how to work with XML for scheduled tasks. For background information, I recommend the following posts:
- PowerShell and XML
- XML Part 2: Write, Add And Change XML Data
- Use PowerShell to Simplify Working with XML Data
The first thing you need to do is import a task:
$Task = get-content .\example.xml
Then you can begin investigating or overwriting settings. Today we’re going to set up a task to run a Windows PowerShell script that’s starts on January 1 and runs every 4 hours for a week. Just for fun, we’ll also set it to run when a certain user logs on.
Whenever I work with a new XML object, I like to start by piping the XML document to the Format-Custom cmdlet. It’s great way to view any XML object in detail, and it can be a lot easier than trying to go through it manually. Avoid Format-List if you don’t want to see big blocks of the raw XML.
$task | format-custom
Hopefully after looking at the output, you should have a pretty good idea of all the options you have for modifying the task. Here’s a quick tip: The date format that is supported by the Task Scheduler XML schema is produced as follows:
get-date –format s
It outputs something like this:
Overwriting XML elements is really easy. They accept strings, so all you need to do is:
$xml.element.property = “MyNewValue”
For scheduled tasks, you browse or tab your way to the property you’re looking for, and overwrite it.
You can (and should) use the Task Scheduler Schema information from MSDN if you run into issues when you are overwriting elements.
Time intervals are specified by using the Interval (repetitionType) Element. The format is:
In our case, 4 hours will be PT4H.
Before you can start modifying the XML, you’ll need a good template to work with. I usually start with a simple Task document and add to it as needed. The following posts have good information about adding nodes to XML documents:
I’ve added TimeTrigger and LogonTrigger nodes under $task.task.triggers.
Now I’m going to overwrite the settings to meet my needs. I’m staging the task to run when my friend Nick logs on:
$task.Task.Triggers.LogonTrigger.UserId = "Contoso\Nick"
In addition to that, I want it to run a little after New Year’s Day 2014.
$task.Task.Triggers.TimeTrigger.StartBoundary = "$(Get-Date "01/1/2014 00:01:00" -Format s)"
I need to use the subexpression, $(), and the quotation marks because the XML can only accept string values. After that, I set the repetition interval and duration:
$task.Task.Triggers.TimeTrigger.Repetition.Interval = "PT4H"
$task.Task.Triggers.TimeTrigger.Repetition.Duration = "P7D"
Note Earlier I mentioned the time format that the Task Scheduler accepts. If you have questions, please refer to the post I linked to there.
We’ve set the triggers the way we want them. So now we want to set the actions for our task and import our updated XML document. To overwrite the task actions, we simply navigate to the actions node and update the command and arguments:
$task.Task.Actions.Exec.Command = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
$task.Task.Actions.Exec.Arguments = "-file c:\scripts\SendHappyNewYear.ps1"
I wrote a fun little script that plays a happy New Year’s greeting for my friend. I’d like to keep my friend from discovering this task before it goes off, so I’ll hide it:
$task.Task.Settings.Hidden = "true"
With the actions in place and the settings modified, the only thing left to do is load it into the Task Scheduler. For Schtasks.exe, we need to point to an XML file. So need to save our modified task as an .xml file. You can commit your changes by saving the XML object—you can overwrite the existing document or make a new one.
Now run schtasks:
schtasks.exe /create /tn HappyNewYear /XML C:\NewTask.xml
That’s all there is to it!
When you are comfortable deploying a single task, it’s a quick step to deploying more complicated tasks across your environment. The Schtasks utility works well with PSRemoting and with the Invoke command, you can get a new task out to hundreds of servers in a couple minutes.
Thanks for reading!
Thank you Jason, for sharing your time and knowledge in this blog post, and also for leading the user group in NOVA.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at firstname.lastname@example.org, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy