Generate reports from a scheduled task

Andrew Kazyrevich
 
As your humble correspondent occasionally grumbles, generating SharpShooter reports from a WinForms app is not programmatically ordained. You have a choice, and a strong one: command line, coming along with the option of “automating everything”.
 
When a report needs to be generated on a regular basis, a scheduled task with a console app looks like a decent solution to eliminate a human. This post will show in detail, how to setup the necessary infrastructure.

Creating a scheduled task: semi-working solutions.

If you’re looking for “the final script” – feel free to move on to the next section: here we go through several simple but not perfect solutions and explain why and how they can be improved.
 
So said so done. There’s a nice command schtasks.exe which we could use for the following, perhaps the most straightforward, setup of a scheduled task from Powershell:

   $taskName = "AndrewTasks\MasterReportGenerator"
   $computer = "localhost"
   $runAs = "DOMAIN\username"    
   $runAsPassword = "yourpasswordhere"   
   $command = "MasterReportConsoleApp.exe"
   $arguments = "/master:C:\Temp\master.rst /child:C:\Temp\child.rst
   $schedule = "DAILY"
   iex "schtasks.exe /create 
           /s $computer 
           /ru $runAs /rp $runAsPassword 
           /tn $taskName /tr ($command + " " + $arguments) 
           /sc $schedule /st $startTime /F" | out-null

Unfortunately, this works well only on pre-Vista machines. On Vista onwards, this code will not fill in the “Start In” field and so your scheduled task would be starting with current folder set to System32 or something.
 

 
The above empty “Start in” might be a problem if your task operates with files using relative paths (say, uses logging etc). This can be fixed surprisingly easy though: just add a /V1 switch to the command to force the pre-Vista behavior:

   $taskName = "AndrewTasks\MasterReportGenerator"
   ...
   iex "schtasks.exe /create ...  ... /V1 /F" | out-null

This seems great, but has another drawback: this variant doesn’t let you create folders. If your task name has a backslash, the text before the backslash becomes a folder name, as in the screenshot below:
 

 
However, the /V1 switch doesn’t allow for backslashes in the task name, so folders are not an option either.
 
Looks like we need a better way!

Creating a scheduled task: XML based solution.

To get the full control over task creation, we need to drill down to its XML definition. It’s a relatively complex XML – which I’m not going to show here – with a motley collection of properties one can tweak, so just to give you a taste of what we’re doing here’s a simplified Powershell code (the proper version is waiting for you here at BitBucket):

   function CreateScheduledTask($computer, $taskName, $command, $arguments, 
                                $workingFolder, $startTime, $enable, $runAs, 
                                $runAsPassword)
   {    
       $xmlTemplate = "xml with placeholders for things we wanna tweak"
       $xml = $xmlTemplate -f "placeholder values - executable, start in, etc"

       $sch = new-object -ComObject("Schedule.Service")
       $sch.Connect($computer)
       $task = $sch.NewTask($null)
       $task.XmlText = $xml
       $createOrUpdateFlag = 6
       $sch.GetFolder("\").RegisterTaskDefinition(...) | out-null
   }

Basically, we fill in the placeholders of xmlTemplate with the values we want, and create a COM object of Schedule.Service which can register tasks using the XML we provide.
 
Here’s how to create a scheduled task for the console app from the previous post:

   $computer = "localhost"
   $taskName = "AndrewTasks\MasterReportGenerator"
   $workingFolder = "D:\sharpshooter\tasks\MasterReportGenerator"
   $command = "MasterReportConsoleApp.exe"
   $arguments = "/master:{0}\master.rst /child:{0}\child.rst /saveAs:{0}\result.pdf" -f $workingFolder
   $startTime = '21:00'
   $enable = $true.ToString().ToLower()
   $runAs = "DOMAIN\username"
   $runAsPassword = "yourpasswordhere"

   CreateScheduledTask  -computer:$computer `
                     -taskName:$taskName `
                     -workingFolder:$workingFolder `
                     -command:$command `
                     -arguments:$arguments `
                     -startTime:$startTime `
                     -enable:$enable `
                     -runAs:$runAs `
                     -runAsPassword:$runAsPassword

And here’s the result: the scheduled task gets created under the proper folder, it would be run daily at 21:00, and of course we can always disable it or run it manually via the context menu in Task Scheduler:
 

 

Summary.

Using a scheduled task to automate report generation/delivery/etc is a neat and easy to implement solution (if you’re not afraid of Powershell ;) ). In this post we looked into a few simple scripts which may or may not work, depending on your Windows version – and finally opted for a more complex XML based solution which would work on any machine.
 
The powershell script for creating a scheduled task is added to the previous post’s project – download it here on BitBicket and have fun!
 

January 10th, 2012

Leave a Comment