functions/Get-JobSchedulerTaskHistory.ps1
function Get-JobSchedulerTaskHistory { <# .SYNOPSIS Returns the task execution history for jobs. .DESCRIPTION History information is returned for jobs from a JobScheduler Master. Task executions can be selected by job name, folder, history status etc. The history information retured includes start time, end time, return code etc. .PARAMETER Job Optionally specifies the path and name of a job. If the name of a job is specified then the -Directory parameter is used to determine the folder. Otherwise the -Job parameter is assumed to include the full path and name of the job. One of the parameters -Directory, -JobChain or -Job has to be specified. .PARAMETER JobChain Optionally specifies the path and name of a job chain that includes jobs. If the name of a job chain is specified then the -Directory parameter is used to determine the folder. Otherwise the -JobChain parameter is assumed to include the full path and name of the job chain. One of the parameters -Directory, -JobChain or -Job has to be specified. .PARAMETER OrderId Optionally specifies the identifier of an order to limit results to jobs that correspond to the order's current state. .PARAMETER Directory Optionally specifies the folder for which jobs should be returned. The directory is determined from the root folder, i.e. the "live" directory. .PARAMETER Recursive Specifies that any sub-folders should be looked up when used with the -Directory parameter. By default no sub-folders will be looked up for jobs. .PARAMETER State Specifies that only jobs are considered that an order is currently passing. This is identified by the order's state attribute that corresponds to the job node's state attribute. This parameter requires use of the -JobChain parameter. If used with the -OrderId parameter then only jobs for that order are considered, otherwise jobs for any orders in the given job chain are considered. .PARAMETER ExcludeJob This parameter accepts a single job path or an array of job paths that are excluded from the results. .PARAMETER RegEx Specifies a regular expression that filters the jobs to be returned. The regular expression is applied to the path and name of jobs. .PARAMETER DateFrom Specifies the date starting from which history items should be returned. Consider that a UTC date has to be provided. Default: Begin of the current day as a UTC date .PARAMETER DateTo Specifies the date until which history items should be returned. Consider that a UTC date has to be provided. Default: End of the current day as a UTC date .PARAMETER RelativeDateFrom Specifies a relative date starting from which history items should be returned, e.g. * -1s, -2s: one second ago, two seconds ago * -1m, -2m: one minute ago, two minutes ago * -1h, -2h: one hour ago, two hours ago * -1d, -2d: one day ago, two days ago * -1w, -2w: one week ago, two weeks ago * -1M, -2M: one month ago, two months ago * -1y, -2y: one year ago, two years ago Optionally a time offset can be specified, e.g. -1d+02:00, as otherwise midnight UTC is assumed. Alternatively a timezone offset can be added, e.g. by using -1d+TZ, that is calculated by the cmdlet for the timezone that is specified with the -Timezone parameter. This parameter takes precedence over the -DateFrom parameter. .PARAMETER RelativeDateTo Specifies a relative date until which history items should be returned, e.g. * -1s, -2s: one second ago, two seconds ago * -1m, -2m: one minute ago, two minutes ago * -1h, -2h: one hour ago, two hours ago * -1d, -2d: one day ago, two days ago * -1w, -2w: one week ago, two weeks ago * -1M, -2M: one month ago, two months ago * -1y, -2y: one year ago, two years ago Optionally a time offset can be specified, e.g. -1d+02:00, as otherwise midnight UTC is assumed. Alternatively a timezone offset can be added, e.g. by using -1d+TZ, that is calculated by the cmdlet for the timezone that is specified with the -Timezone parameter. This parameter takes precedence over the -DateFrom parameter. .PARAMETER Timezone Specifies the timezone to which dates should be converted in the history information. A timezone can e.g. be specified like this: Get-JSTaskHistory -Timezone (Get-Timezone -Id 'GMT Standard Time') All dates in JobScheduler are UTC and can be converted e.g. to the local time zone like this: Get-JSTaskHistory -Timezone (Get-Timezone) Default: Dates are returned in UTC. .PARAMETER Limit Specifies the max. number of history items for task executions to be returned. The default value is 10000, for an unlimited number of items the value -1 can be specified. .PARAMETER Successful Returns history information for successfully completed tasks. .PARAMETER Failed Returns history information for failed tasks. .PARAMETER Incomplete Specifies that history information for running tasks should be returned. .OUTPUTS This cmdlet returns an array of history items. .EXAMPLE $items = Get-JobSchedulerTaskHistory Returns today's task execution history for any jobs. .EXAMPLE $items = Get-JobSchedulerTaskHistory -RegEx '^/sos' Returns today's task execution history for any jobs from the /sos folder. .EXAMPLE $items = Get-JobSchedulerTaskHistory -RegEx 'report' Returns today's task execution history for jobs that contain the string 'report' in the job path. .EXAMPLE $items = Get-JobSchedulerTaskHistory -Timezone (Get-Timezone) Returns today's task execution history for any jobs with dates being converted to the local timezone. .EXAMPLE $items = Get-JobSchedulerTaskHistory -Timezone (Get-Timezone -Id 'GMT Standard Time') Returns today's task execution history for any jobs with dates being converted to the GMT timezone. .EXAMPLE $items = Get-JobSchedulerTaskHistory -Job /sos/dailyplan/CreateDailyPlan Returns today's task execution history for a given job. .EXAMPLE $items = Get-JobSchedulerTaskHistory -JobChain /sos/dailyplan/CreateDailyPlan Returns today's task execution history for jobs in the given job chain. .EXAMPLE $items = Get-JobSchedulerTaskHistory -ExcludeJob /sos/dailyplan/CreateDailyPlan, /sos/housekeeping/scheduler_rotate_log Returns today's task execution history for any jobs excluding the specified job paths. .EXAMPLE $items = Get-JobSchedulerTaskHistory -Successful -DateFrom "2020-08-11 14:00:00Z" Returns the task execution history for successfully completed jobs that started after the specified UTC date and time. .EXAMPLE $items = Get-JobSchedulerTaskHistory -Failed -DateFrom (Get-Date -Hour 0 -Minute 0 -Second 0).AddDays(-7).ToUniversalTime() Returns the task execution history for any failed jobs for the last seven days. .EXAMPLE $items = Get-JobSchedulerTaskHistory -RelativeDateFrom -7d Returns the task execution history for the last seven days. The history is reported starting from midnight UTC. .EXAMPLE $items = Get-JobSchedulerTaskHistory -RelativeDateFrom -7d+01:00 Returns the task execution history for the last seven days. The history is reported starting from 1 hour after midnight UTC. .EXAMPLE $items = Get-JobSchedulerTaskHistory -RelativeDateFrom -7d+TZ Returns the task execution history for any jobs for the last seven days. The history is reported starting from midnight in the same timezone that is used with the -Timezone parameter. .EXAMPLE $items = Get-JobSchedulerTaskHistory -RelativeDateFrom -1w Returns the task execution history for the last week. .EXAMPLE $items = Get-JobSchedulerTaskHistory -Directory /sos -Recursive -Successful -Failed Returns today's task execution history for any completed tasks from the "/sos" directory and any sub-folders recursively. .LINK about_jobscheduler #> [cmdletbinding()] param ( [Parameter(Mandatory=$False,ValueFromPipeline=$False,ValueFromPipelinebyPropertyName=$True)] [string] $Job, [Parameter(Mandatory=$False,ValueFromPipeline=$False,ValueFromPipelinebyPropertyName=$True)] [string] $JobChain, [Parameter(Mandatory=$False,ValueFromPipeline=$False,ValueFromPipelinebyPropertyName=$True)] [string] $OrderId, [Parameter(Mandatory=$False,ValueFromPipeline=$False,ValueFromPipelinebyPropertyName=$True)] [string] $Directory = '/', [Parameter(Mandatory=$False,ValueFromPipeline=$False,ValueFromPipelinebyPropertyName=$True)] [switch] $Recursive, [Parameter(Mandatory=$False,ValueFromPipeline=$False,ValueFromPipelinebyPropertyName=$True)] [string] $State, [Parameter(Mandatory=$False,ValueFromPipeline=$False,ValueFromPipelinebyPropertyName=$True)] [string[]] $ExcludeJob, [Parameter(Mandatory=$False,ValueFromPipeline=$False,ValueFromPipelinebyPropertyName=$True)] [string] $RegEx, [Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$True)] [DateTime] $DateFrom = (Get-Date -Hour 0 -Minute 0 -Second 0).ToUniversalTime(), [Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$True)] [DateTime] $DateTo = (Get-Date -Hour 0 -Minute 0 -Second 0).AddDays(1).ToUniversalTime(), [Parameter(Mandatory=$False,ValueFromPipeline=$False,ValueFromPipelinebyPropertyName=$True)] [string] $RelativeDateFrom, [Parameter(Mandatory=$False,ValueFromPipeline=$False,ValueFromPipelinebyPropertyName=$True)] [string] $RelativeDateTo, [Parameter(Mandatory=$False,ValueFromPipeline=$False,ValueFromPipelinebyPropertyName=$True)] [TimeZoneInfo] $Timezone = (Get-Timezone -Id 'UTC'), [Parameter(Mandatory=$False,ValueFromPipeline=$False,ValueFromPipelinebyPropertyName=$True)] [int[]] $TaskId, [Parameter(Mandatory=$False,ValueFromPipeline=$False,ValueFromPipelinebyPropertyName=$True)] [int] $Limit, [Parameter(Mandatory=$False,ValueFromPipeline=$False,ValueFromPipelinebyPropertyName=$True)] [switch] $Successful, [Parameter(Mandatory=$False,ValueFromPipeline=$False,ValueFromPipelinebyPropertyName=$True)] [switch] $Failed, [Parameter(Mandatory=$False,ValueFromPipeline=$False,ValueFromPipelinebyPropertyName=$True)] [switch] $Incomplete ) Begin { Approve-JobSchedulerCommand $MyInvocation.MyCommand $stopWatch = Start-JobSchedulerStopWatch $jobs = @() $orders = @() $folders = @() $historyStates = @() $excludeJobs = @() $taskIds = @() } Process { Write-Debug ".. $($MyInvocation.MyCommand.Name): parameter Directory=$Directory, JobChain=$JobChain Job=$Job" if ( !$Directory -and !$JobChain -and !$Job -and !$TaskId ) { throw "$($MyInvocation.MyCommand.Name): no directory, job chain or job specified, use -Directory, -JobChain, -Job or -TaskId" } if ( $Directory -and $Directory -ne '/' ) { if ( $Directory.Substring( 0, 1) -ne '/' ) { $Directory = '/' + $Directory } if ( $Directory.Length -gt 1 -and $Directory.LastIndexOf( '/' )+1 -eq $Directory.Length ) { $Directory = $Directory.Substring( 0, $Directory.Length-1 ) } } if ( $JobChain ) { if ( (Get-JobSchedulerObject-Basename $JobChain) -ne $JobChain ) # job chain name includes a directory { $Directory = Get-JobSchedulerObject-Parent $JobChain } else { # job chain name includes no directory if ( $Directory -eq '/' ) { $JobChain = $Directory + $JobChain } else { $JobChain = $Directory + '/' + $JobChain } } } if ( $OrderId ) { if ( (Get-JobSchedulerObject-Basename $OrderId) -ne $OrderId ) # order id includes a directory { $Directory = Get-JobSchedulerObject-Parent $OrderId } # order id includes no directory } if ( $Job ) { if ( (Get-JobSchedulerObject-Basename $Job) -ne $Job ) # job name includes a directory { $Directory = Get-JobSchedulerObject-Parent $Job } else { # job name includes no directory if ( $Directory -eq '/' ) { $Job = $Directory + $Job } else { $Job = $Directory + '/' + $Job } } } if ( $Directory -eq '/' -and !$OrderId -and !$JobChain -and !$Job -and !$Recursive ) { $Recursive = $true } if ( $Successful ) { $historyStates += 'SUCCESSFUL' } if ( $Failed ) { $historyStates += 'FAILED' } if ( $Incomplete ) { $historyStates += 'INCOMPLETE' } if ( $JobChain ) { $objOrder = New-Object PSObject Add-Member -Membertype NoteProperty -Name 'jobChain' -value $JobChain -InputObject $objOrder if ( $OrderId ) { Add-Member -Membertype NoteProperty -Name 'orderId' -value $OrderId -InputObject $objOrder } if ( $State ) { Add-Member -Membertype NoteProperty -Name 'state' -value $State -InputObject $objOrder } $orders += $objOrder } if ( $Job ) { $objJob = New-Object PSObject Add-Member -Membertype NoteProperty -Name 'job' -value $Job -InputObject $objJob $jobs += $objJob } if ( !$JobChain -and $Directory ) { $objFolder = New-Object PSObject Add-Member -Membertype NoteProperty -Name 'folder' -value $Directory -InputObject $objFolder Add-Member -Membertype NoteProperty -Name 'recursive' -value ($Recursive -eq $true) -InputObject $objFolder $folders += $objFolder } if ( $ExcludeJob ) { foreach( $excludeJobItem in $ExcludeJob ) { $objExcludeJob = New-Object PSObject Add-Member -Membertype NoteProperty -Name 'job' -value $excludeJobItem -InputObject $objExcludeJob $excludeJobs += $objExcludeJob } } if ( $TaskId ) { $taskIds += $TaskId } } End { # PowerShell/.NET does not create date output in the target timezone but with the local timezone only, let's work around this: $timezoneOffsetPrefix = if ( $Timezone.BaseUtcOffset.toString().startsWith( '-' ) ) { '-' } else { '+' } $timezoneOffsetHours = [Math]::Abs($Timezone.BaseUtcOffset.hours) if ( $Timezone.SupportsDaylightSavingTime -and $Timezone.IsDaylightSavingTime( (Get-Date) ) ) { $timezoneOffsetHours += 1 } [string] $timezoneOffset = "$($timezoneOffsetPrefix)$($timezoneOffsetHours.ToString().PadLeft( 2, '0' )):$($Timezone.BaseUtcOffset.Minutes.ToString().PadLeft( 2, '0' ))" $body = New-Object PSObject Add-Member -Membertype NoteProperty -Name 'jobschedulerId' -value $script:jsWebService.JobSchedulerId -InputObject $body if ( $jobs ) { Add-Member -Membertype NoteProperty -Name 'jobs' -value $jobs -InputObject $body } if ( $excludeJobs ) { Add-Member -Membertype NoteProperty -Name 'excludeJobs' -value $excludeJobs -InputObject $body } if ( $RegEx ) { Add-Member -Membertype NoteProperty -Name 'regex' -value $RegEx -InputObject $body } if ( $DateFrom -or $RelativeDateFrom ) { if ( $RelativeDateFrom ) { if ( $RelativeDateFrom.endsWith( '+TZ' ) ) { $RelativeDateFrom = $RelativeDateFrom.Substring( 0, $RelativeDateFrom.length-3 ) + $timezoneOffset } Add-Member -Membertype NoteProperty -Name 'dateFrom' -value $RelativeDateFrom -InputObject $body } else { Add-Member -Membertype NoteProperty -Name 'dateFrom' -value ( Get-Date (Get-Date $DateFrom).ToUniversalTime() -Format 'u').Replace(' ', 'T') -InputObject $body } } if ( $DateTo -or $RelativeDateTo ) { if ( $RelativeDateTo ) { if ( $RelativeDateTo.endsWith( '+TZ' ) ) { $RelativeDateTo = $RelativeDateTo.Substring( 0, $RelativeDateTo.length-3 ) + $timezoneOffset } Add-Member -Membertype NoteProperty -Name 'dateTo' -value $RelativeDateTo -InputObject $body } else { Add-Member -Membertype NoteProperty -Name 'dateTo' -value ( Get-Date (Get-Date $DateTo).ToUniversalTime() -Format 'u').Replace(' ', 'T') -InputObject $body } } if ( $folders ) { Add-Member -Membertype NoteProperty -Name 'folders' -value $folders -InputObject $body } if ( $Limit ) { Add-Member -Membertype NoteProperty -Name 'limit' -value $Limit -InputObject $body } if ( $historyStates ) { Add-Member -Membertype NoteProperty -Name 'historyStates' -value $historyStates -InputObject $body } if ( $orders ) { Add-Member -Membertype NoteProperty -Name 'orders' -value $orders -InputObject $body } if ( $taskIds ) { Add-Member -Membertype NoteProperty -Name 'taskIds' -value $taskIds -InputObject $body } [string] $requestBody = $body | ConvertTo-Json -Depth 100 $response = Invoke-JobSchedulerWebRequest '/tasks/history' $requestBody if ( $response.StatusCode -eq 200 ) { $returnHistoryItems = ( $response.Content | ConvertFrom-JSON ).history } else { throw ( $response | Format-List -Force | Out-String ) } if ( $Timezone.Id -eq 'UTC' ) { $returnHistoryItems } else { $returnHistoryItems | Select-Object -Property ` jobschedulerId, ` clusterMember, ` taskId, ` job, ` state, ` @{name='startTime'; expression={ ( [System.TimeZoneInfo]::ConvertTimeFromUtc( [datetime]::SpecifyKind( [datetime] "$($_.startTime)".Substring(0, 19), 'UTC'), $Timezone ) ).ToString("yyyy-MM-dd HH:mm:ss") + $timezoneOffset }}, ` @{name='endTime'; expression={ ( [System.TimeZoneInfo]::ConvertTimeFromUtc( [datetime]::SpecifyKind( [datetime] "$($_.endTime)".SubString(0,19), 'UTC'), $($Timezone) ) ).ToString("yyyy-MM-dd HH:mm:ss") + $timezoneOffset }}, ` criticality, ` exitCode, ` @{name='surveyDate'; expression={ ( [System.TimeZoneInfo]::ConvertTimeFromUtc( [datetime]::SpecifyKind( [datetime] "$($_.surveyDate)".SubString(0, 19), 'UTC'), $($Timezone) ) ).ToString("yyyy-MM-dd HH:mm:ss") + $timezoneOffset }} } if ( $returnHistoryItems.count ) { Write-Verbose ".. $($MyInvocation.MyCommand.Name): $($returnHistoryItems.count) history items found" } else { Write-Verbose ".. $($MyInvocation.MyCommand.Name): no history items found" } Trace-JobSchedulerStopWatch $MyInvocation.MyCommand.Name $stopWatch } } |