find-inactive-user-accounts-in-your-domain

アクティブでないユーザーアカウントの検出

アクティブでないユーザーアカウントの検出

Active Directory は、ユーザー、コンピュータ、および関連オブジェクトに関する情報を保持するディレクトリサービスです。このブログでは、ドメイン内のアクティブでないユーザーアカウントを検出する方法を説明します。

Active Directory は、関連性を維持して有用であり続けるために長期にわたるメンテナンスが必要なリレーショナル情報のデータベースです。アカウントが使用されなくなっても、特に何もしなければ存在し続けることになります。Active Directory でそのようなアクティブでないアカウントを見つけることは、それほど単純な作業ではありません。Active Directory のアクティブでないユーザーアカウントを検出し、それらを自動的に削除するにはどうすればいいでしょうか?

検索条件の定義

まず、このプロセスに何が必要かを考えましょう。長期間ネットワークにログインしていないユーザーのアカウントを見つけることが目標になります。アクティブでないことを判定する指標として、90日間または120日間アクティビティがないという数値を使うことは適切だと思いますが、事情によっては14日間ぐらいの数値を使った方がいい場合もあるかもしれません。どの数値を使うべきかは、完全に組織の事情に依存します。休暇、家族の緊急事態、入院や長期療養などのためにオフィスを離れるケースを考慮しても、一般的には、90日間は、リーズナブルな設定でしょう。ここでは、アカウントの非アクティブ状態が90日間に達したら、そのアカウントを無効にして別の OU に移動することにします。

検索条件が定義できれば、それを満たすルールセットが設定できます。

  • 90日間ログオンのアクティビティがないアクティブ設定になっているアカウントを検出して、それを無効にする
  • 無効になった各アカウントを無効ユーザー OU に移動する
  • 無効になったユーザーには自動化プロセスによって無効にされたというコメントをつける

プロパティ情報の中からアクティブでないことを示すものを見つける

各ユーザーアカウントには、ログオン情報に関連するいくつかのプロパティがあります。プロパティ情報の中から、最終ログオン時刻を示すプロパティを見つけられれば、指定日時以降にログオンしていないアカウントがないか照会することができます。上記のルールセットすべてを、PowerShell を使用してコード化できます。

Get-ADUser は、ユーザー情報を表示するために最もよく使用されるコマンドレットです。Get-ADObjectSearch-ADAccount も使用可能ですが、このタスクに最適なコマンドレットは Get-ADUser です。ユーザープロパティをすべて表示するには、コマンドレット構文に -properties * を追加する必要があります。これがないと、デフォルトである10個までのプロパティしか表示されません。

Get-ADUser Michael_Kanakos -Properties *

このクエリに対して返ってくるのは150以上のフィールドのある長いリストになるので、もう少し絞り込む必要があります。そのために、ワイルドカードを使用して、特定の単語を含むプロパティだけを検索することができます。ここでは、ログオン関連のフィールドを検索したいので、logon という単語を含むプロパティを検索することにします。

いったん、PowerShell にすべてのプロパティを取得するように指示して、その中から logon という単語に一致するプロパティだけを選択表示するように、Select-Object を使います。左側の結果を取得して右側に渡す ”|”(「パイプ」と呼ばれます)で区切って、Select-Object を実行します。Select-Object はワイルドカードにマッチングするものだけを表示します。

Get-ADUser username -Properties * | Select-Object *logon*

BadLogonCount          : 0
lastLogon              : 132181280348543735
LastLogonDate          : 11/11/2019 9:08:45 PM
lastLogonTimestamp     : 132179981259860013
logonCount             : 328
LogonWorkstations      :
MNSLogonAccount        : False
SmartcardLogonRequired : False

結果は、Active Directory のドメイン機能レベルによって多少異なります。筆者の環境で行った検索では、8つのプロパティが返ってきました。それらしいのは、LastLogonLastLogonDate、そして LastLogonTimeStamp の3つのプロパティ情報です。Active Directory が日付/時刻情報をどう保存するかをよく知らないと、わけのわからない値に見えるかもしれませんが、通常の日時データのほかに、「ティック (tick)」で保存される日時情報があります。

PowerShell と .NET Framework の日付/時刻値は、0001年1月1日午前0時を0として始め、それ以降のティック数をカウントしたもので表現します。ティックは一千万分の1秒に相当し、1ミリ秒は10,000ティックになります。ティックを標準の日付形式に変換できる数学コマンドレットがあります。

ティック値を通常の日付/時刻形式に変換したものを確認したい場合は、Active Directory User and Computers または Active Directory Administrative Center で確認できます

ADUser-Logon-Propertes

[ADUser の Logon プロパティ]

Logon プロパティの説明

検出された、日付/時刻ログオン情報を示す3つのプロパティのうち、2つのプロパティの日付と時刻は同じですが、1つは異なります。どういうことでしょうか?

日付/時刻情報の違いは仕様によるものであり、すべてのログオン情報を同期させようとする複製トラフィックでDCがクラッシュするのを防ぐために設けられています。LastLogon プロパティは認証するたびに更新されますが、データは認証したDCに保存され、他のDCには複製されません。LastLogonTimeStampLastLogonDate プロパティはすべてのDCに複製されますが、複製は頻繁には行われません。

日付/時刻情報を比較すると、複製の頻度がクエリにどのように影響するかがわかります。この例では、LastLogonTimeStamp の情報は、実際には2日遅れています。ユーザーが対話的にログオンし、ネットワークファイル共有にアクセスし、その他のアカウントの認証を必要とするアクティビティを実行するたびに、ログオン情報が Active Directory に保存されます。誰かがネットワーク上の何かにアクセスするたびに、必ずそのデータをDCに複製しようとすると、特に大規模な環境ではDCがパンクしてしまう可能性があります。そのため、一部のログオン情報は正確でも複製はされず、別のログオン情報は複製されるものの、低い頻度での複製になります。

今回のようなタスクのためには、正確なログオンタイムスタンプは必要ありません。長期間(90日間以上)ログオンしていないアカウントを見つければよく、日付が数日ずれていても問題にはなりません。ログオンの日付を照会するときに、どのプロパティ情報を使用するかによって、11/11または11/13が返ってくるでしょう。最後のログオンから90日間が経過したら非アクティブとしてフラグを立てる場合、ある時点では一方のフィールドを使うとフラグが立ち、別のフィールドを使うとフラグが立たないということもあります。ですが、このプロセスを毎月実行するように設定した場合、次にチェックしたときには前回フラグが立たなかったフィールドでも非アクティブのフラグが立ちます。つまり、定期的に行うようにすれば、一貫してチェックしている限り、どちらのフィールドでも使用できます。

ここでは、次の2つの理由で、LastLogonDate プロパティを使用しました。まず、既に日付値であるため、ティック値を通常の日付情報に変換する必要がありません。2つ目の理由は、このログオン情報が複製されているからです。複製されない LastLogon プロパティを使用した場合、ネットワーク内の他のドメインコントローラーに対して認証しているユーザーの日付が最新ではありません。最新のタイムスタンプを取得するには、各ユーザーのローカルDCに照会する必要がありますが、手間がかかってあまり効率的ではありません。

単一のアカウントについて、この情報を取得するコードは簡単です。

get-aduser Michael_Kanakos -properties LastLogonDate | Select-Object Name, LastLogonDate

Name     LastLogonDate
----     -------------
mkanakos 11/11/2019 9:08:45 PM

すべてのユーザーに対してこれを行うには、フィルタを使用する必要があります。

Get-ADUser -filter * -properties LastLogonDate | Select-Object Name, LastLogonDate

ログオン情報の日付が90日以前より古いアカウントのみを検索しましょう。比較演算子として使用するには、比較対象となる日付を変数に保存する必要があります。

$date = (get-date).AddDays(-90)
Get-ADUser -Filter {LastLogonDate -lt $date} -properties LastLogonDate | Select-Object Name, LastLogonDate

90日以上ログオンしていないすべてのユーザーを検出するコードは次のようになります。ADフィルタを作成して、変数保存した90日前の日付未満(その日付に達していない、つまりその日付より前)のログオンを検索するようにします。また、有効(enabled)なアカウントのみを照会する要件を追加する必要があります。この例では、構文が非常に長いため、コードを読みやすくするためにスプラッティングを使用しています。ADコマンドレットのスプラッティングはトリッキーかもしれないので、スプラッティングの例の下に長い形式の構文も示しました。

$date = (get-date).AddDays(-90)

$paramhash = @{
    Filter =        "LastLogonDate -lt $date -and Enabled -eq $true"
    Properties =    'LastLogonDate'
}

$SelectProps =            'Name','LastLogonDate','Enabled','DistinguishedName'

$InactiveUsers = Get-Aduser @paramhash | Select-Object $SelectProps

$InactiveUsers = Get-ADUser -Filter {LastLogonDate -lt $date -and Enabled -eq $true} -properties LastLogonDate, DistinguishedName | Select-Object Name, LastLogonDate, Enabled, DistinguishedName

これで、有効になっているのにアクティブでないユーザーを見つけることができます。DistinguishedName プロパティが必要になるので、再利用のために結果を変数に保存します。次のステップは、アクティブでないユーザーのアカウントを無効化することです。Set-ADUser コマンドレットを使用して、ADユーザーアカウントを変更します。

$Today = Get-Date
$DisabledUsers = (
    $InactiveUsers | Foreach-object {
        Set-User $_.DistinguishedName -Enabled $false -Description "Acct disabled on $Today via Inactive Users script"}
    )

上記のコードで、有効になっているのにアクティブでないユーザーアカウントを無効にすることができます。無効になったユーザーアカウントを新しい OU に移動します。この例では、Disabled-Users という名前の OU を使用します。この OU の識別名は「OU = Disabled-Users,DC=Contoso,DC=Com」です。Move-ADObject コマンドレットを使用して、ユーザーアカウントをターゲットOUに移動します。

$DisabledUsers | ForEach-Object {
    Move-ADObject $_.DistinguishedName -TargetPath "OU=Disabled-Users,DC=Contoso,DC=Com"}

最後のステップとして、Move-ADObject を使用してユーザーアカウントを新しい OU に移動し、信頼性の高い反復可能な自動化タスクを作成するために必要なコアコードが作成できました。ここまでできたら、次は個々の要件に応じてどう設定するかを検討します。このコードは、毎月同じ時間に自動的に実行されるように設定でき、またそれが推奨されます。そのための簡単な方法の1つは、毎月実行するよう、スケジュールされたジョブを作成することです。

このコードには、エラーチェック用のコードを追加したり、もう少し詳しいユーザー情報のフィールドを加えたりすることも可能です。こういったタイプのタスクを実行する部門では、たいてい、どれが無効になったのかをチェックできるようレポートを作成するので、レポート作成用にチェックしたいフィールドを Active Directory から取り出して追加することは有意義でしょう。また、もう一歩進んで、無効になったユーザーに関して特に問題がなければ6か月後にはそれを削除する別のタスクを作成するといったことも考えられます。

タスクを管理しやすい部分に分割すると、込み入った自動化タスクも比較的簡単に構築できます。要件から始め、ステップを踏んで(別の変数を追加する前に、各ステップが機能することを確認し)、少しずつコード作成を進めてきました。このような説明方法が読者の方々の理解を助け、わかりやすいレクチャーになっているといいのですが。

 

関連ブログ


Comments
Comments are disabled in preview mode.
Loading animation