2016年3月3日木曜日

【Active Directory】NTタイムエポック値 について

event_note

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についてはこちらで記事にしています。

2020年1月18日に納車したWRX STI Type S (VAB F型)の整備について記録を残していきたいと思います。

【LastLogonTimeStamp】属性については、マイクロソフトが運営するブログにて詳しく説明されていますのでそちらを参照してください。

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タイムエポック値となる。

NTタイムエポック値 = (.NET Ticks値) - 504911232000000000

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列に計算式を追加した。