A few months ago I published a post about how to find the jobs in the Project Server queue programmatically. In the current post I will show you, how can you use PowerShell to track the number of jobs in queue, and send an e-mail alert, if the count is higher than a predefined limit for a longer period. Although the example in this post is Project Server specific, you can use the same technique to create other types of alerts as well.
Since the PowerShell script will be run by Windows Task Scheduler (for example on a 5-minute schedule) it was an important question, how to solve the communication between the runs. For example, how the current session can find out, since when the counter is higher than the limit? Of course, if the limit is reached, and we have already sent a mail, we would not like to send further mails for every and each runs till the counter is higher than the limit. But how to inform the forthcoming sessions from the current session, that we have sent a mail? Of course, there are many possible solutions for this problem. We could use a database, or a file (either XML or any custom format) to persist the information between the sessions. I’ve chosen an even simpler approach. I’ve create empty files (QueueLimitReached.txt and MailSent.txt), and check their existence and / or creation date to check when the limit has been reached and if the alert mail has been already sent. If the counter goes below the limit again, I simply delete these semaphore files.
Having this background, the script itself should be already straightforward.
- Add-PSSnapin "Microsoft.SharePoint.PowerShell"
- $folderPath = "D:\ScheduledTasks\"
- $limitReachedFileName = "QueueLimitReached.txt"
- $mailSentFileName = "MailSent.txt"
- $ageOfFileLimit = 15 # in minutes
- $counterValueLimit = 50
- $emailTo = "admins@company.com"
- $emailCc = "helpdesk@company.com;projmans@company.com"
- $emailSubject = "Project Server Queue Alert"
- $emailBody = @"
- Hi,
- the count of the jobs in the Project Server Queue is very high. Please, fix the issue!
- Regards,
- The PowerShell Monitor
- "@
- $limitReachedFilePath = $folderPath + $limitReachedFileName
- $mailSentFilePath = $folderPath + $mailSentFileName
- function HasAlertState()
- {
- $counter = Get-Counter -Counter "\ProjectServer:QueueGeneral(_Total)\Current Unprocessed Jobs"
- $counterValue = $counter.CounterSamples[0].CookedValue
- return ($counterValue -gt $counterValueLimit)
- }
- function SendAlert()
- {
- $globalAdmin = New-Object Microsoft.SharePoint.Administration.SPGlobalAdmin
- $smtpMail = New-Object Net.Mail.MailMessage
- $smtpMail.From = $globalAdmin.MailFromAddress
- $smtpMail.Subject = $emailSubject
- $smtpMail.Body = $emailBody
- $emailTo.Split(";") | % { $mailAddr = New-Object Net.Mail.MailAddress($_); $smtpMail.To.Add($mailAddr) }
- $emailCc.Split(";") | % { $mailAddr = New-Object Net.Mail.MailAddress($_); $smtpMail.Cc.Add($mailAddr) }
- $smtpMail.ReplyTo = New-Object Net.Mail.MailAddress($globalAdmin.MailReplyToAddress)
- $smtpMail.BodyEncoding = [System.Text.Encoding]::GetEncoding($globalAdmin.MailCodePage)
- $smtpMail.SubjectEncoding = [System.Text.Encoding]::GetEncoding($globalAdmin.MailCodePage)
- $smtpClient = New-Object Net.Mail.SmtpClient($globalAdmin.OutboundSmtpServer)
- $smtpClient.Send($smtpMail)
- }
- $alertCondition = HasAlertState
- If ($alertCondition)
- {
- If (Test-Path $limitReachedFilePath)
- {
- $creationTime = (Get-ChildItem $limitReachedFilePath).CreationTime
- $ageOfFile = ([DateTime]::Now – $creationTime).Minutes
- Write-Host $ageOfFile
- If ($ageOfFile -gt $ageOfFileLimit)
- {
- Write-Host Limit reached
- If (-not (Test-Path $mailSentFilePath))
- {
- Write-Host Mail has not yet been sent. Send it now.
- SendAlert
- # suppress return value via casting it to null
- [void] (New-Item -name $mailSentFileName -path $folderPath -itemType File)
- }
- }
- }
- # create a new file, if no former one exists
- else
- {
- If (-not (Test-Path $limitReachedFilePath))
- {
- # suppress return value via casting it to null
- [void] (New-Item -name $limitReachedFileName -path $folderPath -itemType File)
- }
- }
- }
- # delete the former files, if they exist
- Else
- {
- If (Test-Path $limitReachedFilePath)
- {
- Remove-Item $limitReachedFilePath
- }
- If (Test-Path $mailSentFilePath)
- {
- Remove-Item $mailSentFilePath
- }
- }
In the sample we check the value of the Current Unprocessed Jobs counter of Project Server. You can easily change the limit of job count (50), and the time period (15 minutes) in the code, or customize the addressees, subject and body of the mail. If you would like to create other types of alerts, you should simply implement your own version of the HasAlertState method.
