The Usual Tech Ramblings

Powershell, and exporting Windows Scheduled Tasks

We’ve recently been asked to upgrade a 2003 server to 2008R2. Instead of doing an upgrade, we’re planning on doing a format, and clean install. One of the issues we have with this server is the number of scheduled tasks on the server. Unfortunately the 2003 .job format isn’t compatible with the 2008 .xml job format. After poking around, I found two solutions to this.


The first solution involves using the command schtasks. I stumbled across this one over at Simon Hampel’s blog here. This is a pretty easy method, and gets a Windows 7 (or 2008) machine to talk to the XP/2003 server to fetch the tasks. Telling schtasks to use the XML format, you can export all the jobs in one big batch as follows:

schtasks /query /S remotehostname /U username /P password /XML > output_file.xml

The username and password arguments can be omitted if you are using a domain account, and you have access to the server. This creates one big XML file that is mostly formatted in the 2008 .xml format. You simply have to split all the jobs up into their own files for re-importing. One thing to remember is that 2008 imports the job name as the file name, so if the file is myjob.xml, the job in 2008 will be called “myjob”, and I have yet to find a successful way to rename them without having to export, rename, and re-import them.


The second method was Powershell. While doing some job monitoring code for Nagios, I used a com object to connect to the scheduler service. This com object allows you to connect to remote hosts too. For a kick, I thought I’d test what I could see.

$sch = New-Object -ComObject("Schedule.Service")
$tasks = $sch.GetFolder("\").GetTasks(0)
$tasks | Get-Member

This series of commands returned the following:

Name                  MemberType Definition                                                    
----                  ---------- ----------                                                    
GetInstances          Method     IRunningTaskCollection GetInstances (int)                     
GetRunTimes           Method     void GetRunTimes (_SYSTEMTIME, _SYSTEMTIME, uint, _SYSTEMTIME)
GetSecurityDescriptor Method     string GetSecurityDescriptor (int)                            
Run                   Method     IRunningTask Run (Variant)                                    
RunEx                 Method     IRunningTask RunEx (Variant, int, int, string)                
SetSecurityDescriptor Method     void SetSecurityDescriptor (string, int)                      
Stop                  Method     void Stop (int)                                               
Definition            Property   ITaskDefinition Definition () {get}                           
Enabled               Property   bool Enabled () {get} {set}                                   
LastRunTime           Property   Date LastRunTime () {get}                                     
LastTaskResult        Property   int LastTaskResult () {get}                                   
Name                  Property   string Name () {get}                                          
NextRunTime           Property   Date NextRunTime () {get}                                     
NumberOfMissedRuns    Property   int NumberOfMissedRuns () {get}                               
Path                  Property   string Path () {get}                                          
State                 Property   _TASK_STATE State () {get}                                    
Xml                   Property   string Xml () {get}          

One of the properties is “Xml”, and a quick look at the output of that, showed the format matched that used in 2008 for jobs. A few more lines, and we had it outputting all the jobs to files.

$sch = New-Object -ComObject("Schedule.Service")
$tasks = $sch.GetFolder("\").GetTasks(0)

$outfile_temp = "C:\Temp\tasks\{0}.xml"

$tasks | %{
	$xml = $_.Xml
	$task_name = $_.Name
	$outfile = $outfile_temp -f $task_name
	$xml | Out-File $outfile

Now there are individual files for each task in the temp folder, and these can each be imported. The name of the file matches the old job name, so when reimporting, the jobs should match names too.

This affirms my belief that Microsoft did good stuff with Powershell, and they’ve begin to catch up with a decent scripting language for system administration. I could probably have executed the same with vbscript, but I suspect it would have been a lot harder.

Do you know any other ways to export 2003 jobs so 2008 can handle them? I’d love to hear them.