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.
schtasks
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.
Powershell
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")
$sch.Connect("remotehost")
$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")
$sch.Connect("remotehost")
$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.