Script to disable time synchronization in VM… and more!

Shares

Time synchronization of Guest OS-es running vmware virtual machines is a very important topic that has been extensively covered in VMware documentation.

General recommendation for all types of OS-es is to use external (NTP) time source and not to use VMware Tools time synchronization (with vSphere host) whenever possible.
There are many good reasons for that, including but not limited to reduction of CPU overhead when using external time source.

Unfortunately it is not that obvious that un-ticking “Synchronize guest time with host” checkbox might not be enough in some scenarios.

If you saw Artur’s post from last week, you probably know VMware’s KB 1189 where you can read, that even with above functionality disabled, VMware Tools (by default!) will synchronize time with host upon events like machine (s)vMotion, snapshot creation or restore and Guest OS reboots.

Moreover, while “standard” time synchronization with host can only move your time “forward”, Guest OS time can be also set “backward” (in circumstances where host time is “in the past” compared to Guest OS time) after each of the events listed. This in turn can be a source of many unexpected and unwanted situations, included but not limited to Kerberos authentication problems (if time is skewed by more than 5 minutes) or inability to co-relate event timelines from different vms in your enterprise monitoring / log analytics systems.

This has been a reoccurring topic in many VMware environments I’ve supported, especially when implemented backup software heavily depends on VMware snapshots and volume of protected data is larger than average.

[Update as of July 22nd] Inspired by StanJ comment below – I’d like to stress out that I’m not recommending changing this default VMware Tools behavior for everybody, I’m just sharing a tool that would facilitate this change if you need it in your environment (if you experience time synchronization issues coming from VMware Tools) [/end of Update]

Disabling time synchronization via VMware Tools completely requires change of all 8 advanced settings for each virtual machine. This of course is a weary task if you have anything more than 2 vms in your environment, that’s why I wrote a script to automate this task.

#requires -version 2

<#
.SYNOPSIS
    
    Script can be used to configure advanced settings for all vms in given cluster (changes are saved in .vmx file of each vm found in cluster)  

.DESCRIPTION

    Script takes vCenterServer name and ClusterName as parameters, then loads requested configuration changes from CSV file with predefined name of 
    "adv_settings_list.csv" (file is expected in the same folder where script was invoked from).
    Subsequently the script enumerates all vms from the given cluster EXCLUDING templates and uses New-AdvancedSetting cmdlet to set requested parameters.
    PowerCLI 5.1 or higher is required to use New-AdvancedSetting cmdlet

.PARAMETER vCenterServer

    Mandator parameter indicating vCenter server to connect to (FQDN or IP address)
   
.PARAMETER ClusterName

    Mandator parameter indicating host cluster name where vms need to be reconfigured

.EXAMPLE

    set-vm-adv-settings.ps1 -vCenterServer vcenter.seba.local -ClusterName Production-Cluster

.EXAMPLE

    set-vm-adv-settings.ps1 -vcenter 10.0.0.1 -cluster tdq-cluster

.EXAMPLE

    set-vm-adv-settings.ps1
   
#>

[CmdletBinding()]
Param(
  [Parameter(Mandatory=$True,Position=1)]
   [string]$vCenterServer,
	
   [Parameter(Mandatory=$True)]
   [string]$ClusterName
)


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" 
}

#variables
$ScriptRoot = Split-Path $MyInvocation.MyCommand.Path
$csvfile = "$ScriptRoot\adv_settings_list.csv"
$StartTime = Get-Date -Format "yyyyMMddHHmmss_"
$logfilename = $ScriptRoot + "\" + $StartTime + "Set-VM-Adv-Settings.log"
$transcriptfilename = $ScriptRoot + "\" + $StartTime + "Set-VM-Adv-Settings_Transcript.log"
$total_errors = 0
$total_vms = 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"
	}
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 the vms
		$vms_in_cluster = get-vm -location $ClusterName | where-object {(-not $_.Config.Template)}
    
    	#import the settings to configure
		$settings_list = Import-Csv -Path $csvfile
        
        #only if we've found some vms
		if ($vms_in_cluster){
			foreach ($vm in $vms_in_cluster){
		        
                $total_vms += 1
                
                #display nice progress bar in PowerCLI window
				write-progress -Activity "Configuring advanced settings for virtual machines" -Status "Percent complete" -PercentComplete (($total_vms / $vms_in_cluster.count) * 100) -CurrentOperation "$("{0:N2}" -f (($total_vms / $vms_in_cluster.count) * 100))% complete"
				
				foreach ($setting in $settings_list){
				
					#only if both parameter and value are not empty
            		if (($setting.name -ne "") -and ($setting.value -ne "")){
                
                		#again - assume everything is OK
                		$Error.Clear()
                
                		#configure requested settings
                		New-AdvancedSetting -Entity $vm -Name $setting.name -Value $setting.value -Confirm:$false -Force:$true -ErrorAction SilentlyContinue | Out-Null
                
                		#inform what have you done
                		Write-And-Log $logfilename "Configuring VM $($vm.name), setting $($setting.name) with value of $($setting.value)" $error.count "full"
						$total_errors += $Error.Count
            
            		}
        		}
		}
		}
		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_vms VMs configured 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

Nothing really advanced in this script, it takes vCenter server name and host cluster name as parameters (I assume you want to reconfigure your vms on per cluster basis, but it is really easy to change it to whole datacenter or whatever). Script also expects adv_settings_list.csv file in its working directory. The content of this .csv file are basically parameter name and value pairs, for the use case of disabling vmtools time synchronization the .csv file should look like this:

name,value
tools.syncTime,0
time.synchronize.continue,0
time.synchronize.restore,0
time.synchronize.resume.disk,0
time.synchronize.shrink,0
time.synchronize.tools.startup,0
time.synchronize.tools.enable,0
time.synchronize.resume.host,0

If you want to disable periodic vmware tools time synchronization and time synchronization for snapshot creation event (leaving synchronization on for revert to snapshot operation – just in case you snapshot your memory as well) the adv_setttings_list.csv file should look like this:

name,value
tools.syncTime,0
time.synchronize.continue,0
time.synchronize.restore,1
time.synchronize.resume.disk,1
time.synchronize.shrink,1
time.synchronize.tools.startup,1
time.synchronize.tools.enable,1
time.synchronize.resume.host,1

Values imported from .csv file are fed to New-AdvancedSetting PowerCLI cmdlet, which is executed for every vm found in the cluster, templates are excluded from modification but you can easily revert this condition and modify your templates only. Please note that the first setting (tools.syncTime =0) is corresponding to “Synchronize guest time with host” available directly in GUI.

You need PowerCLI 5.1 or higher to use New-AdvancedSetting cmdlet, if you are still in 4.x zone you might be interested in a custom function created by LucD and Alan Renouf some good time ago already.

Because I want my scripts to look as pr0 as possible especially for this blog I introduced Write-And-Log function that allows you to write colorful messages both to the console and logfile (well OK – they are not colorful in plain-text log file), to keep track what the script was trying to do and where had it failed. I also make use of PowerShell transcript log capabilities, but you can easily turn transcripting off.

Disabling vmtools time synchronization is only one possible use case for this script, in fact you can use it to manipulate any of virtual machine advanced settings, in scenarios like vm security hardening etc.
Just know names of parameters to change and values you want to set then save them in adv_settings_list.csv file and you are ready to go.
Well… you should probably be careful with settings that require Guest OS support, like vMemory HotAdd or vCPU HotPlug capabilities 🙂

To be honest – I tried to experiment with New-AdvancedSetting cmdlet a little and tried to use it also to modify “not-so-advanced” settings. For example I tried to modify ethernet0.virtualDev parameter (type of first vnic for virtual machine that is stored in .vmx file) so that all my vms use vmxnet3 but it failed (obviously *-AdvancedSetting cmdlets weren’t build to change “standard” parameters but I still wanted to give it a try 😉 ).

OK, technically the cmdlet didn’t fail, it hasn’t returned any error, even displayed the new value (vmxnet3) for ethernet0.virtualDev parameter but “in reality” nothing has changed, so it looks like “standard” properties of virtual machine object are protected from being modified by *-AdvancedSetting cmdlets.

I hope you find this script useful, feel free to share and provide your feedback!

0 0 votes
Article Rating

Sebastian Baryło

Successfully jumping to conclusions since 2001.

You may also like...

Subscribe
Notify of
guest
5 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
StanJ

Hi Sebi, Artur, this is ofc useful bit of work but you are not sharing the risks coming from using it?! As I see it if you will run this script across your environment it might be useful but quite dangerous if you (as 99% of the population) would be using AD authentication and you would happen to have only 1gbit links. The reason for my thinking is that if you will start vmotions the time inside of the VM is being slow down to allow vmotion to happen. Once the time difference between AD and the time inside of… Read more »

[…] is sort of like a physical machine getting it from BIOS.  But if you want to not even do that this article can help with that but I would suggest it is NOT necessary under normal […]

[…] The script I would like to share today is in a way supplementary to what I wrote about in my previous post. […]

5
0
Would love your thoughts, please comment.x
()
x

FOR FREE. Download Nutanix port diagrams

Join our mailing list to receive an email with instructions on how to download 19 port diagrams in MS Visio format.

NOTE: if you do not get an email within 1h, check your SPAM filters

You have Successfully Subscribed!

Pin It on Pinterest