So we had an admin leave awhile back and soon afterwards some stuff stopped working. I won’t get into the details, but the root cause was not malicious. He’d been here for awhile and automated some tasks using task scheduler, that were set to run using his administrative account. While I applaud the effort to set stuff like this up, it wasn’t documented and it put us in a bind for a little bit. So if you’re thinking about doing something like this, first let someone know and second use a domain account with specific rights tailored to the task. Your coworkers thank you.
Anyway, after all the dust settled I was tasked to check all our systems for scheduled tasks running with accounts from our admin domain. At first I thought this was easy, SCCM captures everything about everything right? Well it doesn’t collect data about scheduled tasks, which seems odd to me because they can be used for some pretty malicious stuff. I ended up with the following as a bandaid scanner to check for the specific scenario of checking systems for a scheduled task running as a user in a specific domain. It’s quick and dirty like most of my scripts, but it got the job done once.
In the future, I’d like to tweak it a little to run on a local machine, just flag pass/fail, and set that up in DCM so that I can run a report once every month or so. I’m also thinking about ‘whitelisting’ tasks so that if a machine fails the whitelist check we’d get an alert through SCCM to go look at the box and see what unexpected task is running on the machine. So without futhre adieu:
If you’re planning on using this, there are a few things you need to change and/or review for your environment. So make sure you read and understand the code before you blindly drop it on your machine and run it.
#####################################################################
# Find Admin Tasks
#
# AUTHOR: David Bennett
#
# Purpose: Locate scheduled tasks from a list of remote systems
# which run under a admin account context
#
# USE: Place in a folder with FindAdmin.txt
# Populate FindAdmin.txt with a list of machines to be checked
# –One machine name per line…
# Ensure get-executionpolicy will allow PowerShell scripts
# Open a PS Console or CMD prompt, CD to containing folder
# Execute .\FindAdminTasks.ps1
#
#####################################################################
CLS
Remove-Item .\tasks.txt
$ErrorActionPreference = “silentlycontinue”
$InputList = get-content .\FindAdmin.txt
$InputCount = $InputList.Count
$runtime = $InputList.Length * 3 / 60
“Expected runtime for $InputCount systems is $runtime minutes”
# For Each Computer, get results to tasks.csv
foreach ($Computer in $InputList)
{
If(Test-Connection -ComputerName $Computer -Quiet -Count 2)
{
“Checking $Computer”
#Set up native command
$ScriptBlock =
$CMD = ‘schtasks.exe’
$arg1 = “/query”
$arg2 = “/S”
$Arg3 = “$Computer”
$arg4 = ‘/V’
$arg5 = ‘/FO’
$arg6 = ‘TABLE’
$arg7 = ‘/NH’
&$cmd $arg1 $arg2 $Arg3 $arg4 $arg5 $arg6 >> .\tasks.txt
}
Else {“Connection to $Computer failed”}
}
$tasks = Get-Content .\tasks.txt
“Line Title System User Status Next Run Time”
Foreach ($line in $tasks)
{
#Filter out bad rows
#Remove Folder Info
If($line.Length -ge 80) {
#Remove Divider Lines
If (!$line.StartsWith(“=”)) {
If (!$line.StartsWith(“Host”)) {
#Build Output Fields
$LineNumber = $line.ReadCount
If ($LineNumber -le 9) {$LineNumber = “$LineNumber “}
If ($LineNumber -le 99 -and $LineNumber -ge 10) {$LineNumber = “$LineNumber “}
If ($LineNumber -le 999 -and $LineNumber -ge 100) {$LineNumber = “$LineNumber “}
$RunAs = $line.Substring(460,15)
$ComputerName = $line.Substring(0,15)
$TaskName = $line.Substring(15,40)
$Status = $line.Substring(81,15)
$NRT = $line.Substring(58,13)
#Remove Blank Rows
If (!$ComputerName.StartsWith(” “)) {
#Finally, output only systems with a Admin account as RunAs
If ($RunAs.StartsWith(“\”))
{
“$LineNumber $TaskName $ComputerName $RunAs $Status $NRT”
}
}
}
}
}
}