Friday, 17 November 2017

Server Health checks


$date = get-date -f "dd/MM/yyy hh:mm:ss"
#this is server list
$servers = Get-Content -Path 'C:\servers.txt'

$count = $servers | Measure-Object
$c=$count.Count




$b = @'
<html> 
  <body> 
    <span style="background-color:#4DF903;"> Wintel Health Checks Report</span>
  </body> 
</html> 
'@ 


$title = "$b"
$ttr = "<center><h1>$title</h1></center>"

$totalc ="<h2>Total $c Servers scanned</h2>"




$a = "<style>"
$a = $a + "BODY{background-color:#F2F5F9;}"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}"
$a = $a + "TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:DodgerBlue}"
$a = $a + "TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:white}"
$a = $a + "</style>"


function ForEach-Parallel {

    [cmdletbinding()]
    param(
        [Parameter(Mandatory=$false,position=0,ParameterSetName='ScriptBlock')]
            [System.Management.Automation.ScriptBlock]$ScriptBlock,

        [Parameter(Mandatory=$false,ParameterSetName='ScriptFile')]
        [ValidateScript({test-path $_ -pathtype leaf})]
            $scriptFile,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
            [PSObject]$InputObject,

            [int]$Throttle=5,

            [double]$sleepTimer = 200,

            [double]$Timeout = 0
    )
    BEGIN {
       
        #Build the scriptblock depending on the parameter used
        switch ($PSCmdlet.ParameterSetName){
            'ScriptBlock' {$ScriptBlock = $ExecutionContext.InvokeCommand.NewScriptBlock("param(`$_)`r`n" + $Scriptblock.ToString())}
            'ScriptFile' {$scriptblock = [scriptblock]::Create($(get-content $scriptFile | out-string))}
            Default {Write-Error ("Must provide ScriptBlock or ScriptFile"); Return}
        }
       
        #Define the initial sessionstate, create the runspacepool
        Write-Verbose "Creating runspace pool with $Throttle threads"
        $sessionState = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
        $pool = [Runspacefactory]::CreateRunspacePool(1, $Throttle, $sessionState, $host)
        $pool.open()
       
        #array to hold details on each thread
        $threads = @()

        #If inputObject is bound get a total count and set bound to true
        $bound = $false
        if( $PSBoundParameters.ContainsKey("inputObject") ){
            $bound = $true
            $totalCount = $inputObject.count
        }
       
    }

    PROCESS {
       
$run = @'
        #For each pipeline object, create a new powershell instance, add to runspacepool
        $powershell = [powershell]::Create().addscript($scriptblock).addargument($InputObject)
        $powershell.runspacepool=$pool
        $startTime = get-date

        #add references to inputobject, instance, handle and startTime to threads array
        $threads += New-Object psobject -Property @{
            Object = $inputObject;
            instance = $powershell;
            handle = $powershell.begininvoke();
            startTime = $startTime
        }

        Write-Verbose "Added $inputobject to the runspacepool at $startTime"
'@

        #Run the here string.  Put it in a foreach loop if it didn't come from the pipeline
        if($bound){   
            $run = $run -replace 'inputObject', 'object'
            foreach($object in $inputObject){ 
                Invoke-Expression -command $run
            }
        }

        else{
       
            Invoke-Expression -command $run
        }

    }
    END {
        $notdone = $true
       
        #Loop through threads.
        while ($notdone) {

            $notdone = $false
            for ($i=0; $i -lt $threads.count; $i++) {
                $thread = $threads[$i]
                if ($thread) {

                    #If thread is complete, dispose of it.
                    if ($thread.handle.iscompleted) {
                        Write-verbose "Closing thread for $($thread.Object)"
                        $thread.instance.endinvoke($thread.handle)
                        $thread.instance.dispose()
                        $threads[$i] = $null
                    }

                    #Thread exceeded maxruntime timeout threshold
                    elseif( $Timeout -ne 0 -and ( (get-date) - $thread.startTime ).totalminutes -gt $Timeout ){
                        Write-Error "Closing thread for $($thread.Object): Thread exceeded $Timeout minute limit" -TargetObject $thread.inputObject
                        $thread.instance.dispose()
                        $threads[$i] = $null
                    }

                    #Thread is running, loop again!
                    else {
                        $notdone = $true
                    }
                }           
            }

            #Sleep for specified time before looping again
            Start-Sleep -Milliseconds $sleepTimer
        }
        $pool.close()
    }
}



#online servers Null variable
$online =@()
#offline servers Null variable
$offline=@()

#looping to get all online servers

$serverresult = $servers | ForEach-Parallel -Throttle 40 {
       
         if(Test-Connection $_ -Count 1 -ea 0){
         $res = ""|select ComputerName,Ping
         $res.ComputerName = $_
         $res.Ping = $true
         $res       
         }
         else{
         $res = ""|select ComputerName,Ping
         $res.ComputerName = $_
         $res.Ping = $false
         $res 
       
         }
}

$online  = $serverresult | ?{$_.ping -eq $true} |select -ExpandProperty Computername
$offline = $serverresult | ?{$_.ping -eq $false} |select -ExpandProperty Computername

#Region Uptime Start

 $infouptime =@()

 $infouptime=$online |ForEach-Parallel -Throttle 5 {
 function get-uptime {

             param(
             $computername =$env:computername
             )

             $os = Get-WmiObject win32_operatingsystem -ComputerName $computername -ea silentlycontinue
           
             if($os){
             $lastbootuptime =$os.ConvertTodateTime($os.LastBootUpTime)
             $LocalDateTime =$os.ConvertTodateTime($os.LocalDateTime)
             $up =$LocalDateTime - $lastbootuptime

             $uptime ="$($up.Days) days, $($up.Hours)h, $($up.Minutes)mins"
             $results =new-object psobject
             $results |Add-Member noteproperty LastBootUptime $LastBootuptime
             $results |Add-Member noteproperty ComputerName $computername
             $results |Add-Member noteproperty uptime $uptime
             $results | Select-Object computername,LastBootuptime,Uptime
             }
             else
             {
             $results =New-Object psobject
             $results =new-object psobject
             $results |Add-Member noteproperty LastBootUptime "Na"
             $results |Add-Member noteproperty ComputerName $computername
             $results |Add-Member noteproperty uptime "Na"
             $results | Select-Object computername,LastBootUptime,Uptime
             }
             }
 get-uptime -computername $_
 }

 $bootime=$infouptime

 ####################Uptime function Ends###################

 ######################################Memory function starts###################################
   
    $infod=@()
    $infod=$online |ForEach-Parallel -Throttle 5 {
    Function Dinfo ($ComputerName=$ENV:ComputerName) {

 foreach ($disk in $ComputerName){
Get-WmiObject win32_logicaldisk -ComputerName $ComputerName -Filter "Drivetype=3"  |
 Select-Object @{Label = "ServerName";Expression = {$_.__Server}}, 
@{Label = "Drive Letter";Expression = {$_.DeviceID}}, 
@{Label = "Total Capacity (GB)";Expression = {"{0:N1}" -f( $_.Size / 1gb)}}, 
@{Label = "Free Space (GB)";Expression = {"{0:N1}" -f( $_.Freespace / 1gb ) }}, 
@{Label="FreeSpace%"; Expression={"{0:N0}" -F (($_.Freespace/$_.Size)*100)}}
}
}
    Dinfo $_
    }



  $diskstatus=$infod



  $infom=@()

    $infom=$online |ForEach-Parallel -Throttle 5 {
       Function Get-MemmoryUtlization ($ComputerName=$ENV:ComputerName) {
                Get-WmiObject Win32_OperatingSystem -ComputerName $ComputerName |
                Select @{Name="Servername";Expression =  {$_.__Server}},
                @{Name = "TotalGB";Expression = {[int]($_.TotalVisibleMemorySize/1mb)}},
                @{Name = "FreeGB";Expression = {[math]::Round($_.FreePhysicalMemory/1mb,2)}},
                @{Name = "PercentFree%"; Expression = {[math]::Round(($_.FreePhysicalMemory/$_.TotalVisibleMemorySize)*100,2)}}
                }
       Get-MemmoryUtlization $_
    }

 $memorydetails= $infom


 ######################################Memory function ends###################################








  ######################################CPU function Starts#############################################################################################################################



$infocpu=@()
$infocpu = $online|ForEach-Parallel -Throttle 40 {
       function Get-Cpu{
                 param(
                 $computername =$env:computername
                 )
                 $os = gwmi win32_perfformatteddata_perfos_processor -ComputerName $computername| ? {$_.name -eq "_total"} | select -ExpandProperty PercentProcessorTime  -ea silentlycontinue
                 if(($os -match '\d+') -or ($os -eq '0')){
                 $results =new-object psobject
                 $results |Add-Member noteproperty Cputil  $os
                 $results |Add-Member noteproperty ComputerName  $computername
                 $results | Select-Object computername,Cputil
                 }
                 else{
                 $results =new-object psobject
                 $results |Add-Member noteproperty Cputil  "Na"
                 $results |Add-Member noteproperty ComputerName  $computername
                 $results | Select-Object computername,Cputil
                 }
                 }
       Get-Cpu $_
    }


   

    ###########################################################################End Cpu Function######################################################################################################


#############################Service report Starts########################################################################################
  $ServicesReport = @()
  foreach($computer in $online)
  {
       $Services = Get-WmiObject -Class Win32_Service  -ComputerName $computer | Where {($_.StartMode -eq "Auto") -and ($_.State -eq "Stopped")}

       foreach ($Service in $Services) {
              $ro = New-Object -Type PSObject -Property @{
                      ComputerName =$Service.PSComputerName
                      Name = $Service.Name
                      StartMode = $Service.StartMode
                      SStatus = $Service.State
              }
       $ServicesReport += $ro
     
       }
     
     
      }

      $servers = $ServicesReport

      #############################Service report ends#######################################################################################
       #endregion

       Function Set-CellColor
        {   <#
    .SYNOPSIS
        Function that allows you to set individual cell colors in an HTML table
    .DESCRIPTION
        To be used inconjunction with ConvertTo-HTML this simple function allows you
        to set particular colors for cells in an HTML table.  You provide the criteria
        the script uses to make the determination if a cell should be a particular
        color (property -gt 5, property -like "*Apple*", etc).
       
        You can add the function to your scripts, dot source it to load into your current
        PowerShell session or add it to your $Profile so it is always available.
       
        To dot source:
            .".\Set-CellColor.ps1"
           
    .PARAMETER Property
        Property, or column that you will be keying on. 
    .PARAMETER Color
        Name or 6-digit hex value of the color you want the cell to be
    .PARAMETER InputObject
        HTML you want the script to process.  This can be entered directly into the
        parameter or piped to the function.
    .PARAMETER Filter
        Specifies a query to determine if a cell should have its color changed.  $true
        results will make the color change while $false result will return nothing.
       
        Syntax
        <Property Name> <Operator> <Value>
       
        <Property Name>::= the same as $Property.  This must match exactly
        <Operator>::= "-eq" | "-le" | "-ge" | "-ne" | "-lt" | "-gt"| "-approx" | "-like" | "-notlike"
            <JoinOperator> ::= "-and" | "-or"
            <NotOperator> ::= "-not"
       
        The script first attempts to convert the cell to a number, and if it fails it will
        cast it as a string.  So 40 will be a number and you can use -lt, -gt, etc.  But 40%
        would be cast as a string so you could only use -eq, -ne, -like, etc. 
    .PARAMETER Row
        Instructs the script to change the entire row to the specified color instead of the individual cell.
    .INPUTS
        HTML with table
    .OUTPUTS
        HTML
    .EXAMPLE
        get-process | convertto-html | set-cellcolor -Propety cpu -Color red -Filter "cpu -gt 1000" | out-file c:\test\get-process.html

        Assuming Set-CellColor has been dot sourced, run Get-Process and convert to HTML. 
        Then change the CPU cell to red only if the CPU field is greater than 1000.
       
    .EXAMPLE
        get-process | convertto-html | set-cellcolor cpu red -filter "cpu -gt 1000 -and cpu -lt 2000" | out-file c:\test\get-process.html
       
        Same as Example 1, but now we will only turn a cell red if CPU is greater than 100
        but less than 2000.
       
    .EXAMPLE
        $HTML = $Data | sort server | ConvertTo-html -head $header | Set-CellColor cookedvalue red -Filter "cookedvalue -gt 1"
        PS C:\> $HTML = $HTML | Set-CellColor Server green -Filter "server -eq 'dc2'"
        PS C:\> $HTML | Set-CellColor Path Yellow -Filter "Path -like ""*memory*""" | Out-File c:\Test\colortest.html
       
        Takes a collection of objects in $Data, sorts on the property Server and converts to HTML.  From there
        we set the "CookedValue" property to red if it's greater then 1.  We then send the HTML through Set-CellColor
        again, this time setting the Server cell to green if it's "dc2".  One more time through Set-CellColor
        turns the Path cell to Yellow if it contains the word "memory" in it.
       
    .EXAMPLE
        $HTML = $Data | sort server | ConvertTo-html -head $header | Set-CellColor cookedvalue red -Filter "cookedvalue -gt 1" -Row
       
        Now, if the cookedvalue property is greater than 1 the function will highlight the entire row red.
       
 
    #>

    [CmdletBinding()]
    Param (
        [Parameter(Mandatory,Position=0)]
        [string]$Property,
        [Parameter(Mandatory,Position=1)]
        [string]$Color,
        [Parameter(Mandatory,ValueFromPipeline)]
        [Object[]]$InputObject,
        [Parameter(Mandatory)]
        [string]$Filter,
        [switch]$Row
    )
   
    Begin {
        Write-Verbose "$(Get-Date): Function Set-CellColor begins"
        If ($Filter)
        {   If ($Filter.ToUpper().IndexOf($Property.ToUpper()) -ge 0)
            {   $Filter = $Filter.ToUpper().Replace($Property.ToUpper(),"`$Value")
                Try {
                    [scriptblock]$Filter = [scriptblock]::Create($Filter)
                }
                Catch {
                    Write-Warning "$(Get-Date): ""$Filter"" caused an error, stopping script!"
                    Write-Warning $Error[0]
                    Exit
                }
            }
            Else
            {   Write-Warning "Could not locate $Property in the Filter, which is required.  Filter: $Filter"
                Exit
            }
        }
    }
   
    Process {
        ForEach ($Line in $InputObject)
        {   If ($Line.IndexOf("<tr><th") -ge 0)
            {   Write-Verbose "$(Get-Date): Processing headers..."
                $Search = $Line | Select-String -Pattern '<th ?[a-z\-:;"=]*>(.*?)<\/th>' -AllMatches
                $Index = 0
                ForEach ($Match in $Search.Matches)
                {   If ($Match.Groups[1].Value -eq $Property)
                    {   Break
                    }
                    $Index ++
                }
                If ($Index -eq $Search.Matches.Count)
                {   Write-Warning "$(Get-Date): Unable to locate property: $Property in table header"
                    Exit
                }
                Write-Verbose "$(Get-Date): $Property column found at index: $Index"
            }
            If ($Line -match "<tr( style=""background-color:.+?"")?><td")
            {   $Search = $Line | Select-String -Pattern '<td ?[a-z\-:;"=]*>(.*?)<\/td>' -AllMatches
                $Value = $Search.Matches[$Index].Groups[1].Value -as [double]
                If (-not $Value)
                {   $Value = $Search.Matches[$Index].Groups[1].Value
                }
                If (Invoke-Command $Filter)
                {   If ($Row)
                    {   Write-Verbose "$(Get-Date): Criteria met!  Changing row to $Color..."
                        If ($Line -match "<tr style=""background-color:(.+?)"">")
                        {   $Line = $Line -replace "<tr style=""background-color:$($Matches[1])","<tr style=""background-color:$Color"
                        }
                        Else
                        {   $Line = $Line.Replace("<tr>","<tr style=""background-color:$Color"">")
                        }
                    }
                    Else
                    {   Write-Verbose "$(Get-Date): Criteria met!  Changing cell to $Color..."
                        $Line = $Line.Replace($Search.Matches[$Index].Value,"<td style=""background-color:$Color"">$Value</td>")
                    }
                }
            }
            Write-Output $Line
        }
    }
   
    End {
        Write-Verbose "$(Get-Date): Function Set-CellColor completed"
    }
}




       $bootime = $bootime |ConvertTo-Html -Head $a -body "<H2>Uptime</H2>"
       $diskstatus =$diskstatus|ConvertTo-HTML -head $a -body "<H2>Disk Information</H2>" | Set-CellColor 'FreeSpace%' Red -Filter "FreeSpace% -lt 80"
       $memorydetails=$memorydetails|ConvertTo-HTML -head $a -body "<H2>Memory Status</H2>"| Set-CellColor 'PercentFree%' Red -Filter "PercentFree% -lt 80"
       $ServicesReport=$ServicesReport|ConvertTo-HTML -head $a -body "<H2>Service Information</H2>" | Set-CellColor SStatus red -Filter "Sstatus -eq 'Stopped'"
       $infocpu =$infocpu|ConvertTo-HTML -head $a -body "<H2>CPU Status</H2>"| Set-CellColor 'Cputil' Red -Filter "Cputil -gt 80" 
       $Serverchecksfinal =  $ttr + $totalc   +"`n`n"+$bootime +"`n"+ $diskstatus + $infocpu+$memorydetails + $ServicesReport

 
 $total= $Serverchecksfinal
 #$total = $total -replace("<td>Stopped</td>",'<style> .blue { background: Red; }<td class="blue">Stopped</td>')


  Send-MailMessage -To "xxxxx" -From "xxxxx" -SmtpServer "xxxx" -BodyAsHtml "$total"  -Subject "Server Health checks on $date"

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



No comments:

Post a Comment

Powershell function to get theremote server IP details,Subnetmask,Gateway,DHCP Enabled status,DNS Servers,Wins and Macaddress

#Powershell function to get theremote server IP details,Subnetmask,Gateway,DHCP Enabled status,DNS Servers,Wins and Macaddress # use...