Active Directoryの最終ログイン日時が知りたい
普段の業務にて
Active Directory に関連する業務の中で、よくある要望の一つとしてユーザーアカウントの最終ログイン日時を調べて欲しいというものがある。
Active Directory 関連の情報は Power Shell にて抽出することができる。
PowerShellにてActive Directory のユーザー情報を出力する
以下のコマンドにてユーザー情報を取得することができる。
# ActiveDirectory関連のモジュールを読み込みする PS C:\> Import-Module ActiveDirectory ~ 中略 ~ # ユーザー情報を取得する PS C:\> Get-ADUser -Properties * -Filter * ~ 実行結果 ~
 Power Shellにて取得したユーザー情報のログインに関連する属性として 【LastLogon】と【LastLogonTimeStamp】という2つの属性が存在する。
      (ドメインの機能レベルが Windows Server 2003) 
ここで落とし穴が・・・
 Active Directory のドメインコントローラーを複数台にて運用している場合、【LastLogon】属性はユーザーがログインに使用したドメインコントローラーにのみ記録される。 
      他のドメインコントローラーには記録されないし情報がレプリケートされることもないので注意が必要である。 
 もう一つの属性として【LastLogonTimeStamp】があり、こちらはドメインコントローラーを複数運用している場合においても情報がレプリケートされる。
      但し、レプリケートされるのに最大で14日のタイムラグが発生するようである。 
      これはログインする度にレプリケートするとサーバーに必要以上に負荷がかかるとの配慮のようである。 
LastLogon属性とLastLogonTimeStamp属性の纏め
| 属 性 | 説 明 | 
|---|---|
| LastLogon | ユーザーがログインに使用したドメインコントローラーにのみ記録される。  他のドメインコントローラーには記録されないし情報がレプリケートされることもない。  | 
          
| LastLogonTimeStamp |  ドメインコントローラー間にてレプリケートされるが、最大で14日のタイムラグが発生する。  また、保存される値はNTタイムエポック値の為、人間が理解するためには日付形式の文字列へ変換する必要がある。  | 
          
NTタイムエポック値
 もう一点、【LastLogonTimeStamp】属性にはNTタイムエポック値という値で記録される。
      NTタイムエポック値とは、1601/01/01 00:00:00 から100ナノ秒単位のカウント値である。 
日時:【2016/2/18 10:35:03】は NTタイムエポック値で表すと【131002329039401000】という18桁の整数となる。
関連記事
ActiveDirectory関連のPowerShellについてはこちらで記事にしています。
【LastLogonTimeStamp】属性については、マイクロソフトが運営するブログにて詳しく説明されていますのでそちらを参照してください。
- chevron_right 最後に対話ログオンを行った日時を知りたいlaunch
 - chevron_right タンポポ、ビデオデッキの時計、および最終ログオン時刻: 我々が最も苦手とするもの launch
 
NTタイムエポック値を変換する
コマンドにて変換
Power Shell にて Active Directory のユーザー情報を抽出すると。
PS C:\> Get-ADUser -Properties * -Filter * ~~~(中略)~~~ DistinguishedName : CN=staff1234,OU=ou_user,DC=testdc,DC=local Enabled : True GivenName : LastLogonTimeStamp : 131002329039401000 Name : staff1234 ObjectClass : user ObjectGUID : 5a46c14b-436f-41dc-ac36-d8b405892ef0 SamAccountName : staff1234 SID : S-1-5-21-3159277430-1725456294-2618848261-6241 Surname : staff1234 UserPrincipalName : staff1234@testdc.local ~~~(中略)~~~
 上記の例では【LastLogonTimeStamp】属性に 131002329039401000 という値が格納されている。 
      ちなみに、NTエポック値 131002329039401000 を人間が理解できる日時(文字列)に変換すると 2016/2/18 10:35:03 になる。 
NTエポック値についてはWindowsのw32tmコマンドにて、人間が理解できる文字列に変換することが出来る。
ためしに、w32tm /ntte 131002329039401000 と入力し実行すると。
C:\> w32tm /ntte 131002329039401000 151623 01:35:03.9401000 - 2016/02/18 10:35:03
エクセルのシリアル値への変換
NTタイムエポック値 131002329039401000 を変換した場合。
| 単 位 | 値 | 説 明 | 
|---|---|---|
| NTタイムエポック値 | 131002329039401000.000000000 | 1601/01/01 00:00:00 から100ナノ秒単位のカウント値 | 
| マイクロ秒 | 13100232903940100.000000000 | NTタイムエポック値 / 10 | 
| ミリ秒 | 13100232903940.100000000 | マイクロ秒 / 1000 | 
| 秒 | 13100232903.940100000 | ミリ秒 / 1000 | 
| 分 | 218337215.065668000 | 秒 / 60 | 
| 時 | 3638953.584427810 | 分 / 60 | 
| 日 | 151623.066017825 | 時 / 24 | 
| エクセルのシリアル値 | 42418.066017825 |  日 - 109205 エクセルのシリアル値 0 (1899/12/31 00:00:00)と 1600/1/1 00:00:00との差は 109205.000000000日 なので  | 
        
| エクセルのシリアル値(日本標準時) | 42418.441017825 |  エクセルのシリアル値 + 0.375 9時間 / 24時間(日) = 0.375 なので (日本標準時 = 世界標準時 + 9時間)  | 
        
| yyyy/mm/dd hh:nn:ss | 2016/02/18 10:35:03 | エクセルの書式 yyyy/mm/dd hh:mm:ss | 
計算式
       エクセルでのシリアル値 = 
      (NTタイムエポック値) / (10 * 1000 * 1000 * 60 * 60 * 24) - 109205 + 0.375 
日付からNTタイムエポック値に変換する
Power Shellと .NETのライブラリを組み合わせて変換する。
Power Shellにて下記のコマンドを実行すると。
PS C:\> ([DateTime]"1601/1/1 00:00:00").Ticks 504911232000000000
 NTタイムエポック値であれば【 0 】が得られるはずだが、大きく異るのは Windows OS のシステム時間はNTタイムエポック値(1601/1/1 00:00:00からのカウント値)で表現されるのに対し、.NET
      の世界では西暦元年(0001/1/1 00:00:00)からのカウント値になるからである。 
      つまり、知りたい日付の 【.NET Ticks 値】から 504911232000000000 を引いた値がNTタイムエポック値となる。 
2016/2/26 01:23:45 のNTタイムエポック値は?
PS C:\> ([DateTime]"2016/2/26 01:23:45").Ticks - 504911232000000000 131009234250000000
実際の業務では
Power Shell にて Active Directory のユーザー情報をCSVファイルに抽出する。
PS C:\> Get-ADUser -Properties * -Filter * | Export-CSV -Encoding UTF8 -Path C:\ADUser.csv
先程抽出したCSVファイルをエクセルにて開き、日時表示用の列を追加する。
この場合は、AM列に計算式を追加した。
