Print Queue Status Monitor with Email

I have a brand new Windows Server 2012 R2 Datacenter virtual server that is setup as a print server.  I saw the custom filters in the Print Management console but found out that notifications only work with that console open.  Since I'm not logged into that machine all the time, I need a powershell script that can do what the custom filters do in the Print Management console.  Here's what I'm looking for:

1. When the print server starts the script starts.  This script should always stay active.

2. The script polls the print queues for a change in status to anything other than Ready every 5 minutes or so.

3. If the printer name contains "CC2", then email certain people the status of that particular printer.  Only email them once so as to not spam them with constant emails (maybe 1 email per day per status change).

So basically I'm looking to email my customer service department if one of their printers goes to a status of anything other than Ready.  Is something like this possible with Powershell?

January 29th, 2015 5:10pm

Hi James,

yes indeed, that is possible. You may want to consider running this script frequently by task scheduler however, instead of having it run perpetually. If you don't watch your memory usage it may slow down your server over time.

Cheers,
Fred

Free Windows Admin Tool Kit Click here and download it now
January 29th, 2015 5:16pm

Hi James,

yes indeed, that is possible. You may want to consider running this script frequently by task scheduler however, instead of having it run perpetually. If you don't watch your memory usage it may slow down your server over time.

Cheers,

January 29th, 2015 5:21pm

I'm fairly new to Powershell so is there a script already written that can do something like this or maybe a template I could modify?
Free Windows Admin Tool Kit Click here and download it now
January 29th, 2015 5:24pm

[...] but spinning up and tearing down a PS session every few minutes to do something fairly trivial wastes a lot of CPU resource.

Definitely a point to keep in mind.

 

About templates, James:

I don't know - you may want to check the Gallery for that kind of thing. However, I have written a guide you may find helpful if you want to tackle this yourself: Scripting without knowing PowerShell.

Adding to that, you can set up a timer as Mjolinor mentioned by wrapping the script into this:

# This goes before your script:

# Time limit when the script expires
$Limit = (Get-Date).AddDays(1)

# Seconds to wait after each execution
$SleepSeconds = 300

while ((Get-Date) -lt $Limit)
{

    ######################
    # Insert Script here #
    ######################



# This goes at the end of the script:

    # Wait a little before repeating
    Start-Sleep $SleepSeconds
}

Cheers,
Fred

January 29th, 2015 5:50pm

I was thinking of an infinite loop like this:

$SleepSeconds = 300

while ($true)

{

   # Script

   Start-Sleep $SleepSeconds

}

In the task scheduler, I would run the script daily at 6:00am and in the settings I would have these options:

If running task does not end when requested, force it stop.

If the task is already running then the following rule applies:

Stop the existing instance.

I believe this would allow the script to run without expiring and let the task scheduler kill the task and start a new one each day.  Does this seem correct?

Free Windows Admin Tool Kit Click here and download it now
January 29th, 2015 6:16pm

Hi James,

that would certainly work well, however I try not to kill a process if I can have it end naturally without a major effort (And my snippet isn't that much extra effort now, is it? :) )

Cheers,
Fred

January 29th, 2015 6:28pm

Yeah, I think I'll add your limit as a safeguard so if the task scheduler doesn't kill the task it will end on its own. 

Could you point me in the right direction as to where I could find some example scripts of print queue status scripts?

Free Windows Admin Tool Kit Click here and download it now
January 29th, 2015 6:55pm

[...] but spinning up and tearing down a PS session every few minutes to do something fairly trivial wastes a lot of CPU resource.

Definitely a point to keep in mind.

 

About templates, James:

I don't know - you may want to check the Gallery for that kind of thing. However, I have written a guide you may find helpful if you want to tackle this yourself: Scripting without knowing PowerShell.

Adding to that, you can set up a timer as Mjolinor mentioned by wrapping the script into this:

# This goes before your script:

# Time limit when the script expires
$Limit = (Get-Date).AddDays(1)

# Seconds to wait after each execution
$SleepSeconds = 300

while ((Get-Date) -lt $Limit)
{

    ######################
    # Insert Script here #
    ######################



# This goes at the end of the script:

    # Wait a little before repeating
    Start-Sleep $SleepSeconds
}

Cheers,

January 29th, 2015 7:07pm

PS sessions are not expensive.  They start and run verry efficiently.  PS wass designed to be run this way.  Just besure to load with no profile and explicitly load all modules you need,
Free Windows Admin Tool Kit Click here and download it now
January 29th, 2015 10:11pm

I'm looking into this command:

Get-Printer -computername MYSERVER | Where {($_.PrinterStatus -eq "Offline") -and ($_.Name -Match "CC2")} | Select Name,PrinterStatus,Comment,Location,Portname

I'm guessing I need to put that information in an array and save it so I can compare further runs to the saved state and see if any status changes have occurred.  This way the users will only get an email if the status changes and not every 5 minutes when the script loops.  I'm still trying to figure out that part.

January 29th, 2015 10:16pm

Do you know you can have vents emamiled from the eventlog including changes in printer status.  This would be the better way to administer a Windows system.

Find the printer que event IDs and righ click and make a task out of the event.

Free Windows Admin Tool Kit Click here and download it now
January 29th, 2015 10:25pm

PS sessions are not expensive.  They start and run verry efficiently.  PS wass designed to be run this way.  Just besure to load with no profile and explicitly load all modules
January 29th, 2015 10:41pm

That says your system has nothing better to do so you are getting full CPU access.  Windows NT optimizes loads if the CPU is not real busy.  THe overhead is trivial.  If you are staritng it every 5 minutes it will pose no issue.   We do that all the time.  I have processes that can run once a minute.

Free Windows Admin Tool Kit Click here and download it now
January 29th, 2015 10:51pm

Do you know you can have vents emamiled from the eventlog including changes in printer status.  This would be the better way to administer a Windows system.

Find the printer que event IDs and righ click and make a task out of the event.

January 29th, 2015 10:54pm

I recommend searching for printer events

Free Windows Admin Tool Kit Click here and download it now
January 29th, 2015 10:58pm

That says your system has nothing better to do so you are getting full CPU access.  Windows NT optimizes loads if the CPU is not real busy.  THe overhead is trivial.  If you are staritng it every 5 minutes it will pose no issue.   We do that all the time.  I have processes that can run once a minute.

January 30th, 2015 12:04am

That says your system has nothing better to do so you are getting full CPU access.  Windows NT optimizes loads if the CPU is not real busy.  THe overhead is trivial.  If you are staritng it every 5 minutes it will pose no issue.   We do that all the time.  I have processes that can run once a minute.

Free Windows Admin Tool Kit Click here and download it now
January 30th, 2015 1:02am

It's quantified.  That's a start.
January 30th, 2015 1:09am

If you go to performmance school they will teach you that, when you cannot pin the processor by creating a high losd it means that you are runnning out of resources.  ht does "used up" mean.  How fast did you sample.

The basic processor display in W8 and W7 both give poor renditions of processor usage.  Use perfmon on a fast scan to get a more accuratie. view.   What was happenig with memory and disk?  Did any processes or services complain or fail?

When starting fromm the GUI the ssystem throttles the uer I/F so it may see sluggish.  Perf tools do thing lie send commm packets at a high speed to try and measure impact.

Starting a copy of PowerShell ever 5 minutes to do a small query is very trivial.  It has little impact.

I have a small sscript that runs every minute.  It just check a couple of directories.  I buit it as a test a year ago and forgot about it.  It is still running.  I see no eveidence of it and it is on a very slow laptop. (dual core 1.5 mhz w/4gb) Outlook retrieving mail is more disruptive.

I also have VS2013, SQLServer, REprt Server and web server all running and the processor is mmostle at 3% to 6%.  If I start any process the processor pins at 100% for a cople of seconds then returns to normal.  Only notepad has no noticeable impact.

Somewhere on MSDN are some good docs explaining the launch process and how it uses the CPU.

Free Windows Admin Tool Kit Click here and download it now
January 30th, 2015 7:15am

It was, admittedly a "rough" test.  I monitored it using Resource Monitor on W7.  The processor cores went to 100%, physical memory usage to about 35%.  Disk I/O was high but the queue length didn't get over 5 and I suspect most of the reads were from cache.

Nothing crashed or failed, but the UI was totally unresponsive.

January 30th, 2015 2:11pm

It was, admittedly a "rough" test.  I monitored it using Resource Monitor on W7.  The processor cores went to 100%, physical memory usage to about 35%.  Disk I/O was high but the queue length didn't get over 5 and I suspect most of the reads were from cache.

Nothing crashed or failed, but the UI was totally unrespo

Free Windows Admin Tool Kit Click here and download it now
January 30th, 2015 8:07pm

It was, admittedly a "rough" test.  I monitored it using Resource Monitor on W7.  The processor cores went to 100%, physical memory usage to about 35%.  Disk I/O was high but the queue length didn't get over 5 and I suspect most of the reads were from cache.

Nothing crashed or failed, but the UI was totally unrespo

January 30th, 2015 8:22pm

My scripts compares the customer service printers (printer names starting with CC2) status every 5 minutes.  If the status has changed and there are Offline printers then customer service gets an email.  I'm using Task Scheduler to start the script at 6:00am every day and the script will quit around 11:00pm.  It's not very elegant but it will get the job done.  Thanks for all your help!

# Time limit when the script expires
$Limit = (Get-Date).AddDays(1)

$SleepSeconds = 300

$PreviousStatus = @()

while ((Get-Date) -lt $Limit)
{
  $CurrentStatus = Get-Printer -computername SERVER | Where {($_.PrinterStatus -ne "Normal") -and ($_.Name -Match "CC2")} | Select Name,PrinterStatus
  
  if ($CurrentStatus)
  {
     if (Compare-Object $CurrentStatus $PreviousStatus -property Name,PrinterStatus)
     {
       # Establish Connection to SMTP server
       $a = "<style>"
       $a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}"
       $a = $a + "TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;}"
       $a = $a + "TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;}"
       $a = $a + "</style>"
       $filedate = get-date
       $smtpserver = smtp.gmail.com
       $msg = new-object Net.Mail.MailMessage
       $smtp = new-object Net.Mail.SmtpClient($smtpServer )
       $smtp.EnableSsl = $True
       $smtp.Credentials = New-Object System.Net.NetworkCredential(from@nobody.com, password); # Put username without the @GMAIL.com or  @gmail.com
       $msg.IsBodyHtml = $True
       $msg.From = from@nobody.com
       $msg.To.Add(me@nobody.com)
       $msg.To.Add(cserve1@nobody.com)
       $msg.To.Add(cserve2@nobody.com)
       $msg.To.Add(cserve3@nobody.com)
       $msg.To.Add("cserve4@nobody.com")
       $msg.Subject = "Printer Status Errors $($filedate)"
       $msg.Body = Write-Output -InputObject (Get-Printer -computername SERVER |  Where {($_.PrinterStatus -ne "Normal") -and ($_.Name -Match "CC2")} | Select Name,PrinterStatus,Comment,Location,Portname) | ConvertTo-Html -Head $a 
       $smtp.Send($msg)
       
       $PreviousStatus = $CurrentStatus
     }
  }

  Start-Sleep -Seconds $SleepSeconds
  if ((get-date).Hour -eq 23) {Exit}
}

Free Windows Admin Tool Kit Click here and download it now
January 30th, 2015 9:03pm

It was, admittedly a "rough" test.  I monitored it using Resource Monitor on W7.  The processor cores went to 100%, physical memory usage to about 35%.  Disk I/O was high but the queue length didn't get over 5 and I suspect most of the reads were from cache.

Nothing crashed or failed, but the UI was totally unrespo

January 30th, 2015 9:06pm

You can still just schedule it to run every 5 minutes.  That would be safer and easier to manage as you could update the script and it would run next time.

You script will also only test one pronter and fail if there is more than one matching the name.

Free Windows Admin Tool Kit Click here and download it now
January 30th, 2015 9:08pm

It also gave me some approximate metrics on "trivial".
January 30th, 2015 9:09pm

Here is an approach that can be scheduled ever 5 minutes.  It is unnoticeable when it runs a  scheduled task.

If you want better performance then we would place the status in the registry instead of in files

# constants
$laststatusfile = 'c:\temp\laststatus.clixml'
$currentstatusfile = 'c:\temp\currentstatus.clixml'
$server = 'server'
$style = @'
    <style>
        TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}
        TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;}
        TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;}
    </style>
'@

$mailprops = @{
    Smtpserver = 'smtp.gmail.com'
    UseSSL = $true
    Credentials = $creds
    IsBodyHtml = $true
    From = 'from@nobody.com'
    To = 'me@nobody.com', 'cserve1@nobody.com', 'cserve2@nobody.com', 'serve3@nobody.com', 'cserve4@nobody.com'
    Subject = "Printer Status Errors $($filedate)"
}

# persist
Get-Printer CC2* -computername $server | Export-Clixml $currentstatusfile

# conditionally import the last status
$PreviousStatus=Import-Clixml $laststatusfile -ea 0

if($PreviousStatus){
    
    $CurrentStatus = Import-Clixml $currentstatusfile

    if (Compare-Object $CurrentStatus $PreviousStatus -property Name, PrinterStatus) {
        $body = Get-Printer CC2*-computername $server | 
            Where{ $_.PrinterStatus -ne 'Normal' } |
            Select Name, PrinterStatus, Comment, Location, Portname |
            ConvertTo-Html -Head $style |
            Out-String
        Send-MailMessage @mailprops -Body $body
    }

    Remove-Item $laststatusfile
    Rename-Item $currentstatusfile $laststatusfile
}

Even if you don't want to use it it shows some better methods for coding this kind of thing.

Free Windows Admin Tool Kit Click here and download it now
January 30th, 2015 9:51pm

Using some of jrv's code, I trimmed down my script.  I like putting the static variables outside the loop since there's no need to have reset inside the loop.

# Time limit when the script expires
$Limit = (Get-Date).AddDays(1)

# Sleep Time
$SleepSeconds = 300

# Previous Status array
$PreviousStatus = @()

$server = "SERVER"
$smtpserver = smtp.gmail.com

$style = @"
    <style>
        TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}
        TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;}
        TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;}
    </style>
"@

$secpasswd = ConvertTo-SecureString "Password" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential("nobody@nowhere.com",$secpasswd)

$mailprops = @{
    Smtpserver = "smtp.gmail.com"
    UseSSL = $true
    Credential = $cred
    BodyAsHtml = $true
    From = "nobody@nowhere.com"
    To = "me@nowhere.com", "cserve1@nowhere.com"
}

while ((Get-Date) -lt $Limit)
{
  $CurrentStatus = Get-Printer CC2* -computername $server | Where {($_.PrinterStatus -ne "Normal")} | Select Name, PrinterStatus, Comment, Location, Portname
  
  if ($CurrentStatus)
  {
     if (Compare-Object $CurrentStatus $PreviousStatus -property Name,PrinterStatus)
     {
       # Establish Connection to SMTP server
       $body = $CurrentStatus | ConvertTo-Html -Head $style | Out-String
       $subject = "Printer Status Errors $(get-date)"
       Send-MailMessage @mailprops -Body $body -Subject $subject
       
       $PreviousStatus = $CurrentStatus
     }
  }

  Start-Sleep -Seconds $SleepSeconds
  if ((get-date).Hour -eq 23) {Exit}
}


January 31st, 2015 12:32am

I am glad you found it useful.

Free Windows Admin Tool Kit Click here and download it now
January 31st, 2015 12:52am

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics