はじめに
アカウントが必要だと申請するから作成したのに、全くログインしていない奴とか、最初の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年間(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
は多くの情報を参照して精査出来る為、今回のような長期ログインしていないケース以外には有用な感じ。
適材適所でコマンドを使っていくのがいいね。