Tuesday, October 6, 2009

NTP. PowerShell. It's About Time.

There's no doubt that time is critically important in a computing environment. Given this sensitivity, and the recent recognition that we had rogue hosts improperly configured, I decided to crank out a script that would analyze our environment. I wanted to find whether the NTPD service was running, what the NTP server configuration was, and provide a report of this. Additionally I wanted to have the option (with commenting) to automatically make corrections.

You can find the NTP settings in vCenter server by selecting the host, clicking on the Configuration Tab, and clicking on Time Configuration under Settings

Fortunately our time errors were in or Dev/QA environment and no harm was done but this led me to think "What time is it on our hosts?" Naturally my first step was PowerShell one-liner and since I'm trying to learn I wanted to start out on my own for a little while before pining for help on Google (actually I usually check Hal Rottenberg's book and Alan Renouf's blog http://www.virtu-al.net/ first).

After browsing the commands available I was able to construct this little one-liner to list the host and the running status of each host:

Get-VMHost | Select-Object Name,@{Name="NTP Running";Expression={($_ | Get-VMHostService | Where-Object {$_.key -eq "ntpd"}).Running}} | Sort-Object -Property "NTP Running"

This provided me the following output (redacted of course) showing the host name and a boolean response to whether the NTPD service is running.

Great! I see I have 5 servers that showed False for the NTPD service running. Now time to figure out how they are configured and then either configure or simply restart the service. I now needed to include the NTP server. Running on a little success with quitting time approaching, I hopped on virtu-al.net and lo and behold there was a post with exactly what I was doing. http://www.virtu-al.net/2009/08/14/powercli-do-you-have-the-time/

Adding @{N=“NTPServer“;E={$_ |Get-VMHostNtpServer}}, slightly modified into the Select-Object allowed me to see the NTP server setting as well

Get-VMHost | Select-Object Name,@{Name="NTP Server";Expression={$_ | Get-VMHostNtpServer}}, @{Name="NTP Running";Expression={($_ | Get-VMHostService | Where-Object {$_.key -eq "ntpd"}).Running}} | Sort-Object -Property "NTP Running", "NTP Server"

I immediately notice that I have a couple of hosts pointing to which tells me for sure that things are not configured properly for some hosts in our environment and which would explain why the NTPD service is not running. The remaining servers appear to simply have the service stopped and getting that started is pretty easy with the one-liner provide by Virtu-Al.

Get-VmHostService -VMHost MyHost | Where-Object {$_.key -eq “ntpd“} | Start-VMHostService

Being a scripter the way that I am I really do not want to have to run this for each of the 4 hosts that need their service restarted so time for another script that will update all hosts involved.

I took a break and decided that I wanted a maintenance and reporting script all in one. The end result was to generate a NTP status report that exported the data to a date named CSV. This made the script a little more flexible and allowed me to run multiple steps on the resulting data while providing historical data if I need to help trace NTP problems.

The new script prompts the user (notes for automation are added) as to whether services need to be started on hosts where NTPRunning = False. To solve the other issue of incorrect or non-configured NTP server I included an If statement that checks the configured NTP server and prompts the user and requests a new NTP server/IP to change to. The top of the script provides a place to put a preconfigured value in case you wish to apply this to a maintenance plan or bulk change NTP values.

Download Script - NTP-Maintenance-Generic.txt (convert to .ps1)

--------------Full Script-----------------------------------

#This script is designed to report the status of NTPD service running in your environment by checking each host.
#You are then able to change the configuration of hosts based on old and new values.
#Also able to restart stopped services.
#You should run this script on a machine that has vSphere PowerCLI installed and as a user who has appropriate vCenter server permissions
#to manage host services and configurations.

#Add-PSSnapin VMware.VimAutomation.Core #In case you need to load the VMware snap-in

Connect-VIServer -Server server.domain.com #Enter your vCenter Server

$NtpServer = "" #Provide your default NTP Server. This will be used as default so entering a NTP server when prompted is not necessary
$OldNtpServer = "" #Leave set as as default unless you wish to change settings in your environment
$DefaultNtpServer = "" #NTP Server Value that is set on a fresh ESX installation.

#Location based on Date
$date = Get-Date -UFormat %Y%m%d
$ExportLocation = "C:\NTP-$date.csv"

#Location where you would like report to be saved to.
#$ExportLocation = 'C:\NTPReport.csv'

$NTPHosts = Get-VMHost | Select-Object Name,@{Name="NTPServer";Expression={$_ | Get-VMHostNtpServer}}, @{Name="NTPRunning";Expression={($_ | Get-VMHostService | Where-Object {$_.key -eq "ntpd"}).Running}} | Sort-Object -Property "NTPRunning", "NTPServer"

$NTPHosts | Export-Csv $ExportLocation -NoTypeInformation
& $ExportLocation #Opens generated report file

$Restart = Read-Host "Would you like to start NTPD services or change NTP configurations on hosts? (y/n)"
#$Restart = "y" #Comment above line and uncomment this line if you wish to automatically restart services.
If ($Restart -eq "y"){
Import-Csv $ExportLocation | % {
$vmhost = $_.Name

#Checks the NTP configuration against a value previously determined at the top of script.
If (($_.NTPServer -eq $OldNtpServer) -or ($_.NTPServer -eq $DefaultNtpServer)){
$NtpInput = Read-Host "Some servers are configured with NTP set as $OldNtpServer or $DefaultNtpServer and may need their NTP settings reconfigured. Please enter NTP Server FQDN or IP address. <$NtpServer> is default."

If ($NtpInput -ne "") {
$NtpServer = $NtpInput #Sets $NtpServer to the inputted value and does nothign if left blank. This allows use of default when value is consistent in the environment.
Add-VMHostNtpServer -VMHost $vmhost -NtpServer $NtpServer | Where-Object {$_.NTPServer -eq $OldNtpServer}
Remove-VMHostNtpServer -VMHost $vmhost -NtpServer $OldNtpServer

#Now time to restart any NTPD services that are currently not running.
If ($_.NTPRunning -eq "False") {
Get-VmHostService -VMHost $vmhost | Where-Object {$_.key -eq "ntpd"} | Start-VMHostService
Write-Host "Process Complete"


  1. Nice work and description, Josh. :)

    One way I like to post scripts to my blog is to paste them at http://poshcode.org, and then use the provided < script > tags which produces syntax highlighted code with a handy download link.

  2. Outstanding work! This is the best I've seen by far!