How to Force a Time Synchronization Using PowerShell

Accurate timekeeping is essential across enterprise IT environments. Whether it’s for security auditing, log correlation, Kerberos authentication, or scheduling automation tasks, a correctly synchronized system clock can mean the difference between smooth operation and widespread disruption. Unfortunately, time drift is common on Windows systems, especially those disconnected from Active Directory or with misconfigured time services. This post explores how IT professionals force a time synchronization using PowerShell in Windows—ensuring accuracy and operational reliability.

Background

Windows devices rely on the Windows Time service (W32Time) to synchronize with a reliable time source, typically using the Network Time Protocol (NTP). However, W32Time can sometimes fail to start, drift significantly, or point to invalid time servers. For MSPs and IT administrators managing diverse fleets of endpoints, especially in distributed or hybrid work environments, being able to programmatically inspect and remediate time sync issues is crucial.

The provided PowerShell script addresses this very need. It inspects the current time sync configuration, verifies the Windows Time service, optionally enables and starts it, and then attempts a manual time sync. Along the way, it provides a detailed snapshot of the system’s time zone and sync status, helping IT professionals make informed decisions or troubleshoot deeper time issues.

The Script:

#Requires -Version 5.1

<#
.SYNOPSIS
    Force a time synchronization with the current time settings and display the current time zone and time sync settings.
.DESCRIPTION
    Force a time synchronization with the current time settings and display the current time zone and time sync settings.
By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use.
    Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. 
    Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. 
    Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. 
    Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. 
    Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. 
    Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. 
    EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).

.PARAMETER -EnableAndStartWindowsTimeService
    Enable and start the Windows Time service if it is disabled or not running. This will set the Start Type to 'Automatic.' This service is required to force a time sync.

.EXAMPLE
    ### Current time zone settings: ###

    Id                         : Pacific Standard Time
    DisplayName                : (UTC-08:00) Pacific Time (US & Canada)
    StandardName               : Pacific Standard Time
    DaylightName               : Pacific Daylight Time
    BaseUtcOffset              : -08:00:00
    SupportsDaylightSavingTime : True

    ### Current time sync settings: ###

    Sync Type                      : NTP only
    NTP Servers                    : time.windows.com
    Last Sync Time                 : 5/12/2025 1:05:48 PM
    Last Sync Source               : time.windows.com
    Sync Interval (NTP)            : 10 minutes
    Sync Interval Minimum (Domain) : 1 minutes
    Sync Interval Maximum (Domain) : 546 minutes

    [Info] Attempting to force a sync with current time settings...
    Sending resync command to local computer
    The command completed successfully.

    ### Current time: ###

    Monday, May 12, 2025 1:05:55 PM

.NOTES
    Minimum OS Architecture Supported: Windows 10, Windows Server 2016
    Release Notes: Initial Release
#>

[CmdletBinding()]
param (
    [Parameter()]
    [switch]$EnableAndStartWindowsTimeService = [System.Convert]::ToBoolean($env:EnableAndStartWindowsTimeService)
)

begin {
    function Test-IsElevated {
        [CmdletBinding()]
        param ()
        
        # Get the current Windows identity of the user running the script
        $id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
        
        # Create a WindowsPrincipal object based on the current identity
        $p = New-Object System.Security.Principal.WindowsPrincipal($id)
        
        # Check if the current user is in the Administrator role
        # The function returns $True if the user has administrative privileges, $False otherwise
        # 544 is the value for the Built In Administrators role
        # Reference: https://learn.microsoft.com/en-us/dotnet/api/system.security.principal.windowsbuiltinrole
        $p.IsInRole([System.Security.Principal.WindowsBuiltInRole]'544')
    }
    function Get-TimeSettings {
        # Get the time sync status
        try {
            $StatusOutputFilename = "$env:temp\w32tm_status_output_$(Get-Random).txt"
            Start-Process -FilePath "$env:WinDir\system32\w32tm.exe" -ArgumentList "/query /status" -RedirectStandardOutput $StatusOutputFilename -NoNewWindow -Wait
        }
        catch {
            throw (New-Object System.Exception("Unable to retrieve time sync status."))
        }
        
        # Get the time sync configuration
        try {
            $ConfigOutputFilename = "$env:temp\w32tm_config_output_$(Get-Random).txt"
            Start-Process -FilePath "$env:WinDir\system32\w32tm.exe" -ArgumentList "/query /configuration" -RedirectStandardOutput $ConfigOutputFilename -NoNewWindow -Wait
        }
        catch {
            throw (New-Object System.Exception("Unable to retrieve time sync configuration."))
        }
        
        # Attempt to read the status output file
        try {
            $status = Get-Content $StatusOutputFilename -Encoding Oem
        }
        catch {
            throw (New-Object System.Exception("Unable to read time sync status."))
        }

        # Attempt to read the config output file
        try {
            $config = Get-Content $ConfigOutputFilename -Encoding Oem
        }
        catch {
            throw (New-Object System.Exception("Unable to read time sync configuration."))
        }

        $lastSyncTime = ($status[-4] -replace "^\w+:\s" -replace "^.+: " | Out-String).Trim()
        $lastSyncSource = ($status[-3] -replace "^\w+:\s" -replace "^.+: " -replace ",0x\w" | Out-String).Trim()
        $syncType = (($config | Select-String -Pattern "^Type: ") -replace "Type: " -replace "\(.+$" | Out-String).Trim()

        $regPath = "HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\Parameters"
        $NtpServers = (Get-ItemProperty -Path $regPath -Name "NtpServer" -ErrorAction SilentlyContinue).NtpServer.Trim() -replace ",0x\w" -replace "\s",", "

        $syncType = switch ($syncType) {
            "NTP" { "NTP only" }
            "NT5DS" { "Domain only" }
            "AllSync" { "Domain with NTP as fallback" }
            default { "Unknown" }
        }

        # Get the SpecialPollInterval from the config
        $SpecialPollInterval = ($config | Select-String -Pattern "^SpecialPollInterval: ") -replace "SpecialPollInterval: " -replace "\(.+$"
        # Convert the SpecialPollInterval to minutes
        $SpecialPollIntervalInMinutes = [int]$SpecialPollInterval / 60

        $object = [PSCustomObject]@{
            "Sync Type"         = $syncType
            "NTP Servers"       = $NtpServers
            "Last Sync Time"    = $lastSyncTime
            "Last Sync Source"  = $lastSyncSource
            "Sync Interval (NTP)" = "$SpecialPollIntervalInMinutes minutes"
        }

        # Get the Min and Max poll intervals used for domain time sync
        $regPath = "HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\Config"
        $MinPollInterval = (Get-ItemProperty -Path $regPath -Name "MinPollInterval" -ErrorAction SilentlyContinue).MinPollInterval
        $MaxPollInterval = (Get-ItemProperty -Path $regPath -Name "MaxPollInterval" -ErrorAction SilentlyContinue).MaxPollInterval

        if ($MinPollInterval -and $MaxPollInterval) {
            # These values are actually powers of 2, the resulting value is the amount of seconds
            $MinPollInterval = [math]::Pow(2, $MinPollInterval)
            $MaxPollInterval = [math]::Pow(2, $MaxPollInterval)

            # Convert those seconds to minutes
            $MinPollInterval = [math]::Round($MinPollInterval / 60)
            $MaxPollInterval = [math]::Round($MaxPollInterval / 60)

            # Add the intervals to the object
            $object | Add-Member -MemberType NoteProperty -Name "Sync Interval Minimum (Domain)" -Value "$MinPollInterval minutes"
            $object | Add-Member -MemberType NoteProperty -Name "Sync Interval Maximum (Domain)" -Value "$MaxPollInterval minutes"
        }
        else {
            Write-Host -Object "[Warning] Unable to retrieve the minimum and maximum poll intervals from the registry."
            $object | Add-Member -MemberType NoteProperty -Name "Sync Interval Minimum (Domain)" -Value "Unavailable"
            $object | Add-Member -MemberType NoteProperty -Name "Sync Interval Maximum (Domain)" -Value "Unavailable"
        }

        # Attempt to remove the status output file
        try {
            Remove-Item $StatusOutputFilename -ErrorAction Stop
        }
        catch {
            Write-Host -Object "[Warning] Unable to delete the temporary file '$StatusOutputFilename'."
        }

        # Attempt to remove the config output file
        try {
            Remove-Item $ConfigOutputFilename -ErrorAction Stop
        }
        catch {
            Write-Host -Object "[Warning] Unable to delete the temporary file '$ConfigOutputFilename'."
        }

        return $object
    }
}
process {
    # Attempt to determine if the current session is running with Administrator privileges.
    try {
        $IsElevated = Test-IsElevated -ErrorAction Stop
    }
    catch {
        Write-Host -Object "[Error] $($_.Exception.Message)"
        Write-Host -Object "[Error] Unable to determine if the account '$env:Username' is running with Administrator privileges."
        exit 1
    }
    
    if (!$IsElevated) {
        Write-Host -Object "[Error] Access Denied: Please run with Administrator privileges."
        exit 1
    }

    $ExitCode = 0

    # Get status of Windows Time Service
    # This service is required for time sync
    try {
        $WindowsTimeService = Get-Service -Name "w32time" -ErrorAction Stop
    }
    catch {
        Write-Host -Object "[Error] Unable to retrieve Windows Time service status."
        Write-Host -Object "[Error] $($_.Exception.Message)"
        exit 1
    }

    # Enable the Windows Time service if requested
    if ($EnableAndStartWindowsTimeService) {
        Write-Host -Object "`n[Info] Setting Windows Time service to start up automatically..."

        # Set the start type to automatic if it is not already
        if ($WindowsTimeService.StartType -ne "Automatic") {
            try {
                Set-Service -Name "w32time" -StartupType Automatic -ErrorAction Stop
                Write-Host -Object "[Info] Windows Time service enabled successfully."
            }
            catch {
                Write-Host -Object "[Error] Unable to enable Windows Time service."
                Write-Host -Object "[Error] $($_.Exception.Message)"
                # Set flag to true so that we can skip forcing the sync
                $serviceError = $true
                $ExitCode = 1
            }
        }
        else {
            Write-Host "[Info] Windows Time service is already set to start automatically."
        }

        # Start the Windows Time service if it is not already running
        Write-Host -Object "`n[Info] Starting Windows Time service..."
        if ($WindowsTimeService.Status -ne "Running") {
            try {
                Start-Service -Name "w32time" -WarningAction SilentlyContinue -ErrorAction Stop
                Write-Host -Object "[Info] Windows Time service started successfully."
            }
            catch {
                Write-Host -Object "[Error] Unable to enable Windows Time service."
                Write-Host -Object "[Error] $($_.Exception.Message)"
                # Set flag to true so that we can skip forcing the sync
                $serviceError = $true
                $ExitCode = 1
            }
        }
        else {
            Write-Host "[Info] Windows Time service is already running."
        }
    }
    # Otherwise check if the service is running and set to start automatically, error if not
    else {
        if ($WindowsTimeService.StartType -ne "Automatic") {
            Write-Host "`n[Error] Windows Time service is not set to start automatically. Please use the 'Enable and Start Windows Time Service' option to enable it."
            # Set flag to true so that we can skip forcing the sync
            $serviceError = $true
            $ExitCode = 1
        }
        elseif ($WindowsTimeService.Status -ne "Running") {
            Write-Host "`n[Error] Windows Time service is not running. Please use the 'Enable and Start Windows Time Service' option to start it."
            # Set flag to true so that we can skip forcing the sync
            $serviceError = $true
            $ExitCode = 1
        }
    }

    # Show current time zone settings
    try {
        Write-Host -Object "`n### Current time zone settings: ###`n"
        (Get-TimeZone -ErrorAction Stop | Out-String).Trim()
    }
    catch {
        Write-Host -Object "[Error] Unable to retrieve current time zone settings."
        Write-Host -Object "[Error] $($_.Exception.Message)"
        $ExitCode = 1
    }
    
    # Show current time sync settings if the Windows Time service is running
    if (-not $serviceError) {
        try {
            Write-Host -Object "`n### Current time sync settings: ###`n"
            $timeSettings = Get-TimeSettings -ErrorAction Stop
            ($timeSettings | Format-List | Out-String).Trim()
            if ($timeSettings."Sync Type" -eq "Unknown") {
                Write-Host -Object "`n[Error] Unable to determine the sync type. The time sync settings may not be configured correctly."
                $skipSync = $true
                $ExitCode = 1
            }
        }
        catch {
            Write-Host -Object "[Error] Unable to retrieve current time sync settings."
            $skipSync = $true
            Write-Host -Object "[Error] $($_.Exception.Message)"
            $ExitCode = 1
        }
    }
    else {
        Write-Host -Object "`n[Error] Unable to retrieve current time sync settings because the Windows Time service is not running."
    }

    # Force a sync if Windows Time service is running
    if ($serviceError) {
        Write-Host "`n[Error] Unable to force a time sync because the Windows Time service is not running."
        $ExitCode = 1
    }
    elseif ($skipSync) {
        Write-Host "`n[Error] Unable to force a time sync because the sync type is unknown. Please correct the time sync settings using the 'Time Sync - Configure Settings' script in the Template Library."
    }
    else {
        try {
            Write-Host "`n[Info] Attempting to force a sync with current time settings..."

            # Create a temporary file to store the output
            $ResyncOutputFile = "$env:temp\w32tm_resync_output_$(Get-Random).txt"
            
            # Start the process to force a time sync 
            Start-Process -FilePath "$env:Windir\System32\w32tm.exe" -ArgumentList "/resync" -NoNewWindow -Wait -RedirectStandardOutput $ResyncOutputFile -ErrorAction Stop
        }
        catch {
            Write-Host -Object "[Error] Unable to initiate time sync."
            Write-Host -Object "[Error] $($_.Exception.Message)"
            $ExitCode = 1
        }

        # Make sure the output file exists
        if (Test-Path -Path $ResyncOutputFile) {
            # Read the output of the time sync
            try {
                Get-Content $ResyncOutputFile -Encoding Oem -ErrorAction Stop | Out-Host
            }
            catch {
                Write-Host -Object "[Error] Unable to read the output of the time sync."
                Write-Host -Object "[Error] $($_.Exception.Message)"
                $ExitCode = 1
            }

            # Clean up the output file
            try {
                Remove-Item -Path $ResyncOutputFile -Force -ErrorAction Stop
            }
            catch {
                Write-Host -Object "[Error] Unable to delete the output file."
                Write-Host -Object "[Error] $($_.Exception.Message)"
                $ExitCode = 1
            }
        }
        else {
            Write-Host -Object "[Error] Unable to find the output file."
            $ExitCode = 1
        }
    }
    
    # Show current time
    try {
        Write-Host -Object "`n### Current time: ###"
        Get-Date -DisplayHint DateTime -ErrorAction Stop | Out-Host
    }
    catch {
        Write-Host -Object "[Error] Unable to retrieve current time."
        Write-Host -Object "[Error] $($_.Exception.Message)"
        $ExitCode = 1
    }

    exit $ExitCode
}
end {
    
    
    
}

 

Detailed Breakdown

The script is modular and thorough, making it well-suited for both standalone execution and integration into tools like NinjaOne. Here’s a step-by-step breakdown:

1. Permissions Check

It begins by checking if the script is run with administrative privileges, as time sync actions require elevation.

2. Windows Time Service Validation

It queries the w32time service:

  • If the -EnableAndStartWindowsTimeService flag is passed (or set via environment variable), it sets the service to start automatically and ensures it’s running.
  • Otherwise, it verifies that the service is active, alerting the user if it is not.

3. Display Time Zone and Sync Settings

The script then:

  • Displays the current time zone using Get-TimeZone.
  • Uses w32tm.exe commands to gather sync status and configuration.
  • Parses:
    • NTP servers in use
    • Last sync time and source
    • Sync intervals (NTP and domain-specific)
    • Sync type: NTP, Domain-based (NT5DS), or fallback (AllSync)

4. Force Time Synchronization

If validation passes, it calls w32tm /resync and captures the output, indicating success or detailing errors.

5. Output Current Time

It concludes by displaying the updated system time.

Potential Use Cases

Case Study: Remote Retail Endpoint Drift

A managed service provider supports 300 retail POS systems, many of which are not domain-joined and rely on public NTP servers. Over time, several terminals fall out of sync by several minutes—causing transaction timestamp mismatches with the central billing system.

Using this script through NinjaOne’s scripting module, the IT team pushes it to all affected systems. The script:

  • Validates and starts the Windows Time service,
  • Confirms the NTP server configuration,
  • Resyncs the clock, and
  • Logs current sync settings for auditing.

This proactive fix avoids revenue-impacting delays and reconciliation errors during end-of-day processing.

Comparisons

MethodProsCons
Manual w32tm CommandsQuick one-linersNo validation, error handling, or service checks
Group Policy / Domain ControlAutomatic for AD-joined devicesIneffective for workgroup or remote systems
This PowerShell ScriptFull visibility, automation-ready, supports both AD and non-AD devicesRequires admin access and PowerShell 5.1+

This script bridges the gap between manual troubleshooting and domain-based automation, particularly for hybrid and MSP environments.

FAQs

Q1: Can this script work on non-domain systems?

Yes. It detects sync type and supports NTP-only configurations.

Q2: What if the sync fails?

The script provides specific errors, such as service not running, misconfiguration, or unknown sync type—helping guide remediation.

Q3: Is the script safe to run multiple times?

Absolutely. It checks service states and avoids redundant changes.

Q4: Can I schedule this script?

Yes. It can be scheduled via Task Scheduler, RMM tools like NinjaOne, or embedded in broader remediation workflows.

Implications

A misconfigured time service isn’t just an annoyance—it can lead to serious IT failures. Authentication services (Kerberos), event logs, system monitoring, and even SSL/TLS certificate validation depend on accurate system clocks. By using this script to inspect and enforce synchronization, IT teams mitigate:

  • Security risks due to audit failures,
  • Application errors from time-dependent logic, and
  • Compliance gaps in time-sensitive environments.

Recommendations

  • Always run with administrative privileges.
  • Use the -EnableAndStartWindowsTimeService flag in unattended scripts or RMM tools.
  • Monitor sync settings proactively on remote and non-domain endpoints.
  • Log output from this script into centralized logging platforms for auditing.

For broader automation, consider packaging this with logging/reporting logic and deploying through your RMM of choice.

Final Thoughts

Keeping system clocks synchronized is foundational for IT stability and security. This PowerShell script offers a clear, reliable, and automation-friendly way to enforce time synchronization across environments—whether they’re domain-joined or standalone.

With NinjaOne, IT professionals can take this one step further. By deploying scripts like this through NinjaOne’s automation engine, monitoring success/failure reports, and remediating drift at scale, MSPs can ensure time sync compliance without lifting a finger. Combine this with custom fields and alerts, and time management becomes a set-it-and-forget-it asset.

Next Steps

Building an efficient and effective IT team requires a centralized solution that acts as your core service delivery tool. NinjaOne enables IT teams to monitor, manage, secure, and support all their devices, wherever they are, without the need for complex on-premises infrastructure.

Learn more about NinjaOne Remote Script Deployment, check out a live tour, or start your free trial of the NinjaOne platform.

Categories:

You might also like