-
-
Save anonymous/5e97eebc13bcc6357cb8e373cc3eb952 to your computer and use it in GitHub Desktop.
Check Multiple NTP Clients in Powershell
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$cred=get-credential | |
$Time_Server1='time.windows.com' | |
$Time_Server2='time.nist.gov' | |
$HostFileLocation='hostnames.txt' | |
############ Admin must change the parameters accordingly in the above section ########### | |
####### Trim the IP addresses check the port connections for 5985 and 5986 for WimRM Connection ####### | |
####################################################################################################### | |
if (Test-Path $HostFileLocation) | |
{ | |
$HostNamesTrimmed=(gc $hostFileLocation) | foreach { $_.trim() } | |
############### function to check the ports 5985 & 5986 are opened to allow WinRM Connection ############## | |
$HostNamesTrimmed | foreach { | |
$job1=start-job -name job1 -scriptBlock { param($Destination) | |
$Socket1= New-Object Net.Sockets.TcpClient | |
$IAsyncResult1= [IAsyncResult] $Socket1.BeginConnect($Destination,'5985', $null, $null) | |
$success1= $IAsyncResult1.AsyncWaitHandle.WaitOne(100,$true) | |
return $Socket1.Connected | |
$Socket1.close() | |
} -ArgumentList $_ | |
$job2=start-job -name job2 -scriptBlock { param($Destination) | |
$Socket2= New-Object Net.Sockets.TcpClient | |
$IAsyncResult2= [IAsyncResult] $Socket2.BeginConnect($Destination,'5986', $null, $null) | |
$success2= $IAsyncResult2.AsyncWaitHandle.WaitOne(200,$true) | |
return $Socket2.Connected | |
$Socket2.close() | |
} -ArgumentList $_ | |
$Socket1Connected=wait-job -name job1 | receive-job | |
$Socket2Connected=wait-job -name job2 | receive-job | |
remove-job -name job1 | |
remove-job -name job2 | |
if (($Socket1Connected) -OR ($Socket2Connected)) | |
{ | |
[array]$hostlist+=$_ | |
} | |
else | |
{ | |
Write-Host -Fore Red "$_`: Port 5985 or 5986 is not opened for WinRM Connection. Please make sure your system is up and Firewall is allowed" | |
} | |
} | |
} | |
####### If a valid host file not exist, then exit ;P ############## | |
else{ | |
Write-Host -Fore Red "Host file with list of IP addresses is not found. Now exit...";exit; | |
} | |
############### Output the value of time servers to be set #################################### | |
"`n" | |
if ($Time_Server1) | |
{ Write-Host -Fore Cyan "The NTP1 value to be set is $Time_Server1" } | |
if ($Time_Server2) | |
{ Write-Host -Fore Cyan "The NTP2 value to be set is $Time_Server2" } | |
########################## Get the registry info & Time info from WMI call ##################### | |
function get-regkey { | |
[CmdletBinding()] | |
param ( | |
[parameter(ValueFromPipeline=$true, | |
ValueFromPipelineByPropertyName=$true)] | |
[string]$computername="$env:COMPUTERNAME" | |
) | |
PROCESS { | |
$rh = '2147483650' # the value for HKLM | |
$key = 'Software\Microsoft\Windows\CurrentVersion\DateTime\Servers' | |
$reg = [wmiclass]"\\$($computername)\root\default:StdRegprov" | |
$default=$reg.GetStringValue($rh, $key) | |
$server1=$reg.GetStringValue($rh, $key, '1') | |
$server2=$reg.GetStringValue($rh, $key, '2') | |
########### fetch from registry for the NTP parameters ######### | |
if ( !$default.ReturnValue) { $def=$default.sValue } else { $def="The registry Key not Found for $key."} | |
if ( !$server1.ReturnValue) { $serv1=$server1.sValue } else { $serv1="Not Found"} | |
if ( !$server2.ReturnValue) { $serv2=$server2.sValue } else { $serv2="Not Found"} | |
############# fetch the time info from WMI ################## | |
$serviceStatus=(get-service w32time).status | |
$timeinfo=get-wmiobject -class win32_operatingsystem | |
$GMTOffsetInMinutes=[string]($timeinfo.CurrentTimeZone) | |
$currentTime=$timeinfo.ConvertToDateTime($timeinfo.LocalDateTime) | |
$ServerName=$timeinfo.CSName | |
$OSversion=$timeinfo.version | |
############# fetch the TimeZone info from WMI ############### | |
$TimezoneInfo=(Get-WmiObject -class win32_timezone).standardname | |
################### covert the Offset minute value to hour:minute string format ########### | |
if([math]::sign($timeinfo.CurrentTimeZone) -eq 1) | |
{ | |
$t=new-TimeSpan -minutes ($timeinfo.CurrentTimeZone) | |
$GMTOffset='+'+[string]$t.hours+':'+[string]$t.minutes | |
} | |
elseif ([math]::sign($timeinfo.CurrentTimeZone) -eq "-1") | |
{ | |
$t=new-TimeSpan -minutes ([math]::abs($timeinfo.CurrentTimeZone)) | |
$GMTOffset='-'+[string]$t.hours+':'+[string]$t.minutes | |
} | |
return $ServerName,$def,$serv1,$serv2,$currentTime,$serviceStatus,$GMTOffset,$GMTOffsetInMinutes,$TimezoneInfo,$OSversion | |
}} | |
####################### Set the registry info to the values ############################ | |
function set-regkey { param([string]$regValue1='',[string]$regValue2='',[string]$IPAddress,[string]$computername="$env:COMPUTERNAME") | |
$rh = '2147483650' # the value for HKLM | |
$key = 'Software\Microsoft\Windows\CurrentVersion\DateTime\Servers' | |
$reg = [wmiclass]"\\$($computername)\root\default:StdRegprov" | |
if ($regValue1) | |
{ $result1=$reg.SetStringValue($rh, $key, '1', $regValue1) | |
if (!$result1.returnValue) | |
{ Write-Host -fore green "$($IPAddress) has successfully changed the NTP1 Value to $regValue1" } | |
else | |
{Write-Host -Fore Red "$($IPAddress)`:Unknown Error Occurred. Please make sure you have write access to registry. Time Server value is not changed`n" } | |
} | |
if ($regValue2) | |
{ $result2=$reg.SetStringValue($rh, $key, '2', $regValue2) | |
if (!$result2.returnValue) | |
{ Write-Host -fore green "$($IPAddress) has successfully changed the NTP2 Value to $regValue2" } | |
else | |
{ Write-Host -Fore Red "$($IPAddress)`:Unknown Error Occurred. Please make sure you have write access to registry. Time Server value is not changed`n" } | |
} | |
} | |
########## Create the custom Psobject to store the output from invoked action ########## | |
$properties=@{'ServerName'="";'IPAddress'="";'DefSvr'="";'TimeServer1'="";'TimeServer2'="";'CurrentTime'="";'TimeService'="";'GMTOffset'="";'GMTOffsetInMinutes'="";'TimezoneInfo'="";'OSversion'=""} | |
$serverObj= New-Object -TypeName PsObject -Prop $properties | |
$ServiceStopped=0 | |
$output=@() | |
$Timer= [Diagnostics.Stopwatch]::StartNew() ### New starting point of the timer object | |
for ($i=0;$i -lt $hostlist.count; $i++) | |
{ | |
################ Get the Server info and time by calling functions ####################### | |
$temp=Invoke-Command -Computername $hostlist[$i] -Credential $cred -ScriptBlock ${function:get-regkey} | |
$serverObj.ServerName=$temp[0] | |
$serverObj.DefSvr=$temp[1] | |
$serverObj.TimeServer1=$temp[2] | |
$serverObj.TimeServer2=$temp[3] | |
$serverObj.CurrentTime=$temp[4] | |
$serverObj.TimeService=$temp[5] | |
$serverObj.GMTOffset=$temp[6] | |
$serverObj.GMTOffsetInMinutes=$temp[7] | |
$serverObj.TimezoneInfo=$temp[8] | |
$serverObj.OSversion=$temp[9] | |
$serverObj.IPAddress=$hostlist[$i] | |
$output+= $serverObj | select ServerName,IPAddress,TimeService,TimeServer1,TimeServer2,DefSvr,GMTOffset,CurrentTime,GMTOffsetInMinutes,TimezoneInfo,OSversion | |
if ($serverObj.TimeService.Value -eq "Stopped") { $ServiceStopped=1} | |
} | |
$output | ft ServerName,IPAddress,TimeService,TimeServer1,TimeServer2,DefSvr,GMTOffset,TimezoneInfo,CurrentTime -auto | |
############################### Compare the given NTP1 values with the value in registry ############################# | |
if ($Time_Server1) | |
{ | |
$output | foreach { | |
if($_.TimeServer1 -ine $Time_Server1) | |
{ | |
Write-Host -fore red "$($_.IPAddress) does not have a valid NTP Server" | |
[array]$InvalidTimeServer1IPs+=$_.IPAddress | |
} | |
} | |
############## Once user confirmed,Change the NTP1 value of each Servers by calling set-regkey function ################# | |
if($InvalidTimeServer1IPs) | |
{ | |
$ToCorrectNTPServer1=0 | |
do | |
{ | |
[console]::foregroundcolor="yellow" | |
$ToCorrectNTPServer1=Read-Host "Do You want to change First NTP Server value of these $($InvalidTimeServer1IPs.count) Server(s) to $($Time_Server1.Trim())?(y/n)" | |
[console]::foregroundcolor="white" | |
if ($ToCorrectNTPServer1 -eq 'y'){ | |
for ($i=0;$i -lt $InvalidTimeServer1IPs.count;$i++) | |
{ | |
Invoke-Command -Computername $InvalidTimeServer1IPs[$i] -Credential $cred -ScriptBlock ${function:set-regkey} -ArgumentList $Time_Server1,$Null,$InvalidTimeServer1IPs[$i] | |
} | |
$ToCorrectNTPServer1=1 | |
} | |
elseif ($ToCorrectNTPServer1 -eq 'n' ){$ToCorrectNTPServer1=1} | |
else {$ToCorrectNTPServer1=0} | |
} while (!$ToCorrectNTPServer1) | |
} | |
} | |
############################### Compare the given NTP2 values with the value in registry ################## | |
if ($Time_Server2) | |
{ | |
$output | foreach { | |
if($_.TimeServer2 -ine $Time_Server2) | |
{ | |
Write-Host -fore red "$($_.IPAddress) does not have a valid NTP2 Server" | |
[array]$InvalidTimeServer2IPs+=$_.IPAddress | |
} | |
} | |
############## Once user confirmed,Change the NTP2 value of each Servers by calling set-regkey function ################# | |
if($InvalidTimeServer2IPs) | |
{ | |
$ToCorrectNTPServer2=0 | |
do | |
{ | |
[console]::foregroundcolor="yellow" | |
$ToCorrectNTPServer2=Read-Host "Do You want to change Second NTP Server value of these $($InvalidTimeServer2IPs.count) Server(s) to $($Time_Server2.Trim())?(y/n)" | |
[console]::foregroundcolor="white" | |
if ($ToCorrectNTPServer2 -eq 'y'){ | |
for ($i=0;$i -lt $InvalidTimeServer2IPs.count;$i++) | |
{ | |
Invoke-Command -Computername $InvalidTimeServer2IPs[$i] -Credential $cred -ScriptBlock ${function:set-regkey} -ArgumentList $Null,$Time_Server2,$InvalidTimeServer2IPs[$i] | |
} | |
$ToCorrectNTPServer2=1 | |
} | |
elseif ($ToCorrectNTPServer2 -eq 'n' ){$ToCorrectNTPServer2=1} | |
else {$ToCorrectNTPServer2=0} | |
} while (!$ToCorrectNTPServer2) | |
} | |
} | |
if (!($InvalidTimeServer1IPs -AND $InvalidTimeServer2IPs)) | |
{ Write-Host -Fore Green "The NTP settings are correct on All Servers"} | |
################### Find the Standard GMT Offset and output the incorrect TimeZone ############# | |
if (($NumberOfTimeZones=$output | group-object -property TimezoneInfo | sort-object -property count -desc | select -first 1).count -eq 1) | |
{ | |
echo "It have some problems in getting TimeZone information, so using your Time Zone as Default" | |
$GMTOffsetStandard= (Get-WmiObject -class win32_timezone).standardname | |
echo "The Standard Timezone becomes $GMTOffsetStandard" | |
} | |
else | |
{ | |
Write-Host -fore Green "`nGetting Standard Timezone is OK" | |
$GMTOffsetStandard= ($output | group-object -property TimezoneInfo | sort-object -property count -desc | select -first 1).name | |
Write-Host "The Standard Time zone is $GMTOffsetStandard" | |
} | |
#################### Compare each computer's time zone with the standard time zone,by creating TimeZone objects ################ | |
$IncorrectTimeZoneServers=@() | |
$IncorrectTimeZoneServerInfo=New-Object -TypeName PsObject -Property @{IP="";OSversion=""} | |
$output | foreach { | |
if ( $_.TimezoneInfo -eq $GMTOffsetStandard ) | |
{} | |
else { | |
$IncorrectTimeZoneServerInfo.IP=$_.IPAddress | |
$IncorrectTimeZoneServerInfo.OSversion=$_.OSversion | |
Write-Host -fore red "$($_.IPAddress) has a wrong Time Zone" | |
$IncorrectTimeZoneServers+=$IncorrectTimeZoneServerInfo | select IP,OSversion | |
} | |
} | |
###### Prompt the user to change the TimeZone and if yes, take action according to OS version ########### | |
if ($IncorrectTimeZoneServers) | |
{ | |
$ToCorrectTimeZone=0 | |
do | |
{ | |
[console]::foregroundcolor="yellow" | |
$ToCorrectTimeZone=Read-Host "Do you want to correct the incorrect Time Zones?(y/n)" | |
[console]::foregroundcolor="white" | |
if ($ToCorrectTimeZone -eq 'y'){ | |
$IncorrectTimeZoneServers | foreach { | |
if ( $_.OSversion.split('.')[0] -lt 6) | |
{ | |
Invoke-Command -ComputerName $_.IP -Credential $cred -ScriptBlock { param($IP,$NewTimeZone)echo "control.exe timedate.cpl,,/Z$NewTimeZone" | cmd.exe | |
if ((Get-WmiObject -class win32_timezone).StandardName -eq $NewTimeZone) {Write-Host -Fore Green "$IP`:Setting TimeZone is OK"} | |
} -ArgumentList $_.IP,$GMTOffsetStandard | |
} | |
else | |
{ | |
Invoke-Command -ComputerName $_.IP -Credential $cred -ScriptBlock { param($IP,$NewTimeZone)tzutil.exe /s $NewTimeZone | |
if ((Get-WmiObject -class win32_timezone).StandardName -eq $NewTimeZone) {Write-Host -Fore Green "$IP`:Setting TimeZone is OK"} | |
} -ArgumentList $_.IP,$GMTOffsetStandard | |
} | |
} | |
$ToCorrectTimeZone=1 | |
} | |
elseif ($ToCorrectTimeZone -eq 'n' ){$ToCorrectTimeZone=1} | |
else {$ToCorrectTimeZone=0} | |
} while (!$ToCorrectTimeZone) | |
} | |
else | |
{ Write-Host -fore Green "All servers have the correct TimeZone" } | |
############ Find the Standard Time by group-object method on the first two part of time, the 'sec' part is as another property########################## | |
############ Creating Array of Current Time values to find the standard Time ############ | |
$ServerTimeArray=@() | |
$ServerTimeObject=New-Object -TypeName PsObject -Property @{IPAddress="";ComparePart="";LatestPart=""} ## ComparePart is MM/dd/YYYY hh:mm & LatestPart is ss to find avg | |
for($i=0;$i -lt $output.count;$i++) { | |
$TempIPAddress=[string]$output[$i].IPAddress | |
$TempStringFormat=[string]$output[$i].CurrentTime ### the value in CurrentTime is [DateTime] format, so we convert to string | |
$TempFirstPart=$TempStringFormat.split(':')[0] | |
$TempSecondPart=$TempStringFormat.split(':')[1] | |
$ServerTimeObject.IPAddress=$TempIPAddress | |
$ServerTimeObject.ComparePart=$TempFirstPart+':'+$TempSecondPart | |
$ServerTimeObject.LatestPart=$TempStringFormat.split(':')[2] | |
$ServerTimeArray+=$ServerTimeObject | select IPAddress,ComparePart,LatestPart | |
} | |
############ function to find the average sec(s) value of two duplicate server times in minutes ############## | |
function get-AvgSecond() | |
{ | |
$count=($ServerTimeArray | Group-Object -Property ComparePart | sort-object -property count -desc | select -first 1).count | |
$ChosenServerTimeGroup= $ServerTimeArray | Group-Object -Property ComparePart | sort-object -property count -desc | select -first 1 -expandproperty group | |
$ChosenServerTimeGroup | foreach { [int]$LatestPartSum+=$_.LatestPart } | |
return $AvgLatestPart=[math]::round($LatestPartSum/$count) | |
} | |
############ Code to find the the standard time, If not OK, use the local time as standard time ############# | |
if (($ServerTimeArray | Group-Object -Property ComparePart | sort-object -property count -desc | select -first 1).count -eq 1) | |
{ | |
$StandardTime=Get-WMIObject -Class Win32_operatingsystem | |
$StandardTimeExact=$StandardTime.ConvertToDateTime($StandardTime.LocalDateTime) | |
Write-Host -Fore Red "`nCan't choose the Standard Time among servers !" | |
Write-Host -Fore Yellow "So now the Your machine Time $StandardTimeExact becomes the standard time" | |
} | |
else { | |
$StandardTime=($ServerTimeArray | Group-Object -Property ComparePart | sort-object -property count -desc | select -first 1).name | |
#Write-Host "`nThe Standard Time is $StandardTime" ### You can output this value, exact to minutes match | |
$AvgSecond=get-AvgSecond | |
$StandardTimeExact=[datetime]($StandardTime+':'+$AvgSecond) ### cannot validate standardtime among servers, so using average second value | |
Write-Host "`nThe Exact Standard Time is $StandardTimeExact" | |
} | |
########### Compare each computer's time with the standard time(hh:mm only) and prompts the user to change the current value ##### | |
$i=0; | |
$IncorrectTimeServerIPs=@(); | |
$ServerTimeArray | foreach { | |
if ( $_.ComparePart -eq $StandardTime ) | |
{} | |
else { $IncorrectTimeServerIPs+=$_.IPAddress | |
Write-Host -fore Red "$($_.IPAddress) has a wrong Date/Time" | |
} | |
$i++; | |
} | |
########### Check each server has the correct time & prompt user to correct ################### | |
if(!$IncorrectTimeServerIPs.count) | |
{ Write-Host -fore Green "All servers have the Correct Time" } | |
else { | |
$ChangeServerTimeValue=0 | |
do | |
{ | |
[console]::foregroundcolor="yellow" | |
$ChangeServerTimeValue=Read-Host "Do you want to change the value of All time servers to Standard time?(y/n)" | |
[console]::foregroundcolor="white" | |
if ($ChangeServerTimeValue -eq 'y'){ | |
$Timer.stop() | |
Write-Host "The base standard tims is $StandardTimeExact" | |
Write-Host "The elpsed time waiting your confirm is $($Timer.elapsed.seconds) sec" | |
$ApplyTime= $StandardTimeExact.addseconds($Timer.elapsed.seconds) | |
Write-Host "So the new standard time to be apply is $ApplyTime" | |
Invoke-Command -ComputerName $IncorrectTimeServerIPs -Credential $cred -ScriptBlock {param($NewDate) Set-Date $NewDate | out-null} -ArgumentList $ApplyTime | |
$ChangeServerTimeValue=1 | |
} | |
elseif ($ChangeServerTimeValue -eq 'n' ){$ChangeServerTimeValue=1} | |
else {$ChangeServerTimeValue=0} | |
} while (!$ChangeServerTimeValue) | |
} | |
######## Check the stopped services & restart if admin confirms################### | |
if ( $ServiceStopped -eq 1) | |
{ | |
$StoppedServers=$null; | |
#[console]::foregroundcolor="magenta" | |
$StoppedServers+=$output | where { $_.TimeService.Value -eq "Stopped" } | select ServerName,IPAddress,TimeService,TimeServer1,TimeServer2,DefSvr,CurrentTime | |
$StoppedServers | ft ServerName,IPAddress,TimeService -auto | |
#[console]::foregroundcolor="white" | |
$NumberOfStoppedServices=$output | where { $_.TimeService.Value -eq "Stopped" } | measure-object | |
Write-Host -Fore Red "$($NumberOfStoppedServices.count) Time Service(s) are stopped" | |
################ Start the Time Service If admin comfirms #################### | |
$StartServiceConfirm=0 | |
[console]::foregroundcolor="yellow" | |
do | |
{ | |
$StartServiceConfirm=Read-Host "Do you want to start the services?(y/n)" | |
if ($StartServiceConfirm -eq 'y'){ | |
$StoppedServers | foreach { | |
Invoke-Command -COMPUTERNAME $($_.IPAddress) -Credential $cred -ScriptBlock { start-service -name w32time -EA SilentlyContinue} | |
if ((Invoke-Command -COMPUTERNAME $($_.IPAddress) -Credential $cred -ScriptBlock { Get-service -name w32time}).status -eq "Running") | |
{ Write-Host -Fore Green "Windows Time Service has successfully started on $($_.IPAddress)"} | |
else { Write-Host -Fore Red "Cannot start the service on $($_.IPAddress). Please make sure the Time Service is not currently disabled"} | |
} | |
$StartServiceConfirm=1 } | |
elseif ($StartServiceConfirm -eq 'n' ){$StartServiceConfirm=1} | |
else {$StartServiceConfirm=0;} | |
} while (!$StartServiceConfirm) | |
[console]::foregroundcolor="white" | |
} | |
####################### List the NTP Settings after correction ######################### | |
Write-Host "`nThe NTP Status after correction..." | |
$output=@() | |
for ($i=0;$i -lt $hostlist.count; $i++) | |
{ | |
################ Get the Server info and time by calling functions ####################### | |
$temp=Invoke-Command -Computername $hostlist[$i] -Credential $cred -ScriptBlock ${function:get-regkey} | |
$serverObj.ServerName=$temp[0] | |
$serverObj.DefSvr=$temp[1] | |
$serverObj.TimeServer1=$temp[2] | |
$serverObj.TimeServer2=$temp[3] | |
$serverObj.CurrentTime=$temp[4] | |
$serverObj.TimeService=$temp[5] | |
$serverObj.GMTOffset=$temp[6] | |
$serverObj.GMTOffsetInMinutes=$temp[7] | |
$serverObj.TimezoneInfo=$temp[8] | |
$serverObj.OSversion=$temp[9] | |
$serverObj.IPAddress=$hostlist[$i] | |
$output+= $serverObj | select ServerName,IPAddress,TimeService,TimeServer1,TimeServer2,DefSvr,GMTOffset,CurrentTime,GMTOffsetInMinutes,TimezoneInfo,OSversion | |
if ($serverObj.TimeService.Value -eq "Stopped") { $ServiceStopped=1} | |
} | |
[console]::Foregroundcolor="Cyan" | |
$output | ft ServerName,IPAddress,TimeService,TimeServer1,TimeServer2,DefSvr,GMTOffset,TimezoneInfo,CurrentTime -auto | |
[console]::Foregroundcolor="White" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment