Windowsで定期的に時刻を同期する

2020.11.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

カフェチームの山本です。

カフェでは、Windowsマシンでプログラムを実行し、各センサからのデータを統合しています。プログラムでは時刻を取得しているため、Windows OSの時刻が大きくずれてしまう(2秒程度以上)と、正しくデータを処理できません。

基本的には時計が大きくズレることはありませんが、機器(PC)に何かしらの問題があり、時計がずれる場合があり、エラーになるということがありました。

今回は、Windowsの時計がズレないようにするために、Windowsのタスクスケジューラを利用して、同期スクリプトを定期的に実行する方法を調べたので、まとめたいと思います。

今回は予め作成したタスクの設定ファイルをエクスポートして、再利用する方法を利用します。(設定画面でタスクを1から作成することもできますので、そちらでも構いません。)

用意するファイル

以下の2つのファイルを用意します。

タスクが実行する時刻同期するbatファイル(以下、time_syc.bat)

batファイルを作成し、以下の内容をコピペします。スクリプトの置くフォルダはどこでも良いですが、タスクにパスを設定するため、動かさないフォルダに入れておいてください。

for /f "tokens=3 delims=\ " %%A in ('whoami /groups^|find "Mandatory"') do set LEVEL=%%A
if not "%LEVEL%"=="High" (
  powershell -NoProfile -ExecutionPolicy Unrestricted -Command "Start-Process \"%~f0\" -Verb runas"
  exit
)

sc query W32Time | findstr STATE | findstr RUNNING > NUL
if %ERRORLEVEL% neq 0 (
  net start W32Time
  timeout /T 3 > NUL
)

w32tm /resync

実行内容は以下のとおりです。

  • 管理者権限を取得
  • w32timeが開始されていなければ、w32timeを開始(net start W32Time)
  • 同期コマンドを実行(w32tm /resync)

(こちらのサイトを参考にさせていただきました)

Windows 時刻同期コマンド バッチファイル

xmlファイル(タスクの設定ファイル)

タスクスケジューラに登録するタスクの設定ファイルです。任意の場所にファイル(以下、SyncTimeRegularly.xml)を作成し、以下の内容をコピペします。その後、下部の<Command>のパス(PATH_TO_FOLDER)を、先程作成したbatファイルへのパスに変更してください。(作者名を変更したい場合は、<Author>を変更も合わせて変更してください)

<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Date>2020-11-25T11:44:20.2557216</Date>
    <Author>yamahiro</Author>
    <URI>\SyncTimeRegularly</URI>
  </RegistrationInfo>
  <Triggers>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2020-11-25T09:00:00</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <UserId>S-1-12-1-322189039-1255377110-817165714-1761623729</UserId>
      <LogonType>Password</LogonType>
      <RunLevel>HighestAvailable</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>true</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <IdleSettings>
      <StopOnIdleEnd>true</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession>
    <UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>C:\PATH_TO_FOLDER\time_syc.bat</Command>
    </Exec>
  </Actions>
</Task>

この設定内容としては、以下のとおりです。詳しい内容は、次節のタスク設定のウィンドウで確認・変更できます。

  • 毎日9時にスタート、5分間隔で実行
  • 「ログオンしているかにかかわらず実行する」
  • 「最上位の権限で実行する」(→ 管理者権限で実行)
  • 「条件」すべてオフ(→ 常に実行)

設定方法

コマンドで登録することできれば理想的だったのですが、権限周りでうまく行かなかったので、手作業で登録することにしました。

タスク設定

タスクスケジューラにタスクを登録します。

  • まずタスクスケジューラを開きます。Windowsでスタートボタンを押し「タスク」or「task」と入力して、表示されたタスクスケジューラを開きます

  • 右ペイン中の「タスクのインポート」を選択し、ダイアログでXMLファイルを選択します。

  • 修正したい設定箇所があれば、ここで変更してください。
  • 「タスクの作成」ウィンドウが表示されるため、設定内容を確認して「OK」を押します。
  • (このあと実行ユーザとパスワードを求められます)

以上の操作により、定期的にbatファイルが実行され、時計が同期されるように設定することができました。

結果

上記の操作のあと、左ペインの「タスクスケジューラ ライブラリ」を選択するとSyncTimeReglarlyという名前のタスクが追加されていることがわかります。

また、左ペインの「タスクスケジューラ(ローカル)」を選択し、下の方にスクロールしていくと「アクティブなタスク」にSyncTimeReglarlyが登録されており、直近の5分で割り切れる時刻にスケジュールされていることがわかります。

また、少し時間が経ったあと、スタートボタンを押して「日付」と入力し、「日付と時刻を変更する」を選択して表示されるウィンドウ中の、「時刻を同期する」の「前回成功した時刻の同期」をみると、スケジュールされていた時刻に同期処理が実行されたことがわかります。

まとめ

Windowsの時計がズレてしまうという問題に対し、タスクスケジューラを利用して、定期的に同期スクリプトを実行する方法で解決することができました。

参考にさせていただいたページ・サイト

Windows 時刻同期コマンド バッチファイル