Server Health Report in Powershell - powershell

I have prepared server health report via PowerShell. My script is working fine but I am getting some random value in the bottom when I receive email via script, also I am not able to add body in my send-mailmessage command. When I do so script generates exception.
Here is my PS code:
<#
.SYNOPSIS
Script for the detailed server health report
.DESCRIPTION
The script accepts parameter from CSV file by which we can get details and
all information related to health status of the server.The script generates all the
information in a CSv file.
#>
[CmdletBinding(SupportsShouldProcess=$True)]
param(
[Parameter(Position=0,mandatory=$true)]
[string]$Servercsv
)
begin{
Write-Host "Running"
}
process{
# Path for the CSV file that contains all the Print Server information.
$ServerDetails=import-csv $Servercsv
$result=#()
$Outputreport = $null
foreach($server in $ServerDetails){
try{
#sysinfo variable contains complete systeminfo like manufacturer name, physical memory,servername
$cpu=Get-WMIObject -ComputerName $server.servers win32_processor| select __Server, #{name="CPUUtilization" ;expression ={“{0:N2}” -f (get-counter -Counter "\Processor(_Total)\% Processor Time" -SampleInterval 1 -MaxSamples 5 |
select -ExpandProperty countersamples | select -ExpandProperty cookedvalue | Measure-Object -Average).average}}
$disks =Get-WmiObject -Class win32_Volume -ComputerName $server.servers -Filter "DriveLetter = 'C:'" |
Select-object #{Name = "PercentFree"; Expression = {“{0:N2}” -f (($_.FreeSpace / $_.Capacity)*100) } }
$os=gwmi -Class win32_operatingsystem -computername $server.servers |
Select-Object #{Name = "MemoryUsage"; Expression = {“{0:N2}” -f ((($_.TotalVisibleMemorySize - $_.FreePhysicalMemory)*100)/ $_.TotalVisibleMemorySize) }}
$result += [PSCustomObject] #{
ServerName ="$($server.servers)"
CPUUtilization = $cpu.CPUUtilization.ToString()
CDrive = $disks.PercentFree
MemLoad = $OS.MemoryUsage
}
}
catch{
"error communicating with $($server.servers), skipping to next"
}
}
$Outputreport = "<HTML><TITLE> Utilization of Server Resources</TITLE>
<BODY background-color:peachpuff>
<font color =""#99000"" face=""arial"">
<H3> Utilization of Server Resources</H3></font>
<Table border=2 cellpadding=1 cellspacing=5>
<TR bgcolor=gray align=center>
<TD><B>Server Name</B></TD>
<TD><B>CPUUtilization</B></TD>
<TD><B>Memory Utilization</B></TD>
<TD><B>CDrive</B></TD></TR>"
Foreach($Entry in $Result){
if(([decimal]$Entry.CPUUtilization -ge 15) -or ([decimal]$Entry.MemLoad -ge 50) -or (([decimal]$Entry.CDrive) -le 60) )
{
$Outputreport += "<TR>"
$Outputreport += "<TD><B>$($Entry.Servername)</B></TD>"
if([decimal]$Entry.CPUUtilization -ge 15)
{
$Outputreport += "<TD align=center style=color:red;>$($Entry.CPUUtilization+'%')</TD>"
}
else {
$Outputreport += "<TD align=center style=color:White;>$($Entry.CPUUtilization+'%')</TD>"
}
if([decimal]$Entry.MemLoad -ge 50)
{
$Outputreport += "<TD align=center style=color:red;>$($Entry.MemLoad+'%')</TD>"
}
else{
$Outputreport += "<TD align=center style=color:White;>$($Entry.MemLoad+'%')</TD>"
}
if(([decimal]$Entry.CDrive) -le 60)
{
$Outputreport += "<TD align=center style=color:red;>$($Entry.Cdrive+'%')</TD>"
}
else{ $Outputreport += "<TD align=center style=color:White;>$($Entry.Cdrive+'%')</TD>"}
#$Outputreport += "<TD>$($Entry.Servername)</TD>"
#$Outputreport += "<TD>$($Entry.Servername)</TD>"
$Outputreport+="</TR>"
}
}
$Outputreport += "</Table><p>Hello</p></BODY></HTML>"
$out=$Outputreport | ConvertTo-Html -Head $Outputreport
#Send an email about the Load
# $smtp is the outgoing mail server
$smtp= "smtphost.redmond.corp.microsoft.com"
try{
send-mailmessage -SmtpServer $smtp -from v-rubhat#microsoft.com -to v-rubhat#microsoft.com -subject "Server Health Report" -BodyAsHtml "$out"
}
catch [exception]
{
write-host ("Cannot send mail, since argument is null or empty")
}
}
Below is my attached output and that * and 1121 is that random number:
Utilization of Server Resources
Server Name CPUUtilization Memory Utilization CDrive
xxxxxxxx 3.25% 29.26% 22.11%
xxxxxxxx 18.80% 52.15% 57.49%
xxxxxxxx 27.76% 27.51% 71.91%
*
1121

I have changed the $out variable and added property attribute in it and that worked. Here's my edited $out command
$out=$Outputreport | ConvertTo-Html -Property Servername,CPUUtilization,MemLoad,CDrive -Head $Outputreport

Related

Need to monitor Server Resources Utilization for 30 minutes and send mail in Powershell

I have developed PowerShell script which monitors server performance like average CPU utilization, Memory and Cdrive and if any of the resource crosses the threshold it will trigger mail. My script is running fine but I want to monitor it for 30 minutes and if in 30 minutes it cross threshold only then it will trigger the mail.
<#
.SYNOPSIS
Script for the detailed server health report
.DESCRIPTION
The script accepts parameter from CSV file by which we can get details and
all information related to health status of the server.The script generates all the
information in a CSv file.
#>
[CmdletBinding(SupportsShouldProcess=$True)]
param(
[Parameter(Position=0,mandatory=$true)]
[string]$Servercsv
)
begin{
Write-Host "Running"
}
process{
# Path for the CSV file that contains all the Print Server information.
$ServerDetails=import-csv $Servercsv
$result=#()
$Outputreport = $null
foreach($server in $ServerDetails){
try{
#sysinfo variable contains complete systeminfo like manufacturer name, physical memory,servername
$cpu=Get-WMIObject -ComputerName $server.servers win32_processor| select __Server, #{name="CPUUtilization" ;expression ={“{0:N2}” -f (get-counter -Counter "\Processor(_Total)\% Processor Time" -SampleInterval 1 -MaxSamples 6 |
select -ExpandProperty countersamples | select -ExpandProperty cookedvalue | Measure-Object -Average).average}}
$disks =Get-WmiObject -Class win32_Volume -ComputerName $server.servers -Filter "DriveLetter = 'C:'" |
Select-object #{Name = "PercentFree"; Expression = {“{0:N2}” -f (($_.FreeSpace / $_.Capacity)*100) } }
$os=Get-WmiObject -Class win32_operatingsystem -computername $server.servers |
Select-Object #{Name = "MemoryUsage"; Expression = {“{0:N2}” -f ((($_.TotalVisibleMemorySize - $_.FreePhysicalMemory)*100)/ $_.TotalVisibleMemorySize) }}
$result += [PSCustomObject] #{
ServerName ="$($server.servers)"
CPUUtilization = $cpu.CPUUtilization.ToString()
CDrive = $disks.PercentFree
MemLoad = $OS.MemoryUsage
}
}
catch{
"error communicating with $($server.servers), skipping to next"
}
}
$Outputreport = "<HTML><TITLE> Utilization of Server Resources</TITLE>
<BODY background-color:peachpuff>
<font color =""#99000"" face=""arial"">
<H3> Utilization of Server Resources</H3></font>
<Table border=2 cellpadding=1 cellspacing=5>
<TR bgcolor=gray align=center>
<TD><B>Server Name</B></TD>
<TD><B>CPUUtilization</B></TD>
<TD><B>Memory Utilization</B></TD>
<TD><B>CDrive</B></TD></TR>"
Foreach($Entry in $Result){
if(([decimal]$Entry.CPUUtilization -ge 25) -or ([decimal]$Entry.MemLoad -ge 50) -or (([decimal]$Entry.CDrive) -le 60) )
{
$Outputreport += "<TR>"
$Outputreport += "<TD><B>$($Entry.Servername)</B></TD>"
if([decimal]$Entry.CPUUtilization -ge 25)
{
$Outputreport += "<TD align=center style=color:red;>$($Entry.CPUUtilization+'%')</TD>"
}
else {
$Outputreport += "<TD align=center style=color:White;>$($Entry.CPUUtilization+'%')</TD>"
}
if([decimal]$Entry.MemLoad -ge 50)
{
$Outputreport += "<TD align=center style=color:red;>$($Entry.MemLoad+'%')</TD>"
}
else{
$Outputreport += "<TD align=center style=color:White;>$($Entry.MemLoad+'%')</TD>"
}
if(([decimal]$Entry.CDrive) -le 60)
{
$Outputreport += "<TD align=center style=color:red;>$($Entry.Cdrive+'%')</TD>"
}
else{ $Outputreport += "<TD align=center style=color:White;>$($Entry.Cdrive+'%')</TD>"}
#$Outputreport += "<TD>$($Entry.Servername)</TD>"
#$Outputreport += "<TD>$($Entry.Servername)</TD>"
$Outputreport+="</TR>"
}
}
$Outputreport += "</Table><p>Regards,<br>Rujhaan Bhatia</p></BODY></HTML>"
$out=$Outputreport | ConvertTo-Html -Head $Outputreport
#Send an email about the Load
# $smtp is the outgoing mail server
$smtp= "smtphost.redmond.corp.microsoft.com"
try{
send-mailmessage -SmtpServer $smtp -from v-rubhat#microsoft.com -to v-rubhat#microsoft.com,v-ketr#microsoft.com -subject "Retail Servers Health Report" -BodyAsHtml "$out"
}
catch [exception]
{
write-host ("Cannot send mail, since argument is null or empty")
}
}
Please do suggest me if any changes are required in any of the command as well.
This should give you an idea on how to run jobs in the background and check for 30 minutes. If at any time the cpu, mem or disk is greater than threhold, send email.
function SendEmail {
param($server, $cpu, $mem, $disk)
#Code goes here to send email
}
$cpuThreshold = 99
$memThreshold = 99
$diskThreshold = 100
$jobHash = #{}
$serverHash = #{}
$serverList = #("localhost")
foreach($server in $serverList) {
$cpu = Start-Job -ComputerName $server -ScriptBlock { Get-Counter "\processor(_Total)\% Processor Time" -Continuous }
$mem = Start-Job -ComputerName $server -ScriptBlock { Get-Counter -Counter "\Processor(_Total)\% Processor Time" -Continuous }
$disk = Start-Job -ComputerName $server -ScriptBlock { Get-Counter -Counter "\LogicalDisk(C:)\% Free Space" -Continuous }
$serverHash.Add("cpu", $cpu)
$serverHash.Add("mem", $mem)
$serverHash.Add("disk", $disk)
$jobHash.Add($server, $serverHash)
}
Start-Sleep 10
$totalLoops = 0
while ($totalLoops -le 360) {
foreach($server in $jobHash.Keys) {
$cpu = (Receive-Job $jobHash[$server].cpu | % { (($_.readings.split(':'))[1]).Replace("`n","") } | measure -Maximum).Maximum
$mem = (Receive-Job $jobHash[$server].mem | % { (($_.readings.split(':'))[1]).Replace("`n","") } | measure -Maximum).Maximum
$disk = (Receive-Job $jobHash[$server].disk | % { (($_.readings.split(':'))[2]).Replace("`n","") } | measure -Maximum).Maximum
if ($Cpu -gt $cpuThreshold -or $mem -gt $memThreshold -or $disk -gt $diskThreshold) {
Send-Email $server $cpu $mem $disk
}
Write-Output "CPU: $($cpu), Mem: $($mem), disk util: $($disk)"
}
Start-Sleep 1
$totalLoops ++
}
Get-Job | Remove-Job
Hopefully this answers the question on how to create jobs in the background to check for status.
I would, however, check the max number of jobs you can have at any given time.
Documentation on Get-Counter

HTML to CSV file conversion

I have the below PowerShell script which shows the remote servers CPU/Disk/Memory health check.
It is not giving the output in HTML format and I am sending it to my email id with SMTP option. It is all working fine.
Current Output:
Along with the HTML output I want this output to be saved in a CSV file as well so that I can load it into Teradata using MLOAD.
Please help me to get output in a CSV file.
How can we load the data in CSV file to Teradata, can this be done using powershell or batch?
Code:
$ServerListFile = "C:\Users\HOSDUM01\Desktop\Auto\Server_health_check\list.txt"
$ServerList = Get-Content $ServerListFile -ErrorAction SilentlyContinue
$Result = #()
ForEach ($computername in $ServerList) {
$AVGProc = Get-WmiObject -computername $computername win32_processor |
Measure-Object -property LoadPercentage -Average | Select Average
$OS = gwmi -Class win32_operatingsystem -computername $computername |
Select-Object #{Name = "MemoryUsage"; Expression = {“{0:N2}” -f ((($_.TotalVisibleMemorySize - $_.FreePhysicalMemory) * 100) / $_.TotalVisibleMemorySize) }}
$vol = Get-WmiObject -Class win32_Volume -ComputerName $computername -Filter "DriveLetter = 'C:'" |
Select-object #{Name = "C PercentFree"; Expression = {“{0:N2}” -f (($_.FreeSpace / $_.Capacity) * 100) } }
$vol2 = Get-WmiObject -Class win32_Volume -ComputerName $computername -Filter "DriveLetter = 'E:'" |
Select-object #{Name = "E PercentFree"; Expression = {“{0:N2}” -f (($_.FreeSpace / $_.Capacity) * 100) } }
$vol3 = Get-WmiObject -Class win32_Volume -ComputerName $computername -Filter "DriveLetter = 'F:'" |
Select-object #{Name = "F PercentFree"; Expression = {“{0:N2}” -f (($_.FreeSpace / $_.Capacity) * 100) } }
$result += [PSCustomObject] #{
ServerName = "$computername"
CPULoad = "$($AVGProc.Average)%"
MemLoad = "$($OS.MemoryUsage)%"
CDrive = "$($vol.'C PercentFree')%"
EDrive = "$($vol2.'E PercentFree')%"
FDrive = "$($vol3.'F PercentFree')%"
}
$Outputreport = "<HTML><TITLE> Server Health Report </TITLE>
<BODY background-color:peachpuff>
<font color =""#99000"" face=""Microsoft Tai le"">
<H2> Server Health Report </H2></font>
<Table border=1 cellpadding=0 cellspacing=0>
<TR bgcolor=Cyan align=center>
<TD><B>EP_Server_Name</B></TD>
<TD><B>CPU_Utilizied</B></TD>
<TD><B>Memory_Utilized</B></TD>
<TD><B>C_Drive_Free_Percentage</B></TD>
<TD><B>E_Drive_Free_Percentage</B></TD>
<TD><B>F_Drive_Free_Percentage</B></TD></TR>"
Foreach ($Entry in $Result) {
if (($Entry.CpuLoad) -ge "80" -or ($Entry.memload) -ge "80" -or ($Entry.Cdrive) -le "20" -or ($Entry.Edrive) -le "20" -or ($Entry.Fdrive) -le "20") {
$Outputreport += "<TR bgcolor=red>"
}
else {
$Outputreport += "<TR bgcolor=green>"
}
$Outputreport += "<TD>$($Entry.Servername)</TD><TD align=center>$($Entry.CPULoad)</TD><TD align=center>$($Entry.MemLoad)</TD><TD align=center>$($Entry.Cdrive)</TD><TD align=center>$($Entry.Edrive)</TD><TD align=center>$($Entry.Fdrive)</TD></TR>"
}
$Outputreport += "</Table></BODY></HTML>"
}
$Outputreport | out-file C:\Users\HOSDUM01\Desktop\Auto\Server_health_check\Test.htm
#Invoke-Expression C:\Users\HOSDUM01\Desktop\Auto\Server_health_check\Test.htm
##Send email functionality from below line, use it if you want
$smtpServer = "Random"
$smtpFrom = "test#test.com"
$smtpTo = "test#test.com"
$messageSubject = "Servers Health report"
$message = New-Object System.Net.Mail.MailMessage $smtpfrom, $smtpto
$message.Subject = $messageSubject
$message.IsBodyHTML = $true
$message.Body = "<head><pre>$style</pre></head>"
$message.Body += Get-Content C:\Users\HOSDUM01\Desktop\Auto\Server_health_check\test.htm
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$smtp.Send($message)
As $result already contains the info you want in the csv, it can just be piped to Export-Csv
Simply add this line at the end of your script:
$result | Export-Csv -Path C:\folder\health_check.csv -NoTypeInformation
Not used Teradata but there was already a question on csv import: How to load data from a csv file into a table using Teradata Studio
All you need to do is, append to your script:
$Result | Export-Csv "C:\Users\HOSDUM01\Desktop\Auto\Server_health_check\Test.csv" -NoType
or whatever path you'd like to store the file
EDIT Reworked the script out of interrest.
Streamlined path usage
Inserted function DriveFreePercent and removed intermediate (unneccessary) variables.
moved the html creation outside of the foreach
Sample Csv file
"ServerName","CPULoad","MemLoad","CDrive","EDrive","FDrive"
"HP-G1610","4","32,61","94,56","",""
## Q:\Test\2018\05\31\SO_50617742.ps1
$BaseDir = "C:\Users\HOSDUM01\Desktop\Auto\Server_health_check\"
$ServerListFile = Join-Path $BaseDir "Server_list.txt"
$ReportHtm = Join-Path $BaseDir "Server_Test.htm"
$ReportCsv = Join-Path $BaseDir "Server_Test.csv"
function DriveFreePercent {
param ([string]$ComputerName,
[string]$DriveLetter)
Get-WmiObject -Class win32_Volume -ComputerName $ComputerName -Filter "DriveLetter = '$($DriveLetter):'" |
ForEach {"{0:N2}" -f (($_.FreeSpace / $_.Capacity)*100) }
}
$ServerList = Get-Content $ServerListFile -ErrorAction SilentlyContinue
$Result = #()
ForEach($computername in $ServerList) {
$Result += [PSCustomObject] #{
ServerName = "$computername"
CPULoad = ("{0}" -f (Get-WmiObject -ComputerName $computername win32_processor|Measure LoadPercentage -Average).Average)
MemLoad = (gwmi -Class win32_operatingsystem -ComputerName $computername |
ForEach{"{0:N2}" -f ((($_.TotalVisibleMemorySize - $_.FreePhysicalMemory)*100)/$_.TotalVisibleMemorySize)})
CDrive = (DriveFreePercent $ComputerName C)
EDrive = (DriveFreePercent $ComputerName E)
FDrive = (DriveFreePercent $ComputerName F)
}
}
$Outputreport = "<HTML><TITLE> Server Health Report </TITLE>
<BODY background-color:peachpuff>
<font color =""#99000"" face=""Microsoft Tai le"">
<H2> Server Health Report </H2></font>
<Table border=1 cellpadding=0 cellspacing=0>
<TR bgcolor=Cyan align=center>
<TD><B>EP_Server_Name</B></TD>
<TD><B>CPULOAD</B></TD>
<TD><B>MemLoad</B></TD>
<TD><B>C_Free</B></TD>
<TD><B>E_Free</B></TD>
<TD><B>F_Free</B></TD></TR>"
Foreach($Entry in $Result) {
if( ($Entry.CpuLoad) -ge "80" -or
($Entry.Memload) -ge "80" -or
($Entry.Cdrive) -le "20" -or
($Entry.Edrive) -le "20" -or
($Entry.Fdrive) -le "20") {
$Outputreport += "<TR bgcolor=red>"
} else {
$Outputreport += "<TR bgcolor=green>"
}
$Outputreport += "<TD>$($Entry.Servername)</TD>"
$Outputreport += "<TD align=center>$($Entry.CPULoad)%</TD>"
$Outputreport += "<TD align=center>$($Entry.MemLoad)%</TD>"
$Outputreport += "<TD align=center>$($Entry.Cdrive)%</TD>"
$Outputreport += "<TD align=center>$($Entry.Edrive)%</TD>"
$Outputreport += "<TD align=center>$($Entry.Fdrive)%</TD></TR>"
$Outputreport += "</Table></BODY></HTML>"
}
$Outputreport | Out-File $ReportHtm
$Result | Export-Csv $ReportCsv -NoTypeInformation
#Invoke-Expression $ReportHtm
#gc $ReportCsv
##Send email functionality from below line, use it if you want
$smtpServer = "Random"
$smtpFrom = "test#test.com"
$smtpTo = "test#test.com"
$messageSubject = "Servers Health report"
$message = New-Object System.Net.Mail.MailMessage $smtpfrom, $smtpto
$message.Subject = $messageSubject
$message.IsBodyHTML = $true
$message.Body = "<head><pre>$style</pre></head>"
$message.Body += $Outputreport
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
#$smtp.Send($message)
$result = #()
for ($i=1; $i -lt 5; $i++) {
$result += [PSCustomObject] #{
ServerName = "$i"
CPULoad = "$($AVGProc.Average)%"
MemLoad = "$($OS.MemoryUsage)%"
CDrive = "$($vol.'C PercentFree')%"
EDrive = "$($vol2.'E PercentFree')%"
FDrive = "$($vol3.'F PercentFree')%"
}
}
$result | ConvertTo-Csv

Generate status report for servers on different domain using Power shell

I am trying to generate server status HTML report for list of servers mentioned in text file. Some of my servers are in different domains so it gives me error.
Error :
Get-WmiObject : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
At C:\Users\raj.negi.RESONATE\Desktop\WinServ-Status.ps1:143 char:32
+ $OperatingSystem = Get-WmiObject Win32_OperatingSystem -ComputerName ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
It is working fine for the servers which is in same domain from where i running the script.
I am able to ping successfully the other domain server.
[CmdletBinding()]
Param(
$ServerFile = "C:\ServerStatus\ServerList.txt",
$OutputPath = "C:\ServerStatus",
[alias("DiskAlert")]
$DiskAlertThreshold,
[alias("CpuAlert")]
$CpuAlertThreshold,
[alias("MemAlert")]
$MemAlertThreshold,
[alias("Refresh")]
$RefreshTime,
[alias("SendTo")]
$MailTo,
[alias("From")]
$MailFrom,
[alias("Smtp")]
$SmtpServer,
[alias("User")]
$SmtpUser,
[alias("Pwd")]
$SmtpPwd,
[switch]$UseSsl)
## Function to get the up time from the server
Function Get-UpTime
{
param([string] $LastBootTime)
$Uptime = (Get-Date) - [System.Management.ManagementDateTimeconverter]::ToDateTime($LastBootTime)
"$($Uptime.Days) days $($Uptime.Hours)h $($Uptime.Minutes)m"
}
## Begining of the loop. Lower down the loop is broken if the refresh option is not configured.
Do
{
## Change value of the following parameter as needed
$OutputFile = "$OutputPath\WinServ-Status-Report.htm"
$ServerList = Get-Content $ServerFile
$Result = #()
## Look through the servers in the file provided
ForEach ($ServerName in $ServerList)
{
$PingStatus = Test-Connection -ComputerName $ServerName -Count 1 -Quiet
## If server responds, get uptime and disk info
If ($PingStatus)
{
$OperatingSystem = Get-WmiObject Win32_OperatingSystem -ComputerName $ServerName
$CpuAlert = $false
$CpuUsage = Get-WmiObject Win32_Processor -Computername $ServerName | Measure-Object -Property LoadPercentage -Average | ForEach-Object {$_.Average; If($_.Average -ge $CpuAlertThreshold){$CpuAlert = $True}; "%"}
$Uptime = Get-Uptime($OperatingSystem.LastBootUpTime)
$MemAlert = $false
$MemUsage = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $ServerName | ForEach-Object {“{0:N0}” -f ((($_.TotalVisibleMemorySize - $_.FreePhysicalMemory) * 100)/ $_.TotalVisibleMemorySize); If((($_.TotalVisibleMemorySize - $_.FreePhysicalMemory) * 100)/ $_.TotalVisibleMemorySize -ge $MemAlertThreshold){$MemAlert = $True}; "%"}
$DiskAlert = $false
$DiskUsage = Get-WmiObject Win32_LogicalDisk -ComputerName $ServerName | Where-Object {$_.DriveType -eq 3} | Foreach-Object {$_.DeviceID, [Math]::Round((($_.Size - $_.FreeSpace) * 100)/ $_.Size); If([Math]::Round((($_.Size - $_.FreeSpace) * 100)/ $_.Size) -ge $DiskAlertThreshold){$DiskAlert = $True}; "%"}
$IPv4Address = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $ServerName | Select-Object -Expand IPAddress | Where-Object { ([Net.IPAddress]$_).AddressFamily -eq "InterNetwork" }
}
## Put the results together
$Result += New-Object PSObject -Property #{
ServerName = $ServerName
IPV4Address = $IPv4Address
Status = $PingStatus
CpuUsage = $CpuUsage
CpuAlert = $CpuAlert
Uptime = $Uptime
MemUsage = $MemUsage
MemAlert = $MemAlert
DiskUsage = $DiskUsage
DiskAlert = $DiskAlert
}
## Clear the variables after obtaining and storing the results so offline servers don't have duplicate info.
Clear-Variable IPv4Address
Clear-Variable Uptime
Clear-Variable MemUsage
Clear-Variable CpuUsage
Clear-Variable DiskUsage
}
## If there is a result put the HTML file together.
If ($Result -ne $null)
{
$HTML = '<style type="text/css">
p {font-family:"Trebuchet MS", Arial, Helvetica, sans-serif;font-size:14px}
p {color:#ffffff;}
#Header{font-family:"Trebuchet MS", Arial, Helvetica, sans-serif;width:100%;border-collapse:collapse;}
#Header td, #Header th {font-size:15px;text-align:left;border:1px solid #1a1a1a;padding:2px 2px 2px 7px;color:#ffffff;}
#Header th {font-size:16px;text-align:center;padding-top:5px;padding-bottom:4px;background-color:#4B4B4B;color:#ffffff;}
#Header tr.alt td {color:#ffffff;background-color:#eaf2d3;}
#Header tr:nth-child(even) {background-color:#4B4B4B;}
#Header tr:nth-child(odd) {background-color:#4B4B4B;}
body {background-color: #1a1a1a;}
</style>
<head><meta http-equiv="refresh" content="30"></head>'
$HTML += "<html><body>
<table border=1 cellpadding=0 cellspacing=0 id=header>
<tr>
<th><b><font color=#e6e6e6>Server</font></b></th>
<th><b><font color=#e6e6e6>IP</font></b></th>
<th><b><font color=#e6e6e6>Status</font></b></th>
<th><b><font color=#e6e6e6>CPU Usage</font></b></th>
<th><b><font color=#e6e6e6>Memory Usage</font></b></th>
<th><b><font color=#e6e6e6>Disk Usage</font></b></th>
<th><b><font color=#e6e6e6>Uptime</font></b></th>
</tr>"
## Highlight the alerts if the alerts are triggered.
ForEach($Entry in $Result)
{
If ($Entry.Status -eq $True)
{
$HTML += "<td><font color=#00e600>$($Entry.ServerName)</font></td>"
}
Else
{
$HTML += "<td><font color=#FF4D4D>&#10008 $($Entry.ServerName)</font></td>"
}
If ($Entry.Status -eq $True)
{
$HTML += "<td><font color=#00e600>$($Entry.IPV4Address)</font></td>"
}
Else
{
$HTML += "<td><font color=#FF4D4D>&#10008 Offline</font></td>"
}
If ($Entry.Status -eq $True)
{
$HTML += "<td><font color=#00e600>&#10004 Online</font></td>"
}
Else
{
$HTML += "<td><font color=#FF4D4D>&#10008 Offline</font></td>"
}
If ($Entry.CpuUsage -ne $null)
{
If ($Entry.CpuAlert -eq $True)
{
$HTML += "<td><font color=#ffff4d>&#9888 $($Entry.CpuUsage)</font></td>"
}
Else
{
$HTML += "<td><font color=#00e600>&#10004 $($Entry.CpuUsage)</font></td>"
}
}
Else
{
$HTML += "<td><font color=#FF4D4D>&#10008 Offline</font></td>"
}
If ($Entry.MemUsage -ne $null)
{
If ($Entry.MemAlert -eq $True)
{
$HTML += "<td><font color=#ffff4d>&#9888 $($Entry.MemUsage)</font></td>"
}
Else
{
$HTML += "<td><font color=#00e600>&#10004 $($Entry.MemUsage)</font></td>"
}
}
Else
{
$HTML += "<td><font color=#FF4D4D>&#10008 Offline</font></td>"
}
If ($Entry.DiskUsage -ne $null)
{
If ($Entry.DiskAlert -eq $True)
{
$HTML += "<td><font color=#ffff4d>&#9888 $($Entry.DiskUsage)</font></td>"
}
Else
{
$HTML += "<td><font color=#00e600>&#10004 $($Entry.DiskUsage)</font></td>"
}
}
Else
{
$HTML += "<td><font color=#FF4D4D>&#10008 Offline</font></td>"
}
If ($Entry.Status -eq $True)
{
$HTML += "<td><font color=#00e600>$($Entry.Uptime)</font></td>
</tr>"
}
Else
{
$HTML += "<td><font color=#FF4D4D>&#10008 Offline</font></td>
</tr>"
}
}
## Report the date and time the script ran.
$HTML += "</table><p><font color=#e6e6e6>Status refreshed on: $(Get-Date -Format G)</font></p></body></html>"
## Output the HTML file
$HTML | Out-File $OutputFile
## If email was configured, set the variables for the email subject and body
If ($SmtpServer)
{
$MailSubject = "Server Status Report"
$MailBody = Get-Content -Path $OutputFile | Out-String
## If an email password was configured, create a variable with the username and password
If ($SmtpPwd)
{
$SmtpPwdEncrypt = Get-Content $SmtpPwd | ConvertTo-SecureString
$SmtpCreds = New-Object System.Management.Automation.PSCredential -ArgumentList ($SmtpUser, $SmtpPwdEncrypt)
## If ssl was configured, send the email with ssl
If ($UseSsl)
{
Send-MailMessage -To $MailTo -From $MailFrom -Subject $MailSubject -Body $MailBody -BodyAsHtml -SmtpServer $SmtpServer -UseSsl -Credential $SmtpCreds
}
## If ssl wasn't configured, send the email without ssl
Else
{
Send-MailMessage -To $MailTo -From $MailFrom -Subject $MailSubject -Body $MailBody -BodyAsHtml -SmtpServer $SmtpServer -Credential $SmtpCreds
}
}
## If an email username and password were not configured, send the email without authentication
Else
{
Send-MailMessage -To $MailTo -From $MailFrom -Subject $MailSubject -Body $MailBody -BodyAsHtml -SmtpServer $SmtpServer
}
}
## If the refresh time option is configured, wait the specifed number of seconds then loop.
If ($RefreshTime -ne $null)
{
Start-Sleep -Seconds $RefreshTime
}
}
}
## If the refresh time option is not configured, stop the loop.
Until ($RefreshTime -eq $null)
Firewall is Off on all servers.

Inconsistent powershell script

I am using a script that performs a basic health check on average CPU and Memory Utilization and checks if a specific service is running or not. The output will be displayed as HTML. If the CPU/Memory utilization is greater than 89%, or if ther service is not running, the affected server will be displayed in red. The script works just fine except for some inconsistencies that the server, even when under utilized, will be in red.
Here is the powershell script I am using:
$ServerListFile = "C:\Scripts\HealthCheck\ServerList.txt"
$ServerList = Get-Content $ServerListFile -ErrorAction SilentlyContinue
$Date = Get-Date -Format M.d.yyyy
$Result = #()
foreach ($computername in $ServerList) {
$AVGProc = Get-WmiObject -ComputerName $computername Win32_Processor |
Measure-Object -Property LoadPercentage -Average |
Select-Object Average
$OS = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computername |
Select-Object #{Name = "MemoryUsage"; Expression = {"{0:N2}" -f ((($_.TotalVisibleMemorySize - $_.FreePhysicalMemory)*100)/ $_.TotalVisibleMemorySize) }}
$Service1 = Get-Service -ComputerName $computername -Name Service1
$Service2 = Get-Service -ComputerName $computername -Name Service2
$Result += [PSCustomObject] #{
ServerName = "$computername"
CPULoad = "$($AVGProc.Average)%"
MemLoad = "$($OS.MemoryUsage)%"
Service1 = "$($Service1.Status)"
Service2 = "$($Service2.Status)"
}
$Outputreport = "<HTML><TITLE> Server Health Check </TITLE>
<BODY background-color:peachpuff>
<font color =""#99000"" face=""Microsoft Tai le"">
<H2> Server Health Check </H2></font>
<Table border=1 cellpadding=7 cellspacing=0>
<font face=""Calibri"">
<TR bgcolor=white align=center>
<TD><B> Server Name </B></TD>
<TD><B> Avrg.CPU </B></TD>
<TD><B> Memory </B></TD>
<TD><B> Service1 </B></TD>
<TD><B> Service2</B></TD></TR>"
foreach ($Entry in $Result) {
if (($Entry.MemLoad -gt "89") -Or ($Entry.CPULoad -gt "89") -or ($Entry.Service1 -eq "Stopped") -or ($Entry.Service2 -eq "Stopped")) {
$Outputreport += "<TR bgcolor=red>"
} else {
$Outputreport += "<TR bgcolor=lightgreen>"
}
$Outputreport += "<TD>$($Entry.Servername)</TD><TD align=center>$($Entry.CPULoad)</TD><TD align=center>$($Entry.MemLoad)</TD><TD align=center>$($Entry.Service1)</TD><TD align=center>$($Entry.Service2)</TD></TR>"
}
$Outputreport += "</Table></BODY></HTML>"
}
$Outputreport | Out-File C:\Scripts\HealthCheck\ServerHealthCheck\HealthCheck_$Date.htm
Thanks!
Don't use string comparisons when you're really interested in a numerical comparison - the ordinality of a string of digits is not equal to that of it's numerical counterpart. Consider the following comparison operations:
PS C:\> 9 -gt 89
False
PS C:\> "9" -gt "89"
True
First, change the result objects to carry the percentages as numbers instead:
$Result += [PSCustomObject] #{
ServerName = "$computername"
CPULoad = $AVGProc.Average
MemLoad = $OS.MemoryUsage
Service1 = "$($Service1.Status)"
Service2 = "$($Service2.Status)"
}
Then change the if statement to compare them as numbers:
if (($Entry.MemLoad -gt 89) -Or ($Entry.CPULoad -gt 89) -or ($Entry.Service1 -eq "Stopped") -or ($Entry.Service2 -eq "Stopped"))
And then finally, add the % sign in the final output:
$Outputreport += "<TD>$($Entry.Servername)</TD><TD align=center>$($Entry.CPULoad)%</TD><TD align=center>$($Entry.MemLoad)%</TD><TD align=center>$($Entry.Service1)</TD><TD align=center>$($Entry.Service2)</TD></TR>"

Output not coming on HTM,

I run the below scripts and Eventlog is blank on HTM File but on powershell
$ServerListFile = "D:\Scripts\ServerList.txt"
$ServerList = Get-Content $ServerListFile -ErrorAction SilentlyContinue
$Result = #()
ForEach($computername in $ServerList)
{
Get-Eventlog -LogName Security -Newest 2000 | Where-Object {$_.EventID -eq "4624"} | Select-Object #{Name ="Username"; Expression = {$_.ReplacementStrings[1]}}
$result += [PSCustomObject] #{
ServerName = "$computername"
EventLog = "$Username"
}
$Outputreport = "<HTML><TITLE> Decommission Validation Report </TITLE>
<BODY background-color:peachpuff>
<font color =""#99000"" face=""Microsoft Tai le"">
<H2> Decommission Validation Report </H2></font>
<Table border=1 cellpadding=0 cellspacing=0>
<TR bgcolor=gray align=center>
<TD><B>Server Name</B></TD>
<TD><B>EventLog</B></TD></TR>"
Foreach($Entry in $Result)
{
if((($Entry.Servername) -or ($Entry.EventLog)) -ge 80 )
{
$Outputreport += "<TR bgcolor=red>"
}
else
{
$Outputreport += "<TR>"
}
$Outputreport += "<TD>$($Entry.Servername)</TD></TD><TD align=center>$($Entry.Username)</TD></TR>"
}
$Outputreport += "</Table></BODY></HTML>"
}
$Outputreport | out-file D:\Scripts\Test.htm
Invoke-Expression D:\Scripts\Test.htm
I run the above scripts and Eventlog is blank on HTM File but on powershell
you arent capturing the get-eventlog return values
ForEach($computername in $ServerList)
{
$eventLog = Get-Eventlog -LogName Security -Newest 2000 | Where-Object {$_.EventID -eq "4624"} | Select-Object #{Name ="Username"; Expression = {$_.ReplacementStrings[1]}}
$result += [PSCustomObject] #{
ServerName = "$computername"
EventLog = "$eventLog.Username"
}
if what you want is an entry in result for each of the 2k event log items returned then do this:
ForEach($computername in $ServerList)
{
$eventLog = Get-Eventlog -LogName Security -Newest 2000 | Where-Object {$_.EventID -eq "4624"} | Select-Object #{Name ="Username"; Expression = {$_.ReplacementStrings[1]}}
foreach($item in $eventLog)
{
$result += [PSCustomObject] #{
ServerName = "$computername"
EventLog = "$eventLog.Username"
}
}
I incorporated the changes suggested by Dane Boulton and modified your code a bit to get what I believe is what you are looking for. I changed the Replacement strings entry to 5 because I believe you are looking for the user account logging in. I also modified the EventLog variable to reference $item.UserName. See how this works for you.
$ServerListFile = "D:\Scripts\ServerList.txt"
$ServerList = Get-Content $ServerListFile -ErrorAction SilentlyContinue
$Result = #()
ForEach($computername in $ServerList)
{
$eventLog = Get-Eventlog -LogName Security -Newest 2000 | Where-Object {$_.EventID -eq "4624"} | Select-Object #{Name ="Username"; Expression = {$_.ReplacementStrings[5]}}
foreach($item in $eventLog)
{
$result += [PSCustomObject] #{
ServerName = $computername
UserName = $item.Username
}
}
$Outputreport = "<HTML><TITLE> Decommission Validation Report </TITLE>
<BODY background-color:peachpuff>
<font color =""#99000"" face=""Microsoft Tai le"">
<H2> Decommission Validation Report </H2></font>
<Table border=1 cellpadding=0 cellspacing=0>
<TR bgcolor=gray align=center>
<TD><B>Server Name</B></TD>
<TD><B>UserName</B></TD></TR>"
Foreach($Entry in $Result)
{
if((($Entry.Servername) -or ($Entry.UserName)) -ge 80 )
{
$Outputreport += "<TR bgcolor=red>"
}
else
{
$Outputreport += "<TR>"
}
$Outputreport += "<TD>$($Entry.Servername)</TD></TD><TD align=center>$($Entry.UserName)</TD></TR>"
}
$Outputreport += "</Table></BODY></HTML>"
}
$Outputreport | out-file D:\Scripts\Test.htm
Invoke-Expression D:\Scripts\Test.htm