Monday, October 31, 2016

Inventory all scheduled tasks in a domain into Excel

I needed a listing of all scheduled tasks on all systems in our domain for a project we're doing.  There are numerous scripts out there on the web that can handle this but none were appropriate for my needs.  I used references from about 10 other scripts and combined them until they worked properly and then added an Excel output.  I needed a sort-able list so Excel was the simplest way of handling it.

You will need a credential file or you can alter it to accept hard values.

#Region Header
<#======================================================================================
         File Name : Get-ScheduledTasks.ps1
   Original Author : Kenneth C. Mazie (kcmjr AT kcmjr.com)
                   :
       Description : Will scan the current domain and extract all scheduled tasks and then
                        : store the results in an Excel spreadsheet.
                   :
         Operation : Requires PowerShell AD module.  Requires a credential file with domain creds.
                        : Scans domain and gets all system names with windows as the OS, then
                        : cycles through each system enumerating the scheduled tasks.  If
                        : connection is sucessful the system name is green, if not then red.
                        : Disabled tasks are a light gray color, enabled ones are black.
                   :
           Arguements : Normal operation is with no command line options.
                        : -console $true : Displays status output to console - defaults to $false
                   :
             Warnings : None.  Read only, no writing to systems.
                   :  
             Legal : Public Domain. Modify and redistribute freely. No rights reserved.
                   : SCRIPT PROVIDED "AS IS" WITHOUT WARRANTIES OR GUARANTEES OF
                   : ANY KIND. USE AT YOUR OWN RISK. NO TECHNICAL SUPPORT PROVIDED.
                   :
           Credits : Code snippets and/or ideas came from many sources including but
                   :   not limited to the following:
                        : http://serverfault.com/questions/604673/how-to-print-out-information-about-task-scheduler-in-powershell-script
                   :
    Last Update by : Kenneth C. Mazie (kcmjr AT kcmjr.com)
   Version History : v1.0 - 10-31-16 - Original
    Change History : v2.0 - 00-00-00 -
                   : 
                   :
=======================================================================================#>
#EndRegion
#requires -version 3.0

Param(
     [bool]$Console = $False
     )

If ($Console){$Script:Console = $true}

Clear-Host

$Credential = import-clixml -path "C:\Creds.txt"
$ErrorActionPreference = "silentlycontinue"
$domain = (Get-ADDomain).DNSroot
$user = $Credential.UserName.Split("\")[1]
$password = $Credential.GetNetworkCredential().password
$x = 1

$Excel = new-object -comobject excel.application
$Excel.Visible = $True
$objWorkbook = $Excel.Workbooks.Add()
$Worksheet = $objWorkbook.Worksheets.Item(1)
$Worksheet.Activate | Out-Null
$Worksheet.Cells.Range("a1","g1").Font.Bold = $True
$Worksheet.Cells.Range("a1","a10000").Font.Bold = $True
$Worksheet.Cells.Range("a1","g1").Interior.ColorIndex = 48
$Worksheet.Cells.Item($x, 1) = "Target Name"
$Worksheet.Cells.Item($x, 2) = "Task Name"
$Worksheet.Cells.Item($x, 3) = "Run As"
$Worksheet.Cells.Item($x, 4) = "Enabled"
$Worksheet.Cells.Item($x, 5) = "Trigger"
$Worksheet.Cells.Item($x, 6) = "Next Run"
$Worksheet.Cells.Item($x, 7) = "Actions"
$Worksheet.application.activewindow.splitcolumn = 0
$Worksheet.application.activewindow.splitrow = 1
$Worksheet.application.activewindow.freezepanes = $true

$TargetList = Get-ADComputer -Properties * -Filter * | sort name | where {$_.operatingsystem -Like "*Windows*"}

Foreach ($Computer in $TargetList){
     $x++
     $Computer = $Computer.name
     $Worksheet.Cells.Item($x, 1) = $Computer
     if (Test-Connection -ComputerName $Computer -count 1 -BufferSize 16 -ErrorAction SilentlyContinue){
           $Worksheet.Cells.Range("a$x","a$x").Font.ColorIndex = 10
           $schedule = New-Object -ComObject "Schedule.Service"
           $Schedule.Connect($Computer, $user, $domain, ($Credential.GetNetworkCredential().password));
           $Tasks = @()
           $out = @()
           $schedule.GetFolder("\").GetTasks(0) | % {
                $xml = [xml]$_.xml
                $out += New-Object psobject -Property @{
                     "ComputerName" = $Computer
                     "Name" = $_.Name
                     "Path" = $_.Path
                     "LastRunTime" = $_.LastRunTime
                     "NextRunTime" = $_.NextRunTime
                     "Actions" = ($xml.Task.Actions.Exec | % { "$($_.Command) $($_.Arguments)" }) -join "`n"
                     "Triggers" = $(If($xml.task.triggers){ForEach($task in ($xml.task.triggers | gm | Where{$_.membertype -eq "Property"})){$xml.task.triggers.$($task.name)}})
                     "Enabled" = $xml.task.settings.enabled
                     "UserID" = $xml.task.principals.Principal.UserID
                     "Description" = $xml.task.registrationInfo.Description
                     "LastTaskResult" = $_.LastTaskResult
                     "RunAs" = $xml.task.principals.principal.userid
                     <#--[ Additional Available Attributes ]--
                     'State' = switch ($_.State) {0 {'Unknown'} 1 {'Disabled'} 2 {'Queued'} 3 {'Ready'} 4 {'Running'} Default {'Unknown'}}
                'LastRunTime' = $_.lastruntime
                'NumberOfMissedRuns' = $_.numberofmissedruns
                'Author' =  ([xml]$_.xml).Task.RegistrationInfo.Author
                #>
                }
                $Tasks += $out
           }

           foreach ($item in $out){
                If ($item.Enabled -eq "false"){
                     $Worksheet.Cells.Range("b$x","g$x").Font.ColorIndex = 16
                }Else{
                     $Worksheet.Cells.Range("b$x","g$x").Font.ColorIndex = 1
                }
                If ($Console){Write-Host "Task Name:  "$item.Name -ForegroundColor Cyan }
                $Worksheet.Cells.Item($x, 2) = $item.name.ToString()
                If ($Console){Write-Host "RunAs User: "$item.UserID -ForegroundColor Green }
                $Worksheet.Cells.Item($x, 3) = $item.UserID.ToString()
                If ($Console){Write-Host "Enabled:    "$item.Enabled -ForegroundColor Magenta }
                $Worksheet.Cells.Item($x, 4) = $item.Enabled.ToString()
           if (($item.Triggers).ToString() -eq "CalendarTrigger") {
                If ($Console){Write-Host "Trigger:    "($item.Triggers).ToString() -ForegroundColor Magenta}
               $Worksheet.Cells.Item($x, 5) = ($item.Triggers).ToString()
                     $Worksheet.Cells.Item($x, 6) = ($item.NextRunTime).ToString()
                }Else{
                     if (($item.Triggers).ToString() -eq 'system.object[]'){
                           $Trigger = "SystemTrigger"
                     }Else{
                           $Trigger = ($item.Triggers).ToString()
                     }
                     If ($Console){Write-Host "Trigger:    "$Trigger -ForegroundColor Magenta}
                     If ($Console){Write-Host "Next Run:   " -ForegroundColor Magenta }
                     $Worksheet.Cells.Item($x, 5) = $Trigger
                     $Worksheet.Cells.Item($x, 6) = ""
                }   
                If ($Console){Write-Host "Actions:    "$item.Actions -ForegroundColor yellow}
                $Worksheet.Cells.Item($x, 7) = $item.Actions.ToString()
                If ($Console){Write-Host "------------------------------------------------"   }
                $x++
                $Range = $Worksheet.UsedRange
                [void] $Range.EntireColumn.Autofit()
           }
          
           $x++
          [System.Runtime.Interopservices.Marshal]::ReleaseComObject($schedule) | Out-Null
           Remove-Variable schedule
     }Else{
           $Worksheet.Cells.Range("a$x","b$x").Font.ColorIndex = 3
           $Worksheet.Cells.Item($x, 1) = $Computer
           $Worksheet.Cells.Item($x, 2).Font.Bold = $True
           $Worksheet.Cells.Item($x, 2) = "--- Connection Error ---"
           $x++
     }   
}

$workbook.SaveAs("$PSScriptRoot\ScheduledTasks.xlsx")
$excel.Quit()
[System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$excel) | Out-Null

If ($Console){Write-Host "--- COMPLETED ---" -ForegroundColor Red }