Windows Service Status Report

Solution 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}}