Examples/Send-PendingJobAlerts.ps1

# Monitor the jobs in all folders of Orch1: Drive and Orch2: Drive every 15 minutes, and
# if there are any jobs that have been Pending for more than 15 minutes, notify via email.


# HashSet to store the IDs of jobs that have already been notified
$notifiedJobIds = [System.Collections.Generic.HashSet[string]]::new()

# Create an Outlook instance outside the loop to be reused for sending emails
$outlook = New-Object -ComObject Outlook.Application

function Write-TimestampedMessage {
    param(
        [Parameter(Mandatory=$true)]
        [string]$Message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    Write-Host "[$timestamp] $Message"
}

try {
    while ($true) {
        Write-TimestampedMessage "Retrieving Jobs from Orchestrator..."

        # You can specify the folders you want to monitor with the Path parameter
        $jobs = Get-OrchJob -Path Orch1:\,Orch2:\ -Recurse -State Pending

        # Display all current pending jobs
        if ($jobs -and $jobs.Count -gt 0) {
            $pendingJobsString = $jobs | Out-String
            Write-TimestampedMessage "Current pending job(s):`n$pendingJobsString"
        } else {
            Write-TimestampedMessage "No pending jobs found."
        }

        # Detect jobs that have been pending for over 15 minutes and not yet notified
        $stuckJobs = $jobs | Where-Object {
            $_.CreationTime.ToLocalTime() -le (Get-Date).AddMinutes(-15) -and
            -not $notifiedJobIds.Contains($_.OrchDirectory + '\' + $_.Id)
        }

        if ($stuckJobs -and $stuckJobs.Count -gt 0) {
            $stuckJobsString = $stuckJobs | Out-String
            Write-TimestampedMessage "Job(s) have been pending for over 15 minutes. Preparing to send notification email..."

            $mail = $outlook.CreateItem(0)
            $mail.To = "you@example.com"
            $mail.Subject = "UiPathOrch Alert: Stuck job(s) detected!"
            $mail.Body = "The following job(s) have been pending for more than 15 minutes:`n$stuckJobsString"
            $mail.Send()

            # Add notified job IDs to HashSet without printing the result
            $stuckJobs | ForEach-Object { $null = $notifiedJobIds.Add($_.OrchDirectory + '\' + $_.Id) }

            Write-TimestampedMessage "Notification email sent."
        }

        # Display the IDs of jobs that have been notified
        if ($notifiedJobIds.Count -gt 0) {
            $sortedNotifiedJobs = $notifiedJobIds | Sort-Object
            $notifiedJobsString = $sortedNotifiedJobs -join ', '
            Write-TimestampedMessage "Job(s) notified so far: $notifiedJobsString"
        }

        Write-TimestampedMessage "Waiting for 15 minutes before the next check..."
        Start-Sleep -Seconds 900
    }
} catch {
    Write-TimestampedMessage "An error occurred: $($_.Exception.Message)"
} finally {
    [System.Runtime.InteropServices.Marshal]::ReleaseComObject($outlook) | Out-Null
    [GC]::Collect()
    [GC]::WaitForPendingFinalizers()
}