Skip to content

Latest commit

 

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Windows Time Fix

Repairs Windows time synchronization on standalone (workgroup) Windows 10 and 11 machines.

If your clock keeps drifting and Windows says "An error occurred while Windows was synchronizing with time.windows.com", this fixes the actual cause instead of forcing a one time resync.

Quick start

Open PowerShell and run:

irm https://rafarrw.github.io/Windows-Time-Fix/run.ps1 | iex

Project page: https://rafarrw.github.io/Windows-Time-Fix/

The short launcher downloads the current script directly from this repository, so Windows-Time-Fix.ps1 remains the single source of truth.

Start with [1] Repair time synchronization (Recommended). It creates a backup and fixes the service, time sources, synchronization settings, and automatic recovery. This is the right choice for most computers.

If the recommended repair finishes but the problem remains, open [A] Advanced options. Use the large clock correction when the clock is wrong by many hours, or rebuild the Windows Time service when its registration appears corrupted. These advanced repairs include everything performed by option 1.

You can also diagnose the current state or exit without making changes. Each operation runs in the same visible PowerShell window. When it finishes, press any key to return to the main menu.

It only asks for administrator rights after you choose a repair option. Windows still shows the normal UAC confirmation, but the elevated worker stays hidden and sends its progress back to the original window.

To only diagnose without changing system settings or requesting elevation:

& ([scriptblock]::Create((irm https://raw.githubusercontent.com/rafarrw/Windows-Time-Fix/main/Windows-Time-Fix.ps1))) -VerifyOnly

Run that first if you want to see what is wrong before changing anything.

Why this exists

Search for this problem and you get the same handful of suggestions repeated in every video and forum thread:

  • Click "Sync now" in Settings
  • Run w32tm /resync
  • Change the server to pool.ntp.org in the Date and Time control panel
  • Restart the Windows Time service
  • Disable your firewall

These either do nothing or fix it until the next reboot. They fail for the same reason: they treat a stopped or misconfigured service as if it were a network problem. Most of the advice never checks whether UDP port 123 actually works, never looks at the Event Log, and never touches the settings that are genuinely wrong.

This script diagnoses first, then changes the specific settings that keep Windows from synchronizing, and verifies the result afterwards.

What actually breaks

On a machine that is not joined to a domain, five things stack up:

  1. The W32Time service is set to Manual with start triggers. One of those triggers is DOMAIN JOINED, which never fires on a workgroup machine. The service ends up stopped, so nothing synchronizes.

  2. There is only one NTP peer, time.windows.com. A single DNS failure at boot (common with Wi-Fi or VPN that comes up late) logs Event 134 and puts the client into exponential backoff: ResolvePeerBackoffMinutes 15 times ResolvePeerBackoffMaxTimes 7, which can reach roughly 16 hours between attempts. It may eventually recover, but can appear stuck for most of a day.

  3. SpecialPollInterval can be huge, commonly 16384 seconds and up to 604800 (one full week), depending on the Windows version and existing configuration.

  4. MaxPosPhaseCorrection and MaxNegPhaseCorrection are capped at 54000 seconds (15 hours). A clock that is further off than that, typically after a dead CMOS battery, gets refused instead of corrected. The script can temporarily lift this limit for one resync when explicitly requested.

  5. There is no safety net for machines whose network only comes up after boot.

The symptom in the Event Log is a recurring Event 36 ("the time service has not synchronized the system time for the last N seconds") along with Source: Free-running System Clock and Last Successful Sync Time: unspecified in w32tm /query /status.

What the script changes

Setting Before (typical) After
Service start type Manual, trigger started Automatic (Delayed Start)
Service start triggers DOMAIN JOINED and custom Removed
NTP peers 1 4 redundant, unreachable ones demoted
SpecialPollInterval often 16384 or 604800 s 3600 s
ResolvePeerBackoffMinutes 15 2
ResolvePeerBackoffMaxTimes 7 (up to 16 h) 3
MaxPos/NegPhaseCorrection typically 54000 s unchanged by default; temporarily lifted with -AllowLargeTimeCorrection, then restored
NTP connectivity not verified every peer tested before any system change
Safety net none scheduled task on boot, every 6 h, and on network connect

Default NTP servers are time.cloudflare.com, time.google.com, pool.ntp.org and time.windows.com. Each one is tested before being written, and any that do not answer are moved to the end of the list as fallbacks.

Options

Running from a downloaded file:

powershell -ExecutionPolicy Bypass -File .\Windows-Time-Fix.ps1
Parameter What it does
-Apply Apply the recommended repair without showing the interactive menu.
-VerifyOnly Diagnose without changing system settings or requesting elevation. Some detailed status queries may be unavailable to non-admin users.
-NtpServers Use your own servers, for example -NtpServers ntp1.corp.local,ntp2.corp.local
-PollSeconds Poll interval, default 3600. Must be between 1024 and 32768.
-Reregister Re-create the W32Time service registration. Only use when the service itself is missing or corrupted.
-AllowDomain Required to run on a domain joined machine. Read the warning below first.
-AllowLargeTimeCorrection Temporarily allow one correction of any size, then restore the previous limits. Only use with trusted NTP servers.
-NoElevate Never prompt for elevation. Fail with a clear message instead. Useful for RMM and automation.

Running without parameters opens the menu. Supplying a parameter runs directly, which keeps the script suitable for automation. Note that irm <url> | iex cannot pass parameters; use the scriptblock form shown in Quick start when you need them.

Verifying the result

Do not trust the script log alone. Check the real state:

w32tm /query /status

You want to see:

Leap Indicator: 0(no warning)
Stratum: 2 (secondary reference - syncd by (S)NTP)
Last Successful Sync Time: <a recent timestamp>
Source: time.cloudflare.com,0x9

If it still says Source: Free-running System Clock or Leap Indicator: 3(not synchronized), it did not work. Open an issue with the output of -VerifyOnly.

Rolling back

Before changing anything, the script exports the current configuration to C:\ProgramData\Windows-Time-Fix-backup-<timestamp>.reg and records the rollback command in the detailed log. To undo:

reg import "C:\ProgramData\Windows-Time-Fix-backup-<timestamp>.reg"
schtasks /delete /tn "Windows-Time-Fix - Resync" /f

Restart Windows afterwards so the Service Control Manager reloads the restored start type and service triggers.

A full technical log of every run is kept at C:\ProgramData\Windows-Time-Fix.log. The normal repair view only shows the main stages and important results; -VerifyOnly shows the detailed diagnostics on screen.

When not to use this

Domain joined machines. They should synchronize from their domain controller using Type=NT5DS. Applying this configuration there breaks the Active Directory time hierarchy. The script detects this and refuses to run unless you pass -AllowDomain.

When outbound UDP 123 is blocked. The script tests every server before changing anything and aborts if none respond, because in that case the problem is a firewall or router and no registry setting can fix it.

Virtual machines that take time from the hypervisor (Hyper-V integration services, VMware Tools) are already synchronized by the host. Fix it there, not in the guest.

A dead CMOS battery. -AllowLargeTimeCorrection can recover the clock once, but it deliberately does not leave unlimited corrections enabled. Replace the battery if the clock resets again after power loss.

Requirements

  • Windows 10 or Windows 11
  • Windows PowerShell 5.1 (ships with Windows) or PowerShell 7
  • Administrator rights to apply changes. -VerifyOnly runs without elevation, although Windows can deny some detailed w32tm status queries to non-admin users.

Hosting your own copy

The script self elevates through a hidden worker and relays its progress to the original PowerShell window. It re-downloads itself for that worker because irm | iex leaves no file on disk to re-launch. If you fork this, edit $ScriptUrl near the top of the script to point at your own raw URL. While it still contains REPLACE-ME, self elevation is skipped on purpose and the script simply asks the user to open an elevated prompt.

License

MIT. See LICENSE.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages