1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Windows ActiveDirectory において長期ログインしていない不届き者を暴く

Last updated at Posted at 2023-01-21

はじめに

アカウントが必要だと申請するから作成したのに、全くログインしていない奴とか、最初の1度だけログインしてそれっきりとか。
たまったもんじゃない。
そういう不要アカウントはきっちり滅してあげよう。

前提条件

  • 個人的なポリシーとしてGUIは捨てている。(とカッコつけているだけ)
  • コマンドラインが正義である。(と思いこんでいるだけ)
  • 定期的にコマンドを実行し、その結果をレポートしてくれるととても助かる。

PowerShell+Module ActiveDirectory

先ずは出力

ActiveDirectoryで管理しているユーザの一覧を先ず出力してみよう。

Import-Module ActiveDirectory
Get-ADUser -Filter *

私の環境ではアカウントが数万存在している為、割といい時間「どぅるるるるる」な感じで画面が動いていた。
全部出力したいならば、これで良い。
ちなみに、-Filter *は必須だ。

中にはユーザ一覧をCSV形式で保存したい人もいるだろう。
そんな時は以下のようにすれば良い。

Get-ADUser -Filter * | Export-Csv -Path C:\Users\Administrator\Desktop\Sample.csv
Get-ADUser -Filter * | Export-Csv -Path C:\Users\Administrator\Desktop\Sample.csv -Encoding UTF8

1行目でも出力されるけど、文字化けパラダイスなのできちんとEncodeを指定するとお行儀がいいかもしれない。

なお、特に指定無しのGet-ADUserの場合おり、-Propertiesを付与した方がさらに情報を出すことが出来る。
但し、沢山出るのでびっくりしないように。

Get-ADUser -Filter * -Properties * | Export-Csv -Path C:\Users\Administrator\Desktop\Sample.csv -Encoding UTF8

必要な情報だけに絞る

さて、ActiveDirectoryの情報を出すことは分かったが、情報量が多すぎても困る為、精査することにしよう。
不要な情報を得るのはセキュリティ的にも面倒だし、非効率だし、気が散って仕方がない。

今回欲しい情報は、各アカウントのログイン情報となる。レポートも行うので項目としては以下が想定される。

  • アカウントID【必須】
  • ログイン情報(最終ログイン日時)【必須】
  • ログイン情報(ログイン有無⇒一度でもログインしたかどうか)
  • アカウント表示名or氏名
  • アカウントの有効無効

一先ず、1アカウントのみを指定してどんな項目で情報が出ているか確認しよう。

Get-ADUser -Filter 'SamAccountName -eq "testuser01"' -Properties *

SamAccountNameとはWindowsログイン時に入力しているアカウントIDだと思ってくれていい。
これでどれくらいの情報が出ているかわかるだろう。
脱線するが、出力されるオブジェクトのプロパティのみを確認したい場合は以下のようにすると良い。

# オブジェクトの名前や型、説明
Get-ADUser -Filter 'SamAccountName -eq "testuser01"' -Properties * | Get-Member
# CSVに出しちゃえ
Get-ADUser -Filter 'SamAccountName -eq "testuser01"' -Properties * | Get-Member | Select-Object Name | Export-Csv -Path C:\Users\Administrator\Desktop\Get-ADUser_ObjectName.csv -Encoding UTF8

さらに脱線で…。
-Filterで条件を指定するいくつかのパターンは以下のとおり。

# 完全一致型
Get-ADUser -Filter 'SamAccountName -eq "testuser01"' -Properties *
# 部分一致型
Get-ADUser -Filter 'SamAccountName -like "*testuser01*"' -Properties *
# 他
-and,-or | -gt,-lt,-ne,-ge,-le,-notlike

もっとFilterの指定を確認したい場合は以下のURLから。
https://learn.microsoft.com/en-us/previous-versions/windows/server/hh531527(v=ws.10)

話は戻り、プロパティの名前から推察するに必要そうなものを以下に絞った。

Properties Name Desc
SamAccountName ログインアカウントIDとなる。
LastLogonTimestamp 最終ログイン日時でログインの度に日時が更新され、DC間で共有される。だが更新頻度低めとのこと。
Enabled アカウントの有効無効となる。
logonCount ログイン回数となる。

これを踏まえるとコマンドは以下のようになってくる。

# SamAccountName,Enabledはデフォルトで出力される
Get-ADUser -Filter * -Properties LastLogonTimestamp,logonCount
# 必要なもののみにする場合は以下
Get-ADUser -Filter * -Properties LastLogonTimestamp,logonCount | Select-Object SamAccountName,Enabled,LastLogonTimestamp,logonCount

長期ログインしていないとする条件

さてさて、ようやく本題に入っていくわけなのだが、長期ログインしていないという定義は今回このように考えた。

  1. アカウントが有効である
  2. 現在日時より1年間(365+猶予30日)前に最終ログイン日時である

1.の場合は、-Filterで指定出来るのでその旨盛り込む。
2.の場合は、-Filter内で日付を入れ込むことが出来なかった(技量不足)ので、一旦最初に定義してから判定に盛り込む。

こんな感じになります。

$chkdate = ([DateTime]::Today.AddDays(-395)).ToFileTime()
Get-ADUser -Filter {Enabled -eq $true -and LastLogonTimestamp -lt $chkdate} `
  -Properties LastLogonTimestamp,logonCount |
  Select-Object SamAccountName,Enabled,LastLogonTimestamp,logonCount |
  ForEach-Object {
    $_.SamAccountName
    [DateTime]::FromFileTime($_.LastLogonTimestamp)
    $_.logonCount
  }

日時の取り方についてですが、Get-Dateの方法もあります。
この2つの違いについては、実行結果のとおり。

[DateTime]::Today.AddDays(-395)
#実行結果 2021年12月22日 0:00:00
([DateTime]::Today.AddDays(-395)).ToFileTime()
#実行結果 132845724000000000
(Get-Date).AddDays(-395)
#実行結果 2021年12月22日 16:08:30
((Get-Date).AddDays(-395)).ToFileTime()
#実行結果 132846305104283932

どうして時間が指定されているものとされていないものになっているのだろうか…。これはまた別の機会で調べておく。

レポートとして出力

レポートとして出力しようと思います。
ですが、前述にあるForEach-ObjectをそのままExport-Csvしようとしてもエラーになります。
この為、Export-CsvからOut-Fileに切り替えるのですが、ForEach-Objectのままでは体裁が悪いです。

$chkdate = ([DateTime]::Today.AddDays(-395)).ToFileTime()
Get-ADUser -Filter {Enabled -eq $true -and LastLogonTimestamp -lt $chkdate} `
  -Properties LastLogonTimestamp,logonCount |
  Select-Object SamAccountName,Enabled,LastLogonTimestamp,logonCount |
  ForEach-Object {
    $_.SamAccountName
    [DateTime]::FromFileTime($_.LastLogonTimestamp)
    $_.logonCount
  } | Out-File -FilePath C:\Users\Administrator\Desktop\Sample.csv -Encoding utf8

この為、体裁よくFormat-Tableを使い、出力してみます。

Get-ADUser -Filter {Enabled -eq $true -and LastLogonTimestamp -lt $chkdate} `
  -Properties LastLogonTimestamp,logonCount |
  Select-Object SamAccountName,Enabled,LastLogonTimestamp,logonCount |
  Format-Table SamAccountName,@{name='LastLogonTimestamp';expression={[DateTime]::FromFileTime($_.LastLogonTimestamp)}},logonCount |
  Out-File -FilePath C:\Users\Administrator\Desktop\Sample.csv -Encoding utf8

レポートとしてはいい感じになりました。
可能であれば、CSV形式にしたかったところですが、Out-Fileで出したものをImport-Csvで入れ込み、再度Export-Csvしてみましたがデリミタが上手く出来ず、匙を投げました。
お勉強していつか更新します。
一応、以下のような感じです。

$chkdate = ([DateTime]::Today.AddDays(-395)).ToFileTime()
Get-ADUser -Filter {Enabled -eq $true -and LastLogonTimestamp -lt $chkdate} `
  -Properties LastLogonTimestamp,logonCount |
  Select-Object SamAccountName,Enabled,LastLogonTimestamp,logonCount |
  Format-Table -HideTableHeaders -AutoSize SamAccountName,@{name='LastLogonTimestamp';expression={[DateTime]::FromFileTime($_.LastLogonTimestamp)}},logonCount |
  Out-File -FilePath C:\Users\Administrator\Desktop\Sample.csv -Encoding utf8
$T = Import-Csv -Delimiter " " -Encoding UTF8 -Path C:\Users\Administrator\Desktop\Sample.csv
$T | Export-Csv -Path C:\Users\Administrator\Desktop\Sample2.csv -Encoding UTF8
#フィールドの分割がダメでアカウントIDしか出力されない

これでおしまい、としたいところですが、本記事をあれこれ書いている中で、Search-ADAccountコマンドがあることに気付きました。
今までの記載は何だったん?という結果です…。

Search-ADAccount を使う

こんな感じで利用します。

Search-ADAccount -AccountInactive -DateTime "2022/10/01" -UsersOnly | Select-Object SamAccountName,Enabled,LastLogonDate

ちなみに-Filterが無い為、条件を付与したい場合は、Where-Objectで絞ったうえでSelect-Object+Export-Csvする。
OUの指定をしたい時はDistinguishedNameでマッチする感じかな。

Search-ADAccount -AccountInactive -DateTime "2022/10/01" -UsersOnly | 
  Where-Object { $_.SamAccountName -like "*testuser01*" -and $_.Enabled -eq $true} |
  Select-Object SamAccountName,Enabled,LastLogonDate |
  Export-Csv -Path C:\Users\Administrator\Desktop\Sample.csv -Encoding UTF8

おわりに

Search-ADAccountはユーザ以外にもコンピュータを対象と出来るけど、情報としては少ない。けれども出力としては理想だった。
Get-ADUserは多くの情報を参照して精査出来る為、今回のような長期ログインしていないケース以外には有用な感じ。
適材適所でコマンドを使っていくのがいいね。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?