Monitor list of services , restart if any stopped, send email alert for the restarted service

I am trying to create a powershell script that will run as a job to monitor a group of service in Windows.

If any of the monitored service stop

Restart it

Send an email alert with date, time and the name of the restarted service.

If no service is stopped do not send any alert

Below is the code I have. It works when any of the service is stopped.

But it sends separate email for each failed service.

It still sends email when all the service are running.

Need assistance or suggestions.

Thanks in advance

##################################################################################################################################

$today=(Get-Date).ToString()
$reportpath="c:\temp\report.html"
$ReportTitle="Service status alert $today"
$computers= $ENV:Computername
$services="Spooler", "W3svc","StorSvc"

$from="servicealert@mail.com
$to="joeDoe@email.com
$smtpserver="mail.server.com"

TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}
TH{border-width: 1px;padding: 5px;border-style: solid;border-color: black;color:black;background-color:#0BC68D;text-align:center;}
TD{border-width: 1px;padding: 5px;border-style: solid;border-color: black;text-align:center;}
</style>
"@

#######*********** ATTEMP TO Start the services when found not runnig,if they are very important to be running.

$array = @()
Foreach($service in $services) {
Get-Service $service -ComputerName $computer -ea "0" | ForEach {
If($_.Status -eq "Stopped") {
$obj = New-Object psobject -Property @{
ComputerName = $computer
DisplayName=$_.displayname
Name = $_.name
Status =$_.status
}

$array += $obj

#Start the service
Start-Service -Name $_.Name
Start-Sleep -Seconds 10

}


}

}

$array | Select Computername,displayname,name,status | ConvertTo-Html -property 'ComputerName','Displayname','Name','Status' -head $Style -building "<h1> $ReportTitle </h1>" | foreach {if($_ -like "*<td>Running</td>*"){$_ -replace "<tr>", "<tr bgcolor=#089437>"} elseif($_ -like "*<td>Stopped</td>*" -or "*<td>Stopping</td>*" -or "*<td>Pending</td>*" -or "*<td>Starting</td>*"){$_ -replace "<tr>", "<tr bgcolor=#C60B1C>"} else{$_}} |out-file $reportpath


$body1 = [System.IO.File]::ReadAllText("$reportpath")
$body2 = "The stopped service was restarted"
$building = "$body1`n`"$body2"

Send-MailMessage -To $to -From $from -Subject "Service Restart Alert" -building $building -BodyAsHtml -SmtpServer $smtpserver

$array = $null

  • No reason to do this from scratch, except as a learning exercise. Yet, this becomes a use, buy or build thought process. The latter means you have to fully document and maintain this an all that entails forever.

    For Windows Service monitoring...

    Then the are enterprise solutions for this like System Center Operations manager, PowerShell DSC and even pre-built scritps for you to use and tweak as needed.

    Use PowerShell to monitor Windows services

    This script is used to monitor services. The script will restart the service(s) three times with the third time also generating an email message to a list of users. The script will also insure that the service(s) is set to Autostart. The script can be ran as a scheduled task. The issue should be investigated if the service fails to start after the third attempt

    'gallery.technet.microsoft.com/scriptcenter/Use-PowerShell-to-monitor-0c1974a9'

    As for ...

    ---

    I am trying to create a PowerShell script that will run as a job to monitor a group of service in Windows.

    If any of the monitored service stop

    ---

    Another centralized way of doing this my be more prudent here.

    1 - Use Group Policy Preferences for this, auto-restart service thing.

    2 - Use a WMI event consumer to alert on that and fire off an script alert. This why you are responding to the actual event vs just the service state.

    This way you have an enterprise defined way of executing on the sort of effort.

    As for

    ---

    But it sends separate email for each failed service.

    It still sends email when all the service are running.

    ---

    It should because that is what you are telling it to do.

    Which is why you should key on the failed or started event vs service state.

    If you don't want messages for all services, then you need to trap for all failed / stopped services, collect those in a variable, use that collection to start them and report on the collection, not all services states on the system.

  • Fixed the issue. Got what I needed. Below is the script for anyone to improve

    $today=(Get-Date).ToString()
    $reportpath="c:\temp\report.html"
    $ReportTitle="Service status alert $today"
    $computers= $ENV:Computername
    $services="Spooler", "W3svc","StorSvc"

    $from="servicealert@mail.com
    $to="joeDoe@email.com
    $smtpserver="mail.server.com"

    TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}
    TH{border-width: 1px;padding: 5px;border-style: solid;border-color: black;color:black;background-color:#0BC68D;text-align:center;}
    TD{border-width: 1px;padding: 5px;border-style: solid;border-color: black;text-align:center;}
    </style>
    "@

    #######*********** ATTEMP TO Start the services when found not runnig,if they are very important to be running.

    $array = Foreach($service in $services) {
                Get-Service $service -ComputerName $computer |Where-Object {$_.Status -eq "Stopped"} | Select-Object MachineName, Name, DisplayName, Status
                Start-Service $service -ErrorAction Stop
            }


    If([string]::IsNullOrEmpty($array)){
    }


    Else {  
        $array | Select Computername,displayname,name,status | ConvertTo-Html -property 'ComputerName','Displayname','Name','Status' -head $Style -building "<h1> $ReportTitle </h1>" | foreach {if($_ -like "*<td>Running</td>*"){$_ -replace "<tr>", "<tr bgcolor=#089437>"} elseif($_ -like "*<td>Stopped</td>*" -or "*<td>Stopping</td>*" -or "*<td>Pending</td>*" -or "*<td>Starting</td>*"){$_ -replace "<tr>", "<tr bgcolor=#C60B1C>"} else{$_}} |out-file $reportpath
        $body1 = [System.IO.File]::ReadAllText("$reportpath")
        $body2 = "The stopped service was restarted"
        $building = "$body1`n`"$body2"
        Send-MailMessage -To $to -From $from -Subject "Service Restart Alert" -building $building -BodyAsHtml -SmtpServer $smtpserver
        }

    $array = $null