Parse schtasks.exe Output with PowerShell

From Svendsen Tech PowerShell Wiki
Jump to: navigation, search

Here's a real-world example of me parsing schtasks.exe output in list format, filtering out things that cluttered up what we were looking for. This lists all scheduled tasks in all folders, including all properties schtasks.exe's verbose parameter provides.

Note that the properties of the first object returned will be used for the rest of the pipeline (no longer so with PSv4, I think?), so you will want the first try to be a success, when testing and viewing results directly...

I also suggest adding a ping check at the top to avoid having schtasks.exe time out (it takes longer).

This seemed to work quite well at work where I ran this code against a few dozen target servers, but I'm seeing oddities in my lab environment, which seems to be broken in odd and unusual ways - as usually. I'm getting errors about invalid XML against a 2012 R2 server among other things.

Anyhow, this isn't a fully cooked solution for you, but the hard part - the parsing, in verbose list format - is taken care of in a way that worked reliably with my test data/servers in early 2015. Good luck.

Jaap Brasser wrote a script that will probably work better for you and put it here on Technet - then Zachary Loeber pimped it up here (also on Technet).




Screenshot Example

This is what it looks like when it works:

Parse-schtasks exe.png

Download

Get-Task.ps1.txt - right-click and download.

Code

@(foreach ($Computer in $ComputerName) {
    Write-Host -ForegroundColor Green "Processing $Computer ..."
    $ErrorActionPreference = 'SilentlyContinue'
    $TaskText = schtasks.exe /query /s $Computer /fo list /v
    if (-not $?) {
        Write-Warning -Message "$Computer`: schtasks.exe failed"
        continue
    }
    $ErrorActionPreference = 'Continue'
    $TaskText = $TaskText -join "`n"
    @(
    foreach ($m in @([regex]::Matches($TaskText, '(?ms)^Folder:[\t ]*([^\n]+)\n(.+)'))) {
        $Folder = $m.Groups[1].Value
        foreach ($FolderEntries in @($m.Groups[2].Value -split "\n\n")) {
            foreach ($Inner in $FolderEntries) {
                [regex]::Matches([string] $Inner, '(?m)^((?:Repeat:\s)?(?:Until:\s)?[^:]+):[\t ]+(.*)') |
                    ForEach-Object -Begin { $h = @{}; $h.'Folder' = [string] $Folder  } -Process {
                        $h.($_.Groups[1].Value) = $_.Groups[2].Value
                    } -End { New-Object -TypeName PSObject -Property $h }
            }
        }
    }) | Where-Object { $_.Folder -notlike '\Microsoft*' -and `
        $_.'Run As User' -notmatch '^(?:SYSTEM|LOCAL SERVICE|Everyone|Users|Administrators|INTERACTIVE)$' -and `
        $_.'Task To Run' -notmatch 'COM handler' } #|
        #Select HostName, Folder, 'Run As User', 'Task To Run', 'Schedule Type', 'Logon Mode' #, * #| ft -AutoSize
}) # | Export-Csv -NoTypeInformation -Encoding UTF8 -Path oracleservertasks.csv