Triggering Cmdlet with Output

Hi Guys. Have used Powershell for various things by Googling the scripts, but just getting into figuring out how to do things myself with an eye to automating tasks. Anyway, I wanted to start off with something simple, so a while ago we had an issue with the print spooler service stopping at random on some terminal servers. While I was looking for the cause it’d be great if I could set something up to automatically restart it when it stopped. Easy enough:

$Serv = 'Server1','Server2','Server3'
Get-Service -Name Spooler -ComputerName -$Serv | Where {$_.Status -eq "Stopped"} | Start-Service

But then I wanted to know the frequency it was happening and on which servers, so I want it to notify me any time it finds a stopped service and restarts it. Sounds straight forward, right? I can have it check the status and write the machine name of any it finds to a csv file. Then I can have it send a mail to me with that csv file attached. But… how can I trigger the email? I don’t want it to send me an email if it finds no stopped services, only if one is stopped.
My first thought is to use the If function. If cmdlet A gets an output then activate cmdlet B. Below is my attempt to put that into action. My problem is I need to use a comparison operator with the If function and none of them really match what I need. I need it to simply check if there is any output from the cmdlet, and if there is then jump into the follow up cmdlet. If there’s no output, then no action necessary.

So my question is - is this possible? Either through the If function or through another means of triggering the email?

$Serv = 'server1','server2','server3'

$CHECKSPOOLER = get-service -name spooler -ComputerName $Serv | Where {$_.Status -eq "Stopped" }

#Check status and write output to CSV in case it needs to be emailed
get-service -name spooler -ComputerName $Serv | where {$_.Status -eq "Stopped" } | select -Property 'name','machinename','status' | export-csv -Path c:\temp\spoolerexport.csv

#Check if an email is required and trigger the email
If ($CHECKSPOOLER -eq $true) {
Send-MailMessage -To email1@domain.com -From email2@domain.com -Subject Spooler service started -Attachments "C:\temp\spoolerexport.csv" -SmtpServer 1.1.1.1
}

#Now that we've determined if an email is needed, fix the stopped service!
get-service -name Spooler -ComputerName $Serv | Where {$_.Status -eq "Stopped" } | start-service

I’ve take what you’ve already done above and tweaked it a bit to answer your question.

$Servers = 'server1','server2','server3'

Foreach ($server in $servers) {

    $CHECKSPOOLER = get-service -name spooler -ComputerName $Server | Where-Object {$_.Status -eq "Stopped" } 
    $CHECKSPOOLER | Select-Object -Property 'name','machinename','status' | export-csv -Path c:\temp\spoolerexport.csv
    If ($CHECKSPOOLER) {
        Send-MailMessage -To email1@domain.com -From email2@domain.com -Subject "Spooler service started" -Attachments "C:\temp\spoolerexport.csv" -SmtpServer 1.1.1.1
        get-service -name Spooler -ComputerName $Server | start-service
    }

}

 

I would chase down the root cause of the spooler service stopping.

I would also configure the service recovery options which can be set to restart the service when/if it stops

Finally, you may want to run this script in a loop to check and restart the spooler service every 5 or so minutes, or have it run every 5 minutes as a scheduled task,…

 

I second Sam’s response. The service should be setup for recovery. Obviously, you want data on when something failed so that you can look at event logs during that date\time. My guess is printer driver. :slight_smile:

Personally, the last thing I need is more emails, so I’d only want a report if there was an issue on any of the servers. This logic (not tested) would only send an email if a spooler service was stopped on one of the servers with the datetime and the status of the restart. You can run it every 5, 15, 30 minutes or whatever you like:

$Servers = 'server1','server2','server3'

$results = foreach ($server in $servers) {

    $spool = Get-Service -Name spooler -ComputerName $Server | 
             Where-Object -FilterScript { $_.Status -eq "Stopped" } 
    
    if ( $spool ) {
        try {
            $spool |
            Start-Service -ErrorAction Stop

            $spool | Select-Object -Property Name, 
                                             MachineName, 
                                             Status, 
                                             @{Name='Message';Expression={'Successfully restarted spooler @ {0}' -f (Get-Date)}}
        }
        catch {
            $spool | Select-Object -Property Name, 
                                             MachineName, 
                                             Status, 
                                             @{Name='Message';Expression={'Failed restarting spooler @ {0}. {1}' -f (Get-Date), $_}}
        }
    }
}

if ( $results ) {

    $body = $results | ConvertTo-Html -Title 'Spooler Report'

    $mailParams = @{
        To         = 'email1@domain.com' 
        From       = 'email2@domain.com' 
        Subject    = "Spooler Report" 
        SmtpServer = 1.1.1.1
        BodyAsHtml = $true
        Body       = $body | Out-String
    }

    Send-MailMessage @mailParams

}

Hi Guys, thanks for your responses! Rest assured I wasn’t pursuing this as a fix, we did resolve the underlying issue (yep, was a driver), just presented a good and easy to test idea to get the hang of powershell.

Based on the suggested scripts it looks like my error was in believing “If” required a comparison operator. You’ve both used just the variable to check for the presence of output, so that was easy.

Thanks again!

Yes, basically…

if ( $results ) {..

is shorthand for

if ($test -ne $null) {"Do something"}

Glad you figured out your driver issue.