【bat】PCの起動時間・稼働時間をログに記録する方法|wmic・PowerShell・タスクスケジューラ・CSV出力まで完全解説

【bat】バッチファイルでPCの起動時間・稼働時間をログに記録する方法 bat

PCの起動時間・稼働時間をバッチファイルで定期記録しておくと、障害調査や運用管理に役立ちます。本記事では wmicnet stats・PowerShell による取得方法の比較から、稼働時間の計算、ログ追記、タスクスケジューラ登録まで体系的に解説します。

この記事で解決できること

  • PCの起動時刻(LastBootUpTime)をバッチファイルで取得する方法
  • 現在時刻 − 起動時刻で稼働時間を計算する方法
  • 起動時刻・稼働時間をログファイルに自動追記する完全スクリプト
  • タスクスケジューラで「ログオン時・定期実行」を自動化する手順
  • wmic・systeminfo・PowerShell の使い分けと注意点
  • ログが肥大化しないようローテーションする方法
スポンサーリンク

取得方法の比較

方法 取得できる情報 特徴
wmic os get LastBootUpTime OS 起動時刻(精密) 純バッチで扱いやすい。Windows 11 22H2 以降で非推奨
systeminfo システム起動時間(文字列) ロケールに依存。実行に 30 秒以上かかることがある
net stats workstation Workstation サービス開始時刻 全エディションで利用可。OS 起動時刻とわずかにずれる
PowerShell Get-CimInstance 起動時刻・稼働時間(計算済み) 最も正確・将来性あり。Windows 11 推奨
Windows 11 環境では PowerShell を推奨
wmic は Windows 11 22H2 以降で非推奨(deprecated)となり、将来的に削除される予定です。Windows 11 が対象の場合は PowerShell の Get-CimInstance を使うのが確実です。

方法1: wmic で起動時刻を取得する(純バッチ)

起動時刻の取得と整形

@echo off
setlocal

REM wmic から LastBootUpTime を取得
REM 出力例: 20250511064823.000000+540
for /f "skip=1 tokens=1" %%A in ('wmic os get LastBootUpTime') do (
    set RAW=%%A
    goto :parse
)
:parse

REM 年月日・時分秒を切り出す
set BOOT_YEAR=%RAW:~0,4%
set BOOT_MON=%RAW:~4,2%
set BOOT_DAY=%RAW:~6,2%
set BOOT_HH=%RAW:~8,2%
set BOOT_MM=%RAW:~10,2%
set BOOT_SS=%RAW:~12,2%

echo 起動時刻: %BOOT_YEAR%/%BOOT_MON%/%BOOT_DAY% %BOOT_HH%:%BOOT_MM%:%BOOT_SS%
endlocal

現在時刻も wmic で取得して整形

@echo off
setlocal

REM 現在時刻(wmic LocalDateTime は %DATE% よりロケール依存が少ない)
for /f "skip=1 tokens=1" %%A in ('wmic os get LocalDateTime') do (
    set NOW_RAW=%%A
    goto :parse_now
)
:parse_now

set NOW=%NOW_RAW:~0,4%/%NOW_RAW:~4,2%/%NOW_RAW:~6,2% %NOW_RAW:~8,2%:%NOW_RAW:~10,2%:%NOW_RAW:~12,2%
echo 現在時刻: %NOW%
endlocal
%DATE% はロケール依存で使いにくい
%DATE% は日本語環境では 2025/05/11、英語環境では Sun 05/11/2025 など形式が異なります。ログに日付を書き込む場合は wmic os get LocalDateTime か PowerShell を使う方がロケールに依存しません。

方法2: net stats workstation で起動時刻を取得

Windows の全エディション(Home 含む)で使えます。ただし、Workstation サービスの開始時刻であり、OS 起動時刻と数秒〜数分ずれる場合があります。

@echo off
setlocal

REM 英語環境: "Statistics since" / 日本語環境: "統計は"
REM findstr で OS 言語に依存しない取得を行う場合は両方を試す
for /f "tokens=2,*" %%A in ('net stats workstation ^| findstr /i "statistics since"') do (
    set SINCE=%%A %%B
    goto :got_since
)
REM 日本語環境向け
for /f "tokens=2,*" %%A in ('net stats workstation ^| find "統計は"') do (
    set SINCE=%%A %%B
    goto :got_since
)
:got_since
echo 稼働開始時刻: %SINCE%
endlocal

方法3: PowerShell で起動時刻・稼働時間を取得(推奨)

PowerShell を使うと、起動時刻と稼働時間を1行で取得できます。Windows 11 環境や wmic が使えない場合はこちらを使ってください。

起動時刻のみ取得

@echo off

REM PowerShell で起動時刻を取得してバッチ変数に格納
powershell -NoProfile -Command "(Get-CimInstance Win32_OperatingSystem).LastBootUpTime.ToString('yyyy/MM/dd HH:mm:ss')" > "%TEMP%oot_time.txt"
set /p BOOT_TIME=< "%TEMP%oot_time.txt"

echo 起動時刻: %BOOT_TIME%

稼働時間(日・時間・分)も計算して取得

@echo off

REM 起動時刻と稼働時間を一括取得
powershell -NoProfile -Command ^
"$os = Get-CimInstance Win32_OperatingSystem;" ^
"$boot = $os.LastBootUpTime;" ^
"$uptime = (Get-Date) - $boot;" ^
"Write-Output ('BOOT=' + $boot.ToString('yyyy/MM/dd HH:mm:ss'));" ^
"Write-Output ('UPTIME=' + $uptime.Days + '日' + $uptime.Hours + '時間' + $uptime.Minutes + '分')" ^
> "%TEMP%uptime_result.txt"

REM 結果をバッチ変数に読み込む
for /f "tokens=1,* delims==" %%K in (%TEMP%uptime_result.txt) do set %%K=%%L

echo 起動時刻: %BOOT%
echo 稼働時間: %UPTIME%

稼働時間をバッチだけで計算する

wmic の起動時刻と現在時刻の差をバッチファイルのみで計算します。日をまたぐ場合の繰り下げ処理も含む実装です。

@echo off
setlocal enabledelayedexpansion

REM 起動時刻を取得
for /f "skip=1 tokens=1" %%A in ('wmic os get LastBootUpTime') do (set BOOT_RAW=%%A & goto :boot_done)
:boot_done
set /a BOOT_H=1%BOOT_RAW:~8,2% - 100
set /a BOOT_M=1%BOOT_RAW:~10,2% - 100
set /a BOOT_S=1%BOOT_RAW:~12,2% - 100

REM 現在時刻を取得
for /f "skip=1 tokens=1" %%A in ('wmic os get LocalDateTime') do (set NOW_RAW=%%A & goto :now_done)
:now_done
set /a NOW_H=1%NOW_RAW:~8,2% - 100
set /a NOW_M=1%NOW_RAW:~10,2% - 100
set /a NOW_S=1%NOW_RAW:~12,2% - 100

REM 秒単位で差を計算
set /a BOOT_TOTAL = BOOT_H*3600 + BOOT_M*60 + BOOT_S
set /a NOW_TOTAL  = NOW_H*3600  + NOW_M*60  + NOW_S
set /a DIFF = NOW_TOTAL - BOOT_TOTAL

REM 日をまたいだ場合(負の値になる)
if !DIFF! LSS 0 set /a DIFF += 86400

REM 時・分・秒に変換
set /a UP_H = DIFF / 3600
set /a UP_M = (DIFF - UP_H*3600) / 60
set /a UP_S = DIFF - UP_H*3600 - UP_M*60

echo 稼働時間: !UP_H!時間 !UP_M!分 !UP_S!秒
endlocal
複数日にまたがる稼働時間の計算
上記のバッチ計算は「当日中の起動」を想定しています。サーバーなど複数日にわたって稼働するケースでは PowerShell の TimeSpan を使って日数も含めて計算する方法を推奨します。

ログファイルに記録する完全スクリプト

起動時刻・稼働時間・現在時刻をログファイルに自動追記する完全版です。PowerShell と純バッチの2バージョンを用意しました。

バージョン A: PowerShell 連携版(推奨・Windows 10/11 向け)

@echo off
setlocal

set LOGFILE=%~dp0pc_uptime_log.txt

REM PowerShell で起動時刻・稼働時間・現在時刻を取得してログに書き込む
powershell -NoProfile -Command ^
"$os = Get-CimInstance Win32_OperatingSystem;" ^
"$boot = $os.LastBootUpTime;" ^
"$now = Get-Date;" ^
"$uptime = $now - $boot;" ^
"$line = '-----------------------------------';" ^
"$line | Add-Content -Path '%LOGFILE%' -Encoding UTF8;" ^
"('記録時刻  : ' + $now.ToString('yyyy/MM/dd HH:mm:ss')) | Add-Content -Path '%LOGFILE%' -Encoding UTF8;" ^
"('起動時刻  : ' + $boot.ToString('yyyy/MM/dd HH:mm:ss')) | Add-Content -Path '%LOGFILE%' -Encoding UTF8;" ^
"('稼働時間  : ' + $uptime.Days + '日' + $uptime.Hours + '時間' + $uptime.Minutes + '分') | Add-Content -Path '%LOGFILE%' -Encoding UTF8"

echo ログを記録しました: %LOGFILE%
endlocal

バージョン B: 純バッチ版(wmic 使用・Windows 7/8/10 向け)

@echo off
setlocal enabledelayedexpansion

set LOGFILE=%~dp0pc_uptime_log.txt

REM 現在時刻を wmic から取得
for /f "skip=1 tokens=1" %%A in ('wmic os get LocalDateTime') do (set NOW_RAW=%%A & goto :now_done)
:now_done
set NOW=%NOW_RAW:~0,4%/%NOW_RAW:~4,2%/%NOW_RAW:~6,2% %NOW_RAW:~8,2%:%NOW_RAW:~10,2%:%NOW_RAW:~12,2%

REM 起動時刻を wmic から取得
for /f "skip=1 tokens=1" %%A in ('wmic os get LastBootUpTime') do (set BOOT_RAW=%%A & goto :boot_done)
:boot_done
set BOOT=%BOOT_RAW:~0,4%/%BOOT_RAW:~4,2%/%BOOT_RAW:~6,2% %BOOT_RAW:~8,2%:%BOOT_RAW:~10,2%:%BOOT_RAW:~12,2%

REM 稼働時間を計算
set /a NOW_H=1%NOW_RAW:~8,2%  - 100
set /a NOW_M=1%NOW_RAW:~10,2% - 100
set /a NOW_S=1%NOW_RAW:~12,2% - 100
set /a BOOT_H=1%BOOT_RAW:~8,2%  - 100
set /a BOOT_M=1%BOOT_RAW:~10,2% - 100
set /a BOOT_S=1%BOOT_RAW:~12,2% - 100

set /a DIFF = (NOW_H - BOOT_H)*3600 + (NOW_M - BOOT_M)*60 + (NOW_S - BOOT_S)
if !DIFF! LSS 0 set /a DIFF += 86400
set /a UP_H = DIFF / 3600
set /a UP_M = (DIFF - UP_H*3600) / 60
set /a UP_S = DIFF - UP_H*3600 - UP_M*60

REM ログに追記
(
    echo -----------------------------------
    echo 記録時刻  : %NOW%
    echo 起動時刻  : %BOOT%
    echo 稼働時間  : !UP_H!時間 !UP_M!分 !UP_S!秒
) >> "%LOGFILE%"

echo ログを記録しました: %LOGFILE%
endlocal

出力されるログ例

-----------------------------------
記録時刻  : 2025/05/11 17:12:33
起動時刻  : 2025/05/11 06:48:23
稼働時間  : 0日10時間24分
-----------------------------------
記録時刻  : 2025/05/12 09:05:10
起動時刻  : 2025/05/12 08:55:02
稼働時間  : 0日0時間10分

タスクスケジューラで自動実行する

GUI から設定する手順

REM タスクスケジューラを開く
taskschd.msc

REM 設定のポイント
REM トリガー: ユーザーのログオン時 / 起動時 / 毎日 N 時
REM 操作: プログラムの開始 → cmd.exe
REM 引数: /c "C:atch
ecord_uptime.bat"
REM 作業フォルダ: C:atch

コマンドラインから登録する

REM ログオン時に実行するタスクを登録(管理者権限で実行)
schtasks /create /tn "PCUptimeLog" ^
  /tr "cmd /c "C:atch
ecord_uptime.bat"" ^
  /sc onlogon /ru "%USERNAME%" /f

REM 毎日 09:00 に実行するタスクを追加
schtasks /create /tn "PCUptimeLogDaily" ^
  /tr "cmd /c "C:atch
ecord_uptime.bat"" ^
  /sc daily /st 09:00 /ru "%USERNAME%" /f

REM 登録内容を確認
schtasks /query /tn "PCUptimeLog" /fo list

REM タスクを削除する場合
schtasks /delete /tn "PCUptimeLog" /f
タスクスケジューラの作業ディレクトリに注意
タスクスケジューラから実行すると作業ディレクトリが C:WindowsSystem32 になります。スクリプト内でログファイルのパスを相対パスで書くと意図しない場所に保存されます。%~dp0 を使ってバッチファイルと同じフォルダに保存するか、絶対パスで指定してください。

ログのローテーション・古いログの削除

@echo off
setlocal

set LOGFILE=%~dp0pc_uptime_log.txt
set MAX_LINES=500

REM ログが MAX_LINES 行を超えたら古い行を削除
for /f %%C in ('find /c /v "" ^< "%LOGFILE%"') do set LINE_COUNT=%%C

if %LINE_COUNT% GTR %MAX_LINES% (
    REM 末尾 MAX_LINES 行だけ残す(PowerShell を利用)
    powershell -NoProfile -Command ^
    "(Get-Content '%LOGFILE%') | Select-Object -Last %MAX_LINES% | Set-Content '%LOGFILE%' -Encoding UTF8"
    echo ログを %MAX_LINES% 行にトリミングしました
)
endlocal

ログの世代管理・自動削除など本格的なローテーションは バッチファイルのログローテーション実装ガイド(日付管理・自動削除・世代管理) で詳しく解説しています。

よくある落とし穴

落とし穴1: wmic が Windows 11 22H2 以降で非推奨

REM wmic os get LastBootUpTime は将来的に削除される可能性がある
REM Windows 11 環境では代わりに PowerShell を使う

REM PowerShell による代替
powershell -NoProfile -Command "(Get-CimInstance Win32_OperatingSystem).LastBootUpTime.ToString('yyyy/MM/dd HH:mm:ss')"

落とし穴2: systeminfo は実行に時間がかかる

REM NG: systeminfo は 30 秒以上かかることがある
for /f "tokens=1,* delims=:" %%a in ('systeminfo ^| find "システム起動時間"') do set BOOT=%%b

REM OK: wmic か PowerShell を使えば 1〜2 秒で取得できる
for /f "skip=1 tokens=1" %%A in ('wmic os get LastBootUpTime') do (set RAW=%%A & goto :done)
:done

落とし穴3: net stats srv は Windows Home で動かない

REM NG: Windows Home には Server サービスが存在しない
net stats srv
REM → エラー: サービス名が正しくありません

REM OK: net stats workstation は全エディションで動く
net stats workstation | findstr /i "statistics since"

落とし穴4: wmic 出力末尾のスペース・改行コード問題

REM wmic の出力には末尾にスペースが含まれることがある
REM 変数展開で文字列切り出し(~8,2 など)を使えば影響を受けない

REM 変数の値を確認するときは [] で囲むと分かりやすい
for /f "skip=1 tokens=1" %%A in ('wmic os get LastBootUpTime') do (set RAW=%%A & goto :done)
:done
echo [%RAW%]   ← 末尾にスペースや不可視文字がないか確認

よくある質問(FAQ)

Q ログをサーバーの共有フォルダに保存したい
A

LOGFILE 変数を UNC パスに変更するだけです。共有フォルダへの書き込み権限があることを確認してください。

REM LOGFILE を共有フォルダのパスに変更
set LOGFILE=\192.168.1.10logspc_uptime_%COMPUTERNAME%.log

REM PC 名をファイル名に含めると複数台の記録を区別しやすい
set LOGFILE=\fileserverlogs\%COMPUTERNAME%_uptime.log
Q 記録したログを CSV 形式で保存したい
A

CSV 形式にすることで Excel で開いて分析しやすくなります。

@echo off
setlocal
set CSVFILE=%~dp0pc_uptime.csv

REM ヘッダー行がなければ追加
if not exist "%CSVFILE%" (
    echo 記録時刻,起動時刻,稼働時間 >> "%CSVFILE%"
)

REM PowerShell で値を取得して CSV に追記
powershell -NoProfile -Command ^
"$os = Get-CimInstance Win32_OperatingSystem;" ^
"$boot = $os.LastBootUpTime;" ^
"$now = Get-Date;" ^
"$up = $now - $boot;" ^
"$row = $now.ToString('yyyy/MM/dd HH:mm:ss') + ',' + $boot.ToString('yyyy/MM/dd HH:mm:ss') + ',' + $up.Days + '日' + $up.Hours + '時間' + $up.Minutes + '分';" ^
"$row | Add-Content -Path '%CSVFILE%' -Encoding UTF8"

echo CSV に記録しました: %CSVFILE%
endlocal
Q 起動時間ではなく「シャットダウン時刻」を記録したい
A

シャットダウン時刻は Windows のシャットダウン時に実行するバッチで現在時刻を記録します。タスクスケジューラのトリガーに「イベント」→「システム シャットダウン」を使います。

REM タスクスケジューラで「シャットダウン開始」イベントを捕捉する
REM トリガー: イベント → ログ: System → ソース: User32 → イベント ID: 1074

schtasks /create /tn "PCShutdownLog" ^
  /tr "cmd /c echo %COMPUTERNAME% %DATE% %TIME% >> C:logsshutdown.log" ^
  /sc onevent /ec System /mo "*[System[Provider[@Name='User32'] and EventID=1074]]" ^
  /ru SYSTEM /f
Q 管理者権限なしでタスクスケジューラに登録できますか?
A

ログオン時・ログオフ時のタスクは一般ユーザーでも登録できます。/ru "%USERNAME%" で自分のアカウントで実行するよう指定してください。スタートアップ(起動時)タスクは管理者権限が必要です。

REM 一般ユーザーでも登録できるログオン時タスク
schtasks /create /tn "PCUptimeLog" ^
  /tr "cmd /c "C:atch
ecord_uptime.bat"" ^
  /sc onlogon /ru "%USERNAME%" /f
Q 複数 PC の起動ログを1か所にまとめたい
A

ログファイル名に %COMPUTERNAME% を含めることで、共有フォルダに PC ごとのログを自動で振り分けられます。

REM PC 名つきのログファイルに記録(共有フォルダ)
set LOGFILE=\fileserveruptimelogs\%COMPUTERNAME%_uptime.log

REM サーバー側で全ファイルをまとめて確認
dir \fileserveruptimelogs*_uptime.log

まとめ

目的 推奨方法
起動時刻を取得(Windows 10 以前) wmic os get LastBootUpTime
起動時刻を取得(Windows 11・将来対応) powershell (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
稼働時間を計算 PowerShell $uptime = (Get-Date) - $boot
ログファイルへの追記 Add-Content -Encoding UTF8 または >> リダイレクト
CSV 形式で保存 PowerShell で値を結合して CSV 追記
自動実行(ログオン時) タスクスケジューラ schtasks /sc onlogon
全エディションで使える起動時刻 net stats workstation(OS 起動時刻と数秒ずれる)

PowerShell との連携パターンの詳細は PowerShell をバッチファイルから呼び出す方法(連携パターンと使い分け) を、ログのサイズ管理・世代交代は バッチファイルのログローテーション実装ガイド(日付管理・自動削除・世代管理) を参照してください。ループ内での変数処理が必要な場合は setlocal enabledelayedexpansion 完全ガイド(FOR内変数・遅延展開) も合わせて確認してください。