Getting Scheduled Tasks in PowerShell

There are a few approaches to manipulating scheduled tasks in PowerShell.

  • WMI – Useful if you are only going to manipulate them via script.  The tasks will not be visible in the control panel applet.
  • SCHTASKS.EXE – Works ok, but has a somewhat arcane syntax, and is a text-only tool.
  • Task Scheduler API -Best of both worlds, but only on Vista (not XP).

My current environment is an XP laptop, and hundreds of W2k3 and W2k8 servers.  I really need to be able to hit the tasks from the control panel (don’t have PowerShell installed everywhere…but that’s in process).  Since I have to use SCHTASKS.EXE , I figured I should write a PowerShell interface that makes things a bit easier.

The main thing I wanted was to get objects back.  Once you’ve started using PowerShell, you realize that “everything returns objects” makes for a very powerful scripting experience.  So, when you have to fall back to an external command like SCHTASKS.EXE, you really feel the pain.  The approach I took was to ask SCHTASKS for a verbose output (no reason not to get all of the properties), and also to write the output as CSV.  I then send the output into a file.  A problem that arises when trying to get PowerShell to import the CSV is that the column headers are not very friendly (e.g. “Repeat: Until: Time”).  So, before importing we need to “massage” a little bit.  I simply removed spaces (leaving Pascal-cased words) and replaced colons with underscores.  Another issue was that different versions of SCHTASKS.EXE would sometimes include an extra blank line in the file.  Finally, I decided that I should add some methods using Add-Member to allow me to run or delete the task without having to remember the syntax.

I hope you find this script useful.  If you have suggestions for improvements, or questions about how part of it works, feel free to leave a comment.

function get-tasks($server="", $taskname="",[switch]$help){
  if ($help)
    {
        $msg = @"
Get scheduled tasks from a remote server as objects.  Optionally you may supply a substring to be found in the task names.

Usage: get-tasks [Server] [substring] [-help]
ex:  get-tasks MACHINE1 LOGS    #to get all scheduled tasks from MACHINE1 containing LOGS
"@
        Write-Host $msg
        return
    }
    $filename = [System.IO.Path]::GetTempFileName()
 if ($server){
     schtasks /query /fo csv /s $server /v > $filename
 } else {
    schtasks /query /fo csv /v > $filename
 }
    $lines=Get-Content $filename
 if ($lines -is [string]){
    return $null
 } else {
        if ($lines[0] -ne ''){
   Set-Content -path $filename -Value ([string]$lines[0]).Replace(" ","").Replace(":","_")
   $start=1

  } else {
   Set-Content -path $filename -Value ([string]$lines[1]).Replace(" ","").Replace(":","_")
   $start=2
  }
  if ($lines.Count -ge $start){
   Add-content  -Path $filename -Value $lines[$start..(($lines.count)-1)]
  }
  $tasks=Import-Csv $filename
  Remove-Item $filename
  $retval=@()
  foreach ($task in $tasks){
   if (($taskname -eq '') -or $task.TaskName.contains($taskname)){
    $task.PSObject.TypeNames.Insert(0,"DBA_ScheduledTask")
    Add-Member -InputObject $task -membertype scriptmethod -Name Run -Value { schtasks.exe /RUN /TN $this.TaskName /S $this.HostName}
    Add-Member -InputObject $task -membertype scriptmethod -Name Delete -Value { schtasks.exe /DELETE /TN $this.TaskName /S $this.HostName}
    $retval += $task
   }
  }
  return $retval
 }
}

Links: