Featured image of post Monitoring with PowerShell Chapter 3: Monitoring creation of scheduled tasks

Monitoring with PowerShell Chapter 3: Monitoring creation of scheduled tasks

Hi All,

After a blog post from Malwarebytes (here) about specific adware and cryptolockers using scheduled tasks to make sure they can remain undetected, or even regain control of the system by running a specific task every once in a while, We’ve decided with to start monitoring the creation of scheduled tasks. Users generally don’t really setup these tasks in normal situations.

We’ve decided to start alerting on any task created in the last 24 hours. Our N-Central monitoring system creates a ticket for this so we can investigate it. The great trick about this is that the set automatically resets itself after 24 hours, unless we create another task.

The monitoring set

Ok, so lets get started! the ingredients we will need today are:

  • Windows 8.1 or higher
  • PowerShell
  • A monitoring system, or way to run the scripts.

First, We’ll start by trying to get all tasks on our system. We’ll use the get-scheduledtask cmdlet.

1
Get-ScheduledTask

Now we have a cool list of tasks, but hey, there is no date information that is returned by this cmdlet?! That’s no fun. It seems like Microsoft had a little oversight in this case. Still, its not really a problem for us; Microsoft always stores the XML files for the scheduled tasks on the same location, namely %WINDIR%\System32\Tasks.

Instead of messing with extra modules, or even trying to get date information out of the default cmdlets we’ll move on to using get-childitem, with a filter of 24 hours. Lets start by grabbing our Task Path and setting it to a variable for ease of use, and then get the list of tasks created today.

1
2
$Taskpath = "$ENV:windir\system32\Tasks"
$TasksToday = Get-ChildItem -Path $TaskPath -Recurse| Where-Object {$_.CreationTime -gt (Get-Date).AddDays(-1)}

Ok, Great! now we already have a list of all files created today. We could stop right now, set this up in our monitoring system and be done with it. The only issue I have with this is that I’d like to know the actual tasks settings. So lets try getting those too.

We start looping through all the files, loading them as XML objects, and getting the information we care about. in our case we only want to know the name, author, and what command it would execute. We put that information in $TaskState. If $Taskstate remains blank during the entire script. We simply output “Healthy”.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$Taskpath = "$ENV:windir\system32\Tasks"
$TasksToday = Get-ChildItem -Path $TaskPath -Recurse| Where-Object {$_.CreationTime -gt (Get-Date).AddDays(-1)}

Foreach($task in $TasksToday){
$TaskXML = get-content $Task.FullName
$TaskName = $($TaskXML.task.RegistrationInfo.uri)
$TaskAuthor = $TaskXML.task.Principals.Principal.userid
$TaskExec = $TaskXML.task.actions.exec.command + $TaskXML.task.actions.exec.Arguments
$TaskState += "$TaskName has been created by SID: $TaskAuthor and executes $TaskExec`n"
}

if(!$TaskState){ $TaskState = "Healthy"}

Based on this information, we load this into our monitoring system and alert if the TaskState is anything but “Healthy”. And that’s it, we’re now monitoring the scheduled tasks with PowerShell. Happy PowerShelling!

Update: it was reported by a reader that he has some jobs that he did not have permissions on, and thus the task failed. My RMM system runs every PowerShell command as SYSTEM, so this wasn’t noticed during testing. Anyway, to solve this issue you can run the script below instead. This script forces ownership to be taken over for the current account.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$Taskpath = "$ENV:windir\system32\Tasks"
takeown /a /r /d Y /f "$TaskPath"
$TasksToday = Get-ChildItem -Path $TaskPath -Recurse| Where-Object {$_.CreationTime -gt (Get-Date).AddDays(-1)}

Foreach($task in $TasksToday){
$TaskXML = get-content $Task.FullName
$TaskName = $($TaskXML.task.RegistrationInfo.uri)
$TaskAuthor = $TaskXML.task.Principals.Principal.userid
$TaskExec = $TaskXML.task.actions.exec.command + $TaskXML.task.actions.exec.Arguments
$TaskState += "$TaskName has been created by SID: $TaskAuthor and executes $TaskExec`n"
}

if(!$TaskState){ $TaskState = "Healthy"}
All blogs are posted under AGPL3.0 unless stated otherwise
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy