Thursday, July 13, 2017

Check ESX Host NTP

#requires -version 2
<#

.SYNOPSIS
    Script can be used to report or setup NTP configuration on all vSphere hosts in given cluster

.DESCRIPTION
    Script takes vCenter Server name and host cluster name as mandatory parameters, NTPSources parameter is optional.
    If only mandatory parameters are provided script generates report aobut NTP settings for all vSphere hosts that are
    connected to cluster. Report include ntp service status, policy, up to 5 ntp servers configured and calculated time difference
    between host and system where the script is invoked. For consistent results script should be run from vCenter Server.
    Optional parameter NTPSources is a comma-separated list of ntp servers that will be configured in cluster.
    If NTPSources paramter is provided the script will configure ntp service to start together with host ("on" policy),
    configure ntp servers provided, set the time manually (to avoid drift problems) and restart ntpd.

.PARAMETER vCenterServer
    Mandatory parameter indicating vCenter server to connect to (FQDN or IP address)

.PARAMETER ClusterName
    Mandatory parameter indicating host cluster name where vms need to be reconfigured

.PARAMETER NTPSources
    Optional parameter indicating NTP servers that will be used

.EXAMPLE
    To configure two NTP servers provide all parameters.

    vmhost-timekeeping.ps1 -vCenterServer vcenter.seba.local -ClusterName Production-Cluster -NTPSources "time01.seba.local,time02.seba.local,10.0.0.1"

.EXAMPLE
    If you provide -NTPSources only the script will ask for mandatory parameters

    vmhost-timekeeping.ps1 -NTPSources "time01.seba.local,time02.seba.local,10.0.0.1"

.EXAMPLE
    To generate report about NTP service status provide only mandatory parameters.

    vmhost-timekeeping.ps1 -vcenter 10.0.0.1 -cluster tdq-cluster

.EXAMPLE
    Script will interactively ask for two mandatory parameters, no changes will be made, only report will be created.

    vmhost-timekeeping.ps1
#>

[CmdletBinding()]
Param(
  [Parameter(Mandatory=$True,Position=1)]
   [string]$vCenterServer,
   [Parameter(Mandatory=$True, Position=2)]
   [string]$ClusterName,
   [Parameter(Mandatory=$False, Position=3)]
   [string]$NTPSources=""
)

Function Write-And-Log {

[CmdletBinding()]
Param(
  [Parameter(Mandatory=$True,Position=1)]
   [string]$LogFile,
   [Parameter(Mandatory=$True,Position=2)]
   [string]$line,
   [Parameter(Mandatory=$False,Position=3)]
   [int]$ErrorCount=0,
   [Parameter(Mandatory=$False,Position=4)]
   [string]$type="terse"
)

$LogEntry = (Get-Date -Format ("[yyyy-MM-dd HH:mm:ss] ")) + $line
$ui = (Get-Host).UI.RawUI

if ($ErrorCount) {

   $ui.ForegroundColor = "red"
   $LogEntry = ">>> ERROR <<< " + $LogEntry
   Write-Output $LogEntry
   $LogEntry | Out-File $LogFile -Append

}
else {

   $ui.ForegroundColor = "green"
   if ($type -ne "terse"){
      Write-Output $LogEntry
      $LogEntry | Out-file $LogFile -Append
   }
   else {
      Write-Output $LogEntry
   }

}

$ui.ForegroundColor = "white"
}

#constans
$maxtimedrift = 1

#variables
$ScriptRoot = Split-Path $MyInvocation.MyCommand.Path
$StartTime = Get-Date -Format "yyyyMMddHHmmss_"
$csvoutfile = $ScriptRoot + "\" + $StartTime+ "time_config_report_for_$($ClusterName)_cluster.csv"
$logfilename = $ScriptRoot + "\" + $StartTime + "vmhost-timekeeping.log"
$transcriptfilename = $ScriptRoot + "\" + $StartTime + "vmhost-timekeeping_Transcript.log"
$all_vmhosts_timeconfig_info = @()
$total_errors = 0
$total_vmhosts = 0

#start PowerShell transcript
Start-Transcript -Path $transcriptfilename

#load PowerCLI snap-in
$vmsnapin = Get-PSSnapin VMware.VimAutomation.Core -ErrorAction SilentlyContinue
$Error.Clear()
if ($vmsnapin -eq $null)
    {
    Add-PSSnapin VMware.VimAutomation.Core
    if ($error.Count -eq 0)
        {
        write-and-log $logfilename "PowerCLI VimAutomation.Core Snap-in was successfully enabled." 0 "full"
        }
    else
        {
        write-and-log $logfilename "Could not enable PowerCLI VimAutomation.Core Snap-in, exiting script" 1 "full"
        Exit
        }
    }
else
    {
    write-and-log $logfilename "PowerCLI VimAutomation.Core Snap-in is already enabled" 0 "full"
    }

#check PowerCLI version
if (($vmsnapin.Version.Major -gt 5) -or (($vmsnapin.version.major -eq 5) -and ($vmsnapin.version.minor -ge 1))) {

    #assume everything is OK at this point
    $Error.Clear()

    #connect vCenter from parameter
    Connect-VIServer -Server $vCenterServer -ErrorAction SilentlyContinue | Out-Null

    #execute only if connection successful
    if ($error.Count -eq 0){

        #measuring execution time is really hip these days
        $stop_watch = [Diagnostics.Stopwatch]::StartNew()

        #use previously defined function to inform what is going on, anything else than "terse" will cause the message to be written both in logfile and to screen
        Write-And-Log $logfilename "vCenter $vCenterServer successfully connected" $error.count "full"

        #get all reachable vmhosts in cluster
        $vmhosts_in_cluster = get-vmhost -location $ClusterName | where-object { ($_.connectionstate -eq "connected") -or ($_.connectionstate -eq "maintenance") }

        #only if we've found some vmhosts
        if ($vmhosts_in_cluster){

            #if no NTP server given - create report only
            if ($NTPSources -eq ""){

                $mode = "checked"
                foreach ($vmhost in $vmhosts_in_cluster){

                        #all OK here
                        $error.Clear()
                        $total_vmhosts += 1
           
                        #display nice progress bar in PowerCLI window
                        write-progress -Activity "Gathering host NTP config report" -Status "Percent complete" -PercentComplete (($total_vmhosts / $vmhosts_in_cluster.count) * 100) -CurrentOperation "$("{0:N2}" -f (($total_vmhosts / $vmhosts_in_cluster.count) * 100))% complete"
                   
                        #retrieve NTPD information
                        $single_vmhosts_timeconfig_info = New-Object PSObject
                        $single_vmhosts_timeconfig_info | Add-Member -Name "VmHostName" -Value $vmhost.name -MemberType NoteProperty
                        $single_vmhosts_timeconfig_info | Add-Member -Name "VmHostTZ" -Value $vmhost.TimeZone -MemberType NoteProperty
                        $ntpservice = $vmhost | get-vmhostservice | Where-Object {$_.key -eq "ntpd"}
                        $single_vmhosts_timeconfig_info | Add-Member -Name "NTPDisRunning" -Value $ntpservice.running -MemberType NoteProperty
                        $single_vmhosts_timeconfig_info | Add-Member -Name "NTPDPolicy" -Value $ntpservice.policy -MemberType NoteProperty
                   
                        #retrieve NTP Servers configured, report only first 5
                        $ntpserver = @($vmhost | get-vmhostntpserver)
                        for ($index = 0; $index -lt 5; $index++){
                            if ($ntpserver[$index]){
                                $single_vmhosts_timeconfig_info | Add-Member -Name "NTPServer$($index)" -Value $ntpserver[$index] -MemberType NoteProperty
                            }
                            else{
                                $single_vmhosts_timeconfig_info | Add-Member -Name "NTPServer$($index)" -Value "none" -MemberType NoteProperty
                            }
                        }
                   
                        #calculate time difference between host and system this script is invoked from
                        $hosttimesystem = get-view $vmhost.ExtensionData.ConfigManager.DateTimeSystem
                        $timedrift = ($hosttimesystem.QueryDateTime() - [DateTime]::UtcNow).TotalSeconds
                   
                        #raise alarm if difference bigger than acceptable
                        if([math]::abs($timedrift) -gt $maxtimedrift){
                            Write-And-Log $logfilename "Time difference exceeded for host $($vmhost.name)!" 1 "full"
                            Write-And-Log $logfilename "Acceptable difference: $("{0:N2}" -f $maxtimedrift)s Current difference: $("{0:N2}" -f $timedrift)s" 1 "full"
                            $total_errors++
                        }
                        $single_vmhosts_timeconfig_info | Add-Member -Name "TimeDrift" -Value $timedrift -MemberType NoteProperty
                   
                        $all_vmhosts_timeconfig_info += $single_vmhosts_timeconfig_info
                        $total_errors += $error.Count
                        Write-And-Log $logfilename "Host $($vmhost.name) added to report" $error.Count "terse"
                }
               
                #export to CSV
                $all_vmhosts_timeconfig_info | Export-Csv -Path $csvoutfile -NoTypeInformation
                Write-And-Log $logfilename "Report created in $($csvoutfile)" $total_errors "full"
            }
           
            #if NTP servers provided - configure them
            else {
           
                #give the engineer invoking the script chance to abort
                Write-And-Log $logfilename "NTP configuration for all vSphere hosts in cluster $ClusterName will be RESET" 1 "full"
                Write-And-Log $logfilename "This is your LAST CHANCE TO ABORT" 1 "full"
                Write-And-Log $logfilename "Press Y + ENTER to continue" 0 "full"
                Write-And-Log $logfilename "Press any other key + ENTER to ABORT..." 1 "full"
                $response = read-host
                if ( $response -ne "Y" ) {
                    write-and-log $logfilename "Operation ABORTED, no changes have been made to NTP settings" 1 "full"
                    #exit
                } else {
               
                    #let's sanitize input a little and leave only NTP servers that respond to ping (from system where this script is invoked!)
                    $NTPSourcesArray = $NTPSources.Split(",") | Where-Object { Test-Connection -ComputerName $_ -Quiet -Count 1}
                    $mode = "configured"
                   
                    #make sure we've got some NTP servers left
                    if ($NTPSourcesArray){
                       
                        foreach ($vmhost in $vmhosts_in_cluster){
                   
                                #all OK here
                                $error.Clear()
                                $total_vmhosts += 1
                           
                                #display nice progress bar in PowerCLI window
                                write-progress -Activity "Configuring NTP for hosts" -Status "Percent complete" -PercentComplete (($total_vmhosts / $vmhosts_in_cluster.count) * 100) -CurrentOperation "$("{0:N2}" -f (($total_vmhosts / $vmhosts_in_cluster.count) * 100))% complete"
                           
                                #stop ntp service on host
                                $ntpservice = $vmhost | get-vmhostservice | Where-Object {$_.key -eq "ntpd"}
                                stop-vmhostservice -HostService $ntpservice -confirm:$False | out-null
                           
                                #clear current NTP servers
                                $current_NTPSources = @($vmhost | get-vmhostntpserver)
                                foreach ($current_NTPSource in $current_NTPSources){
                                        remove-vmhostntpserver -ntpserver $current_NTPSource -vmhost $vmhost -confirm:$false | Out-Null
                                }
                           
                                #and set new NTP servers
                                foreach ($NTPSource in $NTPSourcesArray) {
                                        add-vmhostntpserver -ntpserver $NTPSource -vmhost $vmhost -confirm:$False | out-null
                                }
                           
                                #set service policy to start and stop with host
                                set-vmhostservice -HostService $ntpservice -Policy "on" -confirm:$False | out-null
                           
                                #set vmhost time manually (to avoid problem with too big drift) to match time of system where script is invoked
                                $hosttimesystem = get-view $vmhost.ExtensionData.ConfigManager.DateTimeSystem
                                $hosttimesystem.UpdateDateTime([DateTime]::UtcNow)
                           
                                #finally - start NTP on vmhost
                                start-vmhostservice -HostService $ntpservice -confirm:$False | out-null
                           
                                $total_errors += $error.Count
                                Write-And-Log $logfilename "Host $($vmhost.name) NTP configuration changed" $error.Count "terse"
                        }
                   }    
                   else{
                        Write-And-Log $logfilename "None of NTP servers provided ($NTPSources) is responding, exiting" 1 "full"
                        $total_errors++
                   }    
                }
            }
        }
        else {
            $total_errors += $Error.Count
        }
        $stop_watch.Stop()
        $elapsed_seconds = ($stop_watch.elapsedmilliseconds)/1000
       
        #farewell message before disconnect
        Write-And-Log $logfilename "Total of $total_vmhosts hosts $mode in $("{0:N2}" -f $elapsed_seconds)s, $total_errors ERRORS reported, exiting" $total_errors "full"
       
        #disconnect vCenter
        Disconnect-VIServer -Confirm:$false -Force:$true
    }
    else {
        Write-And-Log $logfilename "Error connecting vCenter server $vCenterServer, exiting" $error.count "full"
    }
}
else {
    write-and-log $logfilename "This script requires PowerCLI 5.1 or greater to run properly" 1 "full"
}
Stop-Transcript

No comments:

Post a Comment

Vmware NSX SSL creation 

Using OpenSSL for NSX Manager SSL import: Creates CSR and 4096 bit KEY Creating NSX 6.4.2 SSL    openssl req -out nsxcert.csr -newkey rsa:40...