1

I wrote a script to check for Windows Services that are in a hung state and send an email to the user accordingly with the subject line.

  • I want to send the email with an image or table data consisting of the Server Name, Service Name, Service Start Type, and Service Status, but right now I am able to send the email with just the body text.

How can I send the email with the data consisting of the Server Name, Service Name, Service Start Type, and Service Status as a table in the below format? enter image description here

#AUTHOR: Chandrakanth Reddy
#DATE: 8/15/2021

#Email Details
$FromAddress = 'XYZ.com'
$ToAddress = 'XYZ.com'
$SmtpServer = 'ABC.com'

#Machine to be monitored
$Computer = "XXXX"

#Create a subset of the previous array for services you want to monitor
$ServiceName = "WSearch"

Foreach ($ServerName in $Computer) {
  Foreach ($Service in $ServiceName) {
    #Get current status
      $CurrentStatus = Get-Service -Name $ServiceName -ComputerName $Computer #| Where-Object { $_.Status -eq "StartPending" }

      if ($_.Status -eq "StartPending") {
        #$CurrentStatus = 'StartPending'

        If (($FromAddress) -And ($SmtpServer)) {
          $msgBody = $ServiceName + " " + "Windows Service is" + " " + $CurrentStatus +" " + "on" + " " + $Computer
          Send-MailMessage -from $FromAddress -to $FromAddress -SmtpServer $SmtpServer -Subject "$Computer - $ServiceName Windows Service is in Hung state '$CurrentStatus' " -BodyAsHtml $msgBody
        }
      }
      elseif ($_.Status -eq "StopPending") {
        #$CurrentStatus = 'StopPending'

        If (($FromAddress) -And ($SmtpServer)) {
          $msgBody = $ServiceName + " " + "Windows Service is" + " " + $CurrentStatus +" " + "on" + " " + $Computer
          Send-MailMessage -from $FromAddress -to $ToAddress -SmtpServer $SmtpServer -Subject "$Computer $ServiceName is not running" -BodyAsHtml $msgBody
        }
      }
      elseif ($_.Status -eq 'Running' -or $_.Status -eq 'Stopped' -or $_.Status -eq 'ContinuePending') {
        Exit
      }
  }
}
Exit
8
  • 1
    What is the question?
    – harrymc
    Commented Aug 14, 2021 at 7:56
  • I want to send the email with an image or table format of data consist of the Server name, Service name, Service Start Type, Service Status.
    – chandu
    Commented Aug 14, 2021 at 7:57
  • 1
    You wrote a script for that, so far so good. Now do you have a specific question for us?
    – harrymc
    Commented Aug 14, 2021 at 7:59
  • Right now i am able to send the email with just the body text. My question is like how can i send the email with the data consist of the Server name, Service name, Service Start Type, Service Status as a table format
    – chandu
    Commented Aug 14, 2021 at 8:01
  • Try piping your data to Format-Table. Commented Aug 14, 2021 at 9:04

1 Answer 1

1

As commented, your current code sends an email for every service from the list on every computer from the array of computernames.

I would suggest gathering all info needed as an array of objects and use ConvertTo-Html on that data to create a nice HTML table from it.

Using a Here-String as body HTML template, you can set the style to color the table the way you want.

Since both the -Name and -ComputerName parameters of Get-Service can take an array of names, your code can be condensed like below:

$machines = 'XXX', 'YYY'           # array of computernames to check
$services = 'WSearch','SENS'       # array of services to check

$result = Get-Service -Name $services -ComputerName $machines | 
        Where-Object { $_.Status -match '(Start|Stop)pending' } |
        # output objects to be collected in $result
        Select-Object @{Name = 'Server name'; Expression = {$_.MachineName}},
                      @{Name = 'Service name'; Expression = {$_.Name}},
                      @{Name = 'Service Start Type'; Expression = {$_.StartType}},
                      @{Name = 'Service Status'; Expression = {$_.Status}}


# only send an email if there is something to alert (found services in 'StartPending' and/or 'StopPending' state)
# the @() is needed to force $result to be an array even if it has only one item
if (@($result).Count) {
    # convert the resulting array of objects into a HTML table
    $table = ($result | Sort-Object 'Server name' | ConvertTo-Html -Fragment) -join [environment]::NewLine

    # create a HTML template for the email using a Here-String
    $htmlTemplate = @"
<html><head>
<style>
    body, table {font-family: sans-serif; font-size: 10pt; color: #000000;}
    table {border: 1px solid white; border-collapse: collapse;}
    th {border: 1px solid white; background: #0000af; padding: 3px; color: #ffffff;}
    td {border: 1px solid white; padding: 3px; color: #000000;}
</style>
</head><body>
Pending services.<br />
@@TABLE@@
<br />
</body></html>
"@

    # create a Hashtable to splat the parameters to Send-MailMessage
    $mailParams = @{
        From       = '[email protected]'
        To         = '[email protected]'
        Subject    = 'Services not running {0:yyyy-MM-dd}' -f (Get-Date)
        SmtpServer = 'ABC.com'
        Body       = $htmlTemplate -replace '@@TABLE@@', $table
        BodyAsHtml = $true
    }

    # send the email
    Send-MailMessage @mailParams
}
else {
    Write-Host "No services found that were in StartPending or StopPending state. No email was sent." -ForegroundColor Green
}

If, as you commented, you would like to show all but two of the possible service states (ContinuePending, Paused, PausePending, Running, StartPending, Stopped, StopPending)
for all services on a collection of servers, you could change the above to:

$machines = 'XXX', 'YYY'           # array of computernames to check
$result = Get-Service -ComputerName $machines | 
        Where-Object { $_.Status -notmatch 'Running|Stopped' } |
        # output objects to be collected in $result
        Select-Object @{Name = 'Server name'; Expression = {$_.MachineName}},
                      @{Name = 'Service name'; Expression = {$_.Name}},
                      @{Name = 'Service Start Type'; Expression = {$_.StartType}},
                      @{Name = 'Service Status'; Expression = {$_.Status}}
3
  • Thanks @Theo , the above script is working as expected
    – chandu
    Commented Aug 17, 2021 at 7:46
  • i have a one question related to the above script, right now i am only checking for the one service, if i want to check for all the services from multiple severs which are in the below states, how can i do that, can you please suggest. 1 - service paused 2 - service starting (start pending) 3 - service pausing (pause pending) 4 - service starting after pause (continue pending) 5 - service stopping (stop pending)
    – chandu
    Commented Aug 18, 2021 at 8:03
  • @chandu Please see the edit on my answer.
    – Theo
    Commented Aug 18, 2021 at 12:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .