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.

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.

$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”.

$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.

$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"}

Recent Articles

The return of CyberDrain CTF

CyberDrain CTF returns! (and so do I!)

It’s been since september that I actually picked up a digital pen equivalent and wrote anything down. This was due to me being busy with life but also my side projects like CIPP. I’m trying to get back into the game of scripting and blogging about these scripts. There’s still so much to automate and so little time, right? ;)

Monitoring with PowerShell: Monitoring Acronis Backups

Intro

This is a monitoring script requested via Reddit, One of the reddit r/msp users wondered how they can monitor Acronis a little bit easier. I jumped on this because it happened pretty much at the same time that I was asked to speak at the Acronis CyberSummit so it kinda made sense to script this so I have something to demonstrate at my session there.

Monitoring with PowerShell: Monitoring VSS Snapshots

Intro

Wow! It’s been a while since I’ve blogged. I’ve just been so swamped with CIPP that I’ve just let the blogging go entirely. It’s a shame because I think out of all my hobbies it’s one I enjoy the most. It’s always nice helping others achieve their scripting target. I even got a couple of LinkedIn questions asking if I was done with blogging but I’m not. Writing always gives me some more piece of mind so I’ll try to catch up again. I know I’ve said that before but this time I’ll follow through. I’m sitting down right now and scheduling the release of 5 blogs in one go. No more whining and no more waiting.