PowerShellで最終ログオン日一覧を作る方法|ADをCSV出力する手順と注意点

PowerShellで最終ログオン日一覧を作るなら、最短ルートは Get-ADUser -Filter * -Properties LastLogonDate で AD ユーザーを取得し、Export-Csv で一覧化する方法です。まずここから始めれば、棚卸しや定期レポートはかなり楽になります。
ただし、LastLogonDate は PowerShell の AD オブジェクトが持つ派生プロパティで、元は lastLogonTimestamp です。手軽に一覧化するには向きますが、退職者の停止判断や監査のように厳密な時刻が必要な場面では、全ドメイン コントローラーの lastLogon を集計する必要があります。この記事では、すぐ使える基本スクリプトから、OU 単位の絞り込み、CSV 出力、失敗しやすい点、精度が必要な場合の代替策まで、迷わず進められる形で整理します。 (Microsoft Learn)

目次

PowerShellで最終ログオン日一覧を作るなら、まずこの形

オンプレミスの Active Directory で、まず一覧を作りたいだけなら、Get-ADUser に LastLogonDate を追加プロパティとして指定して取得するのがいちばん扱いやすい方法です。Get-ADUser は複数ユーザーの検索に使え、既定では限られたプロパティしか返さないため、LastLogonDate のような追加項目は -Properties で明示します。 (Microsoft Learn)

まずは画面で確認する

Import-Module ActiveDirectory

Get-ADUser -Filter * -Properties DisplayName, Enabled, LastLogonDate |
    Select-Object SamAccountName, DisplayName, Enabled, LastLogonDate |
    Sort-Object LastLogonDate -Descending

最初は CSV にせず、コンソールで数件だけ確認するのがおすすめです。意図したユーザーが出るか、日付が空欄のアカウントが混ざっていないかを先に見ておくと、後の手戻りが減ります。

CSVで保存する

Import-Module ActiveDirectory

New-Item -ItemType Directory -Path 'C:\Temp' -Force | Out-Null

Get-ADUser -Filter * -Properties DisplayName, Enabled, LastLogonDate |
    Select-Object SamAccountName, DisplayName, Enabled, LastLogonDate, DistinguishedName |
    Sort-Object LastLogonDate -Descending |
    Export-Csv -Path 'C:\Temp\AD-LastLogonDate.csv' -NoTypeInformation -Encoding UTF8

Export-Csv は区切り文字やエンコードを指定できます。-NoTypeInformation は #TYPE 行を消すための定番指定です。Excel で開いたときに列が崩れる環境では、後述の -UseCulture を使うと改善しやすくなります。 (Microsoft Learn)

先に理解したい LastLogonDate と lastLogon の違い

最終ログオン関連で混同しやすいのは、LastLogonDate、lastLogonTimestamp、lastLogon の3つです。LastLogonDate は PowerShell 側の派生プロパティで、元は lastLogonTimestamp です。lastLogonTimestamp は DC 間で複製される一方、更新はリアルタイムではなく、更新タイミングは msDS-LogonTimeSyncInterval の影響を受けます。lastLogon は DC ごとに別管理され、正確な値を出すには全 DC を見て最大値を採る必要があります。 (Microsoft Learn)

項目向いている用途注意点
LastLogonDate日常の一覧作成、CSVレポート手軽だが厳密な最終ログオン時刻ではない
lastLogonTimestamp非アクティブ候補の把握更新遅延があり、即時反映を期待しにくい
lastLogon監査、無効化前の最終確認全 DC 照会が必要で、件数が多いと重い

迷ったら、一覧作成は LastLogonDate、削除や停止の判断前チェックは lastLogon と覚えておくと外しにくいです。 (Microsoft Learn)

実行前の前提条件

この記事の手順は、オンプレミスの Active Directory Domain Services を前提にしています。Microsoft Learn では、Active Directory モジュールは AD DS / AD LDS を管理するためのモジュールとして案内されており、読み込みは Import-Module ActiveDirectory で行えます。Windows クライアントでは RSAT を機能として追加し、Windows 11 は Pro / Enterprise エディションが前提です。Windows Server では Install-WindowsFeature で AD 関連ツールを導入できます。 (Microsoft Learn)

Windowsクライアントで準備する

Get-WindowsCapability -Online | Where-Object Name -like 'RSAT*'

Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0

Import-Module ActiveDirectory

Windows Serverで準備する

Install-WindowsFeature -Name RSAT-AD-Tools -IncludeAllSubFeature

Import-Module ActiveDirectory

Get-ADUser が見つからないときは、まず RSAT と ActiveDirectory モジュールを疑うのが近道です。PowerShell を開き直しても解決しない場合は、Get-Module -ListAvailable ActiveDirectory で存在確認をすると切り分けが早くなります。

よく使う絞り込みパターン

Get-ADUser は -Filter で条件を付けられ、-SearchBase で検索範囲の AD パスを絞れます。SearchBase には OU 名だけではなく、OU=Users,DC=example,DC=com のような DN 形式を入れるのがポイントです。 (Microsoft Learn)

有効ユーザーだけに絞る

Get-ADUser -Filter { Enabled -eq $true } -Properties DisplayName, LastLogonDate |
    Select-Object SamAccountName, DisplayName, LastLogonDate |
    Sort-Object LastLogonDate -Descending

無効化済みユーザーを除いて、運用中アカウントだけを見たいときに向いています。定期レポートは、まずこの形から始めるとノイズが減ります。

特定OUだけを対象にする

$searchBase = 'OU=Users,OU=Tokyo,DC=example,DC=com'

Get-ADUser -Filter { Enabled -eq $true } -SearchBase $searchBase -Properties DisplayName, LastLogonDate |
    Select-Object SamAccountName, DisplayName, LastLogonDate |
    Sort-Object LastLogonDate -Descending

全ドメインを一気に回す前に、まず対象 OU だけで試すのが安全です。結果確認も速く、誤った DN を入れたときの切り分けもしやすくなります。

90日以上ログオンがない候補を出す

$threshold = (Get-Date).AddDays(-90)

Get-ADUser -Filter { Enabled -eq $true } -Properties DisplayName, LastLogonDate |
    Where-Object { -not $_.LastLogonDate -or $_.LastLogonDate -lt $threshold } |
    Select-Object SamAccountName, DisplayName, LastLogonDate |
    Sort-Object LastLogonDate

この形なら、90日以上前のユーザーだけでなく、LastLogonDate が入っていないアカウントも一緒に拾えます。新規作成だけされて未使用のアカウントを見落としたくないときに便利です。

非アクティブ候補の抽出が目的なら、Search-ADAccount -AccountInactive -UsersOnly -TimeSpan (New-TimeSpan -Days 90) も使えます。こちらは期間指定のための専用コマンドで、TimeSpan または DateTime を使って閾値を指定できます。ただし、一覧レポートとして列を整えたいときは Get-ADUser ベースの方が扱いやすいです。なお、この判定は Windows Server 2003 のドメイン機能レベル以上が前提です。 (Microsoft Learn)

正確な最終ログオン時刻が必要なときは、全DCの lastLogon を集計する

lastLogon は複製されない属性なので、ドメイン内の正確な最終ログオンを知りたい場合は、各ドメイン コントローラーから取得して最大値を使う必要があります。DC 一覧の取得には Get-ADDomainController を使えます。つまり、無効化や削除の最終判断に使うレポートは、LastLogonDate の簡易一覧ではなく、この方法で別取りするのが安全です。 (Microsoft Learn)

Import-Module ActiveDirectory

$searchBase = 'OU=Users,OU=Tokyo,DC=example,DC=com'
$dcs = Get-ADDomainController -Filter *

$latest = @{}

foreach ($dc in $dcs) {
    try {
        $users = Get-ADUser -Server $dc.HostName -SearchBase $searchBase -Filter * -Properties DisplayName, Enabled, lastLogon

        foreach ($user in $users) {
            if (-not $user.Enabled) { continue }

            $key = $user.ObjectGUID.ToString()
            $raw = [int64]$user.lastLogon

            if (-not $latest.ContainsKey($key) -or $raw -gt $latest[$key].LastLogonRaw) {
                $latest[$key] = [pscustomobject]@{
                    SamAccountName = $user.SamAccountName
                    DisplayName    = $user.DisplayName
                    LastLogon      = if ($raw -gt 0) { [datetime]::FromFileTime($raw) } else { $null }
                    SourceDC       = $dc.HostName
                    LastLogonRaw   = $raw
                }
            }
        }
    }
    catch {
        Write-Warning "$($dc.HostName) の取得に失敗しました: $($_.Exception.Message)"
    }
}

New-Item -ItemType Directory -Path 'C:\Temp' -Force | Out-Null

$latest.Values |
    Select-Object SamAccountName, DisplayName, LastLogon, SourceDC |
    Sort-Object LastLogon -Descending |
    Export-Csv -Path 'C:\Temp\AD-ExactLastLogon.csv' -NoTypeInformation -Encoding UTF8

このスクリプトは実務向きですが、負荷はそれなりにあります。いきなり全ドメインで回すのではなく、まず 1 OU か、停止候補だけに絞って実行した方が現実的です。
月次レポートまでこれで回す必要はほとんどありません。普段は LastLogonDate、判断の最終段階だけ lastLogon に切り替える運用がバランスを取りやすいです。

失敗しやすいポイントと対処

つまずきやすいのは、モジュール未導入、属性の取り違え、CSV の区切り文字、検索範囲の広げすぎです。特に LastLogonDate と lastLogon を同じ意味で扱うと、レポートは作れても判断を誤りやすくなります。Export-Csv は -UseCulture で現在のカルチャの区切り文字を使えるので、Excel で1列に見えるときはまずここを疑うと早いです。 (Microsoft Learn)

症状よくある原因まずやること
Get-ADUser が使えないRSAT / ActiveDirectory モジュールが未準備RSAT を入れて Import-Module ActiveDirectory
GUIや別レポートと日付が合わないLastLogonDate と lastLogon を混同している目的に応じて属性を使い分ける
CSVをExcelで開くと1列になる区切り文字がロケールと合っていないExport-Csv -UseCulture を付ける
全件取得が重いいきなり全ドメインを対象にしている-SearchBase で OU 単位に分ける

CSV が崩れる環境では、出力行を次のように変えるだけで改善することがあります。

Export-Csv -Path 'C:\Temp\AD-LastLogonDate.csv' -NoTypeInformation -Encoding UTF8 -UseCulture

戻し方と代替策

この記事で使っている Get-ADUser、Get-ADDomainController、Search-ADAccount、Export-Csv は、一覧取得と出力が中心です。AD オブジェクト自体を書き換えないので、基本的に「戻し方」は不要です。不要になった CSV を削除すれば十分です。

代替策の選び方は、次の3つで考えると迷いません。

目的選ぶ方法
まず一覧を作りたいGet-ADUser + LastLogonDate
長期間未使用の候補を洗い出したいSearch-ADAccount -AccountInactive
正確な最終ログオンを確認したい全 DC の lastLogon を集計

Search-ADAccount -AccountInactive は期間指定の専用手段として便利ですが、厳密な最終ログオン時刻そのものを保証する用途ではありません。停止や削除の前には、必要な範囲だけでも lastLogon を取り直す方が安全です。 (Microsoft Learn)

迷ったらこの順番で進める

  1. まずは Get-ADUser + LastLogonDate で、対象 OU の一覧を小さく出す
  2. 問題なければ CSV 出力に切り替える
  3. 停止候補や削除候補だけを抽出する
  4. 実際に無効化する前に、その候補だけ全 DC の lastLogon で再確認する

PowerShellで最終ログオン日一覧を作る作業は、最初から完璧な精度を狙うより、一覧作成と最終確認を分ける 方が運用しやすくなります。
日常業務のレポートは LastLogonDate、判断が重い場面だけ lastLogon。この切り分けにしておくと、速さと正確さの両方を無理なく両立できます。

この記事を書いた人

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

コメント

コメントする

目次