サーバーの起動時間をPowerShellで確認する方法

Windows Serverが最後に再起動した日時は、PowerShellでWin32_OperatingSystemのLastBootUpTimeを取得すると確認できます。現在の標準的な方法はGet-CimInstanceで、旧記事で使われていたGet-WmiObjectはPowerShell 3.0以降CIMコマンドレットに置き換えられています。ただし、起動日時だけでは「正常な計画再起動か、電源断や停止エラーか」「サービスがずっと正常だったか」は分かりません。本記事では、ローカル・複数サーバーの安全な確認、稼働時間計算、タイムゾーン、接続エラー、イベントログによる再起動原因の切り分けまで解説します。

目次

確認できるのは最後の再起動日時と経過時間

Win32_OperatingSystem.LastBootUpTimeは、オペレーティングシステムが最後に再起動した日付と時刻を表す読み取り専用プロパティです。現在時刻との差を取れば稼働時間を計算できます。これは「電源ボタンを押してからログオン画面が出るまで何秒かかったか」というブート性能ではありません。起動処理の遅さを調べる場合は、別途パフォーマンストレースや起動時イベントを使います。

OSの稼働時間が長くても、業務サービス、IISアプリケーションプール、SQL Server、バックアップエージェントなどが途中で再起動している可能性があります。逆にクラスターの役割移動やアプリ再起動だけなら、OSのLastBootUpTimeは変わりません。OS再起動、サービス稼働、アプリ可用性、パッチ適用は別の指標として監視します。起動日時は原因ではなく、調査の基準時刻です。

ローカルサーバーはGet-CimInstanceで取得する

最小のコマンドはGet-CimInstance -ClassName Win32_OperatingSystemです。必要なプロパティだけを取得し、サーバー名、最後の起動日時、サーバー自身のローカル日時、差分のTimeSpanをオブジェクトとして出力すると、後からCSVや監視へ渡しやすくなります。Format-Tableや文字列化は最後の表示段階に限定し、元のDateTimeとTimeSpanを保持します。読み取り専用なので、サーバーを再起動したり設定を変更したりしません。

稼働時間の差分には管理端末のGet-Dateではなく、同じWin32_OperatingSystemから取得したLocalDateTimeを使います。管理端末と対象サーバーの時刻ずれやタイムゾーン差がある環境で、異なる時計を引き算する誤りを減らせます。負の値や不自然に大きい値が出たら、NTP、仮想化基盤、タイムゾーン、対象名を確認し、値をそのまま監視へ登録しません。

$os = Get-CimInstance -ClassName Win32_OperatingSystem -Property CSName, LastBootUpTime, LocalDateTime
$uptime = $os.LocalDateTime - $os.LastBootUpTime

[pscustomobject]@{
    ComputerName   = $os.CSName
    LastBootUpTime = $os.LastBootUpTime
    ServerNow      = $os.LocalDateTime
    Uptime         = $uptime
    UptimeDays     = [math]::Floor($uptime.TotalDays)
}

PowerShell 6以降のローカル確認ならGet-Uptimeも使える

PowerShell 6.0以降にはGet-Uptimeがあり、引数なしでは前回起動からのTimeSpan、-Sinceでは最後の起動を表すDateTimeを返します。高分解能タイマーの起動後tick数を使うため、Win32_OperatingSystem.LastBootUpTimeとの差分計算とはわずかに違う結果になることがあります。秒単位の監視で二つを混在させず、採用した計測方法をメトリック定義へ記録します。

Windows Serverに標準搭載されるWindows PowerShell 5.1だけの環境ではGet-Uptimeが存在しません。その場合もGet-CimInstanceは使えます。バージョン差を吸収するために未署名モジュールを導入したり、実行ポリシーを緩めたりする必要はありません。Get-Uptimeはリモートコンピューターを指定するパラメーターを持たないため、複数サーバーの一覧にはCIMを使います。

Get-Uptime
Get-Uptime -Since

Get-WmiObjectの旧例はGet-CimInstanceへ置き換える

Get-WmiObject -Class Win32_OperatingSystemはWindows PowerShell 5.1で動く既存スクリプトが残っていますが、MicrosoftはPowerShell 3.0以降Get-CimInstanceに置き換えられたと明記しています。新規スクリプトを旧コマンドへ戻さず、CIMオブジェクトのDateTimeプロパティとセッション管理を使います。移行時は出力型、プロパティ名、リモート接続プロトコル、エラー処理が同じだと決めつけず、検証サーバーで比較します。

PowerShell 7環境ではCimCmdletsモジュールはWindowsプラットフォームで利用できます。旧WMIの-ComputerNameと新しいCIMの-ComputerNameは接続方式が同じではありません。コマンド名だけ置換して本番へ配布せず、WSMan、ファイアウォール、認証、委任を確認します。既存の監視がDMTF日時文字列を前提に解析している場合も、CIMが返すDateTimeオブジェクトに合わせてテストします。

複数サーバーは固定リストとtry/catchで一台ずつ確認する

対象はCMDBや承認済み台帳から作った固定リストにし、誤った名前や廃止サーバーを全ドメイン検索から無条件に拾わないようにします。各サーバーをtry/catchで処理すれば、一台の接続失敗で一覧全体を失わず、成功と失敗を同じスキーマで記録できます。サンプルは起動日時と稼働時間を読み取るだけで、再起動、サービス操作、イベント削除は行いません。

エラー詳細には管理環境の情報が含まれる可能性があるため、共有ログへ無制限に保存せず、管理者だけが読める場所へ保持します。Write-Hostで文章を出すのではなくPSCustomObjectを返すと、成功率、最長稼働、取得失敗を後で集計できます。表示用のFormat-Tableは最後に使い、CSVへ保存する場合はFormat-Tableより前のオブジェクトを渡します。

$servers = @('Server01.contoso.com', 'Server02.contoso.com')
$results = foreach ($server in $servers) {
    try {
        $os = Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName $server `
            -Property CSName, LastBootUpTime, LocalDateTime -ErrorAction Stop
        $uptime = $os.LocalDateTime - $os.LastBootUpTime
        [pscustomobject]@{
            ComputerName   = $os.CSName
            LastBootUpTime = $os.LastBootUpTime
            UptimeDays     = [math]::Floor($uptime.TotalDays)
            Status         = 'OK'
            Detail         = $null
        }
    }
    catch {
        [pscustomobject]@{
            ComputerName   = $server
            LastBootUpTime = $null
            UptimeDays     = $null
            Status         = 'Failed'
            Detail         = $_.Exception.Message
        }
    }
}
$results | Sort-Object ComputerName | Format-Table -AutoSize

繰り返し取得する場合はCIMセッションを再利用する

Get-CimInstance -ComputerNameは指定先へ一時的なWSManセッションを作ります。同じサーバーからOS、ディスク、サービスなど複数の情報を続けて取得するなら、New-CimSessionでセッションを作って-CimSessionへ渡す方が接続を再利用できます。処理の最後はRemove-CimSessionをfinallyで呼び、長時間の管理シェルへ不要なセッションを残しません。

リモート接続には名前解決、WSMan、ファイアウォール、認証、対象名前空間の読み取り権限が必要です。現在の資格情報またはGet-Credentialで得たPSCredentialを使い、パスワードをスクリプトやCSVへ平文で記載しません。MicrosoftはCredSSPについて、侵害されたリモート端末から委任資格情報が悪用される危険を警告しています。単なる起動日時の読み取りにCredSSPを選ばず、最小権限の管理経路を使います。

タイムゾーンと時計ずれをレポートに含める

複数拠点のサーバーを並べる時は、表示された起動日時だけをコピーして比較しないでください。チケット、監視、イベントログがJST、UTC、サーバー現地時刻のどれを使うかを明記し、可能ならISO 8601形式とタイムゾーン情報を一緒に保存します。公式のEvent ID 41資料も、evtxの表示時刻はシステム時刻に調整されるためサーバーのタイムゾーンを確認するよう注意しています。

稼働時間は同じサーバーのLocalDateTimeとLastBootUpTimeの差で算出し、絶対時刻を他システムと突き合わせる時だけ共通のUTCへ正規化します。NTP未同期、仮想マシンの時刻補正、手動時計変更があると、時系列の解釈を誤ります。ドメイン時刻階層と監視時刻を確認し、起動日時の前後にログ時刻が逆転している場合は、再起動原因の判断を保留します。

LastBootUpTimeだけでは正常・異常再起動を判定できない

突然再起動したかを調べるには、Systemログのイベントを起動時刻の前後で確認します。MicrosoftのWindows Server資料では、通常再起動の典型はUser32の1074、Kernel-Generalの13、EventLogの6009で、予期しない再起動はKernel-Powerの41とEventLogの6008です。OS起動はKernel-Generalの12、停止エラーからの再起動はWER-SystemErrorReportingの1001が手掛かりになります。イベントIDだけでなくProviderNameも照合します。

Event ID 41は「Windowsが正常終了を確認できなかった」ことを示し、単独では電源、ハードウェア、停止エラー、ハング、強制電源断のどれかを確定できません。BugcheckCode、ダンプ、UPS・ハイパーバイザー・ハードウェア管理ログ、更新履歴、ドライバー・サービス導入、クラスターログを組み合わせます。起動日時を見て自動的に「Windows Updateが原因」と決めつけたり、ドライバーを推測で削除したりしません。

Get-WinEventで再起動前後の履歴を安全に読む

Get-WinEventはローカルまたはリモートのイベントログを読み取れます。FilterHashtableでSystemログ、対象ID、調査開始日を先に絞れば、全イベントを取得してからWhere-Objectで絞るより効率的です。サンプルは直近30日の再起動関連イベントを新しい順に取得し、時刻、ID、Provider、レベル、メッセージを表示します。ログの読み取り権限がない場合はエラーになるため、必要な閲覧権限だけを委任します。

本番のログ保持が短いと、LastBootUpTimeは分かっても前回停止のイベントが既に上書きされていることがあります。重要サーバーはログサイズ、保持、中央収集、時刻同期を設計します。イベントログを原因調査のために消去したり、エラーを隠すためProviderを無効化したりしません。個人名やプロセス名を含む1074のメッセージを外部共有する時は、必要な範囲へ編集します。

$ids = 12, 13, 19, 41, 1001, 1074, 6008, 6009, 7045
$filter = @{
    LogName   = 'System'
    Id        = $ids
    StartTime = (Get-Date).AddDays(-30)
}

Get-WinEvent -FilterHashtable $filter -MaxEvents 200 |
    Select-Object TimeCreated, Id, ProviderName, LevelDisplayName, Message

Windowsクライアントの高速スタートアップは再起動と区別する

この方法をWindowsクライアントにも流用する場合は、高速スタートアップに注意します。Microsoftの電源状態資料では、高速スタートアップはシャットダウン時にユーザーをサインアウトした後、カーネルのセッション0を休止ファイルへ保存するハイブリッド方式です。見た目は完全シャットダウンでも、内部的には休止状態を利用します。メンテナンス後の検証で「シャットダウンして電源投入」を完全なOS再起動と同一視せず、Restartを使い、イベント履歴を確認します。

Windows Serverの計画再起動でも、再起動日時だけをパッチ適用成功の証跡にしません。更新履歴、保留中の再起動、OSビルド、必要サービス、クラスターノード、業務ヘルスチェックを確認します。稼働日数が基準を超えたら即時再起動する自動処理ではなく、パッチポリシー、冗長性、保守時間、利用部門承認に基づいて計画します。

定期監視では取得失敗と予定外の短縮を別アラートにする

監視へ組み込む場合は、LastBootUpTime、UptimeDays、取得時刻、サーバー自身の時刻、取得方法、ステータスを保存します。前回よりLastBootUpTimeが新しくなったら再起動候補、値が取れなければ監視取得失敗として別のアラートにします。取得失敗を「再起動した」と判定せず、逆に長期稼働を「安定」と評価しません。予定再起動台帳と照合し、予定外ならイベント調査を開始します。

正常判定には、時刻同期、バックアップ、パッチ状態、ストレージ、サービス、ポート、アプリケーション合成監視を組み合わせます。しきい値は全サーバー共通ではなく、ドメインコントローラー、クラスター、単体アプリ、検証機の保守設計に合わせます。読み取りスクリプトを定期実行するアカウントには、再起動やサービス制御の権限を与えず、コード署名、ログ保持、結果欠落の監視を行います。

確認チェックリスト

  • LastBootUpTimeを最後のOS再起動日時として扱い、ブート所要時間と混同していない
  • 新規スクリプトではGet-WmiObjectではなくGet-CimInstanceを使用した
  • 稼働時間は同じサーバーのLocalDateTimeとの差で計算した
  • 複数サーバーを固定リスト、try/catch、オブジェクト出力で確認した
  • WSMan・認証・最小権限を確認し、平文資格情報やCredSSP常用を避けた
  • 時刻を比較する時にタイムゾーンとNTP同期を記録した
  • Event IDとProviderを組み合わせ、41単独で原因を断定しなかった
  • 取得失敗、予定外再起動、サービス障害、パッチ状態を別のアラートにした

Windows Serverの最後の起動日時は、Get-CimInstance Win32_OperatingSystemのLastBootUpTimeで確認します。稼働時間は同じサーバーのLocalDateTimeとの差を取り、PowerShell 6以降のローカル端末ではGet-Uptimeも使えます。複数台では固定対象、try/catch、PSCustomObjectを使い、同じ端末へ繰り返し問い合わせるならCIMセッションを再利用します。起動日時だけで再起動理由やサービス正常性は分かりません。1074・13・6009と41・6008などのSystemイベント、BugcheckCode、更新・ハードウェア・仮想化ログを時刻とProvider付きで照合してください。

公式情報・参考資料

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次