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: