Pull Servers in an OU uptime and e-mail if more than one day

I can get it to work against one server but now I need it to work against all servers in one OU.

$servers = Get-ADComputer -SearchBase ‘OU=Servers,DC=COMPANY,DC=COM’ -Filter ‘SamAccountName -like “ntprocps*”’ | Select-Object -Expand Name
Foreach ($servers in $servers) {

$wmiobjs = Get-WmiObject -Class win32_operatingsystem -Property CSName,LastBootupTime -ComputerName $Servers
$time = $wmi.ConvertToDateTime($wmi.lastbootuptime)
[TimeSpan] $uptime = New-TimeSpan $time $(get-date)

If ($uptime.Hours -gt 1)
{Send-MailMessage -From monitor@company.com -Subject “Server Uptime” -To kelly.farrell@company.com -Body "server didn’t reboot - $uptime " -SmtpServer exchange.internal.company.com}

THIS IS THE ONE THAT WORKS
Get-CimInstance -ComputerName server -ClassName win32_operatingsystem -Property * | select csname, lastbootuptime

$wmi = Get-WmiObject -Class Win32_OperatingSystem -Computer server
$time = $wmi.ConvertToDateTime($wmi.lastbootuptime)
[TimeSpan] $uptime = New-TimeSpan $time $(get-date)

If ($uptime.days -gt 1)

{Send-MailMessage -From monitor@company.com -Subject “Server Uptime” -To kelly.farrell@company.com -Body "server didn’t reboot - $uptime " -SmtpServer exchange.internal.company.com}

Hi Kelly,

First thing I notice when looking at your script, is your foreach loop.
You do foreach $servers (plurral):

foreach ($servers in $servers) { ... code here ... }

Where I expect you would want to do foreach $server (singular):

foreach ($server in $servers) { ... code here ... }

Further to that, you miss a closing curly brace in your foreach loop (might just be a copy/paste error), and you store your WMI object in $wmiobjs, but refor to $wmi when trying to read the data afterwards

This slightly modified version of your own script might do what you are after (beware: untested)

$servers = Get-ADComputer -SearchBase 'OU=Servers,DC=COMPANY,DC=COM' -Filter 'SamAccountName -like "ntprocps*"' | Select-Object -ExpandProperty Name

foreach ($server in $servers)
{
    $wmi = Get-WmiObject -Class win32_operatingsystem -Property CSName,LastBootupTime -ComputerName $server
    $time = $wmi.ConvertToDateTime($wmi.lastbootuptime)
    [TimeSpan] $uptime = New-TimeSpan $time $(get-date)

    if ($uptime.days -gt 1)
    {
        Send-MailMessage -From monitor@company.com -Subject "Server Uptime" -To kelly.farrell@company.com -Body "server didn't reboot – $uptime " -SmtpServer exchange.internal.company.com
    }
}

thanks that worked - appreciate your help

If you wanted to get a SINGLE email with all of the servers that met your criteria, you could reformat it a bit like below. Also, if you are connecting to servers, especially that could be in the middle of a reboot cycle, you need to test the connection and do error handling on WMI. Take a look at this example (not tested):

$servers = Get-ADComputer -SearchBase 'OU=Servers,DC=COMPANY,DC=COM' -Filter 'SamAccountName -like "ntprocps*"' | Select-Object -Expand Name

$results = foreach ($server in $servers) {
    if (Test-Connection -ComputerName $server -Count 2 -Quiet) {
        try {
            $os = Get-WmiObject -Class win32_operatingsystem -Property LastBootupTime -ComputerName $server -ErrorAction Stop |
            Select CSName, @{Name="UpTimeHours";Expression={(New-TimeSpan -Start $_.ConvertToDateTime($_.lastbootuptime) -End $(Get-Date)).Hours}}
            
            $uptime = $os | Select -ExpandProperty UpTimeHours
            $msg = $null

        }
        catch {
            $uptime = $null
            $msg = "WMI Failure. {0}" -f $_.Exception.Message
        }

 
    }
    else {
        $uptime = $null
        $msg = "Server offline. Ping failure."
    }

    $props = @{
        ComputerName  = $server;
        UpTimeInHours = $uptime;
        Message       = $msg;
    }

    New-Object -TypeName PSObject -Property $props
}

$serversNoReboot = $results | Where{$_.UpTimeInHours -ge 1}

if ($serversNoReboot) {
    $serversNoRebootHTML = $serversNoReboot | Select ComputerName, UpTimeInHours |  ConvertTo-HTML -Head "Server Reboot Failure"
    
    $mailParams = @{
        To = "kelly.farrell@company.com"
        From = "monitor@company.com"
        Subject = "Server Uptime"
        Body = $serversNoRebootHTML 
        SmtpServer = "exchange.internal.company.com"
    }
    
    Send-MailMessage @mailParams
}

I tried that but I get this:

Send-MailMessage : Cannot convert ‘System.Object[]’ to the type ‘System.String’
required by parameter ‘Body’. Specified method is not supported.
At C:\Users\kefarrell\Documents\Scripts\reboot-citrix-servers.ps1:47 char:22

  • Send-MailMessage @mailParams
    
  •                  ~~~~~~~~~~~
    
    • CategoryInfo : InvalidArgument: (:slight_smile: [Send-MailMessage], Parameter
      BindingException
    • FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Command
      s.SendMailMessage

I think the issue is Line 43 should be BodyAsHtml = $serversNoRebootHTML

darn now I’m getting -

PS C:\Windows\system32> C:\Users\kefarrell\Documents\Scripts\reboot-email-test.ps1
Send-MailMessage : Cannot convert ‘System.Object[]’ to the type
‘System.Management.Automation.SwitchParameter’ required by parameter
‘BodyAsHtml’.
At C:\Users\kefarrell\Documents\Scripts\reboot-email-test.ps1:47 char:22

  • Send-MailMessage @mailParams
    
  •                  ~~~~~~~~~~~
    
    • CategoryInfo : InvalidArgument: (:slight_smile: [Send-MailMessage], Parameter
      BindingException
    • FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Command
      s.SendMailMessage

bodyashtml is a switch. body is a string

$serversNoRebootHTML = $serversNoReboot | Select ComputerName, UpTimeInHours | ConvertTo-HTML -Head “Server Reboot Failure” | out-string

$mailParams = @{
To = ‘kelly.farrell@company.com’
From = ‘monitor@company.com’
Subject = ‘Server Uptime’
Body = $serversNoRebootHTML | Out-String
SmtpServer = ‘exchange.internal.company.com
BodyAsHtml = $true
}

Send-MailMessage @mailParams

I tried replying to this the other day and the forum would log me out every time I went to this thread. Grrr.

Dan covered it, but you simply need to do Out-String:

Body = $serversNoRebootHTML | Out-String

thanks that worked