Windows 2003ドメインコントローラの「セキュリティ」イベントログに、イベント540のいくつかのエントリが表示されます。「成功したネットワークログオン」は、1日平均数分間隔です。
特定の日の特定のユーザーのこれらの最初の1つは、必ずしもユーザーが自分のマシンにログインした時間ですか?
そうでない場合(またはそうである場合でも)、ユーザーが朝にログインした時間を確認する別の(より良い?)方法はありますか?
特定のクライアントコンピューターで対話型ログオンを探している場合は、そのクライアントコンピューターでの長いイベントを探す必要があります。たとえば、キャッシュされた資格情報を使用してログオンするユーザーは、ドメインコントローラーのイベントログにエントリを作成しません。キャッシュされた資格情報を持つログオンを探していない場合でも、ログオンイベントを監査するようにクライアントコンピューターを構成し、クライアントコンピューターのイベントログを調べると、情報が最も正確で最も簡単に見つかります。
ユーザーが現在ログインしているマシンがわかっている場合は、Sysinternals Suiteの psloggedon を試してください。
Last-Logon-TimestampというADユーザーオブジェクトの属性があります。これは、ユーザーがログインするたびに更新されますが、死んだアカウントの検索に使用することを目的としているため、14日ごとにしか複製されません。ドメイン内の各DCをポーリングしてこの情報を取得する場合に、より正確なカウンターとして使用できます。そこから、ユーザーがいつドメインに認証されたかを追跡できます。朝だけでなく、起こります。
タイトルから最初の質問「ドメインユーザーがログインした時間を確認する方法」は、ユーザーがログインしているプラットフォームによって異なります。 Windows 2000/XP/2003の場合、ログオンタイプ2のイベントID 528は、ローカルまたはドメインアカウントからの対話型ログオンを示します。 LogParserは、多数のマシンからのイベントログを解析する優れたツールであり、多数の出力をサポートしています。したがって、たとえば、次のコマンドを使用して、リモートマシンのセキュリティログをクエリし、タブ区切りファイルに出力できます。
c:>logparser.exe "select TimeGenerated, SID from \\wksname\Security where EventID = 528" -i EVT -resolveSIDs:ON -q:ON -headers:off -o:TSV >> c:\UserLogons.txt
Windows Vista/2008/7のセキュリティログからのイベントのクエリは、ログファイルの形式とイベントIDが変更されている点で少し異なります。ログオンタイプ2のイベントID 4624は、成功したインタラクティブログインを示します。 wevtutil を使用して同様のデータをクエリし、XML形式で出力できます。
c:>wevtutil qe Security /q:"*[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and Task=12544 and (EventID=4624)] and EventData[Data[@Name='LogonType']='2']]" /e:Events > c:\UserLogons.xml
ドメインコントローラのセキュリティイベントログにイベントID 540が表示されることを確認するには、次のようにします。
イベント540は、いくつかの理由で記録されます。したがって、たとえば、サーバーサービスが共有リソースにアクセスすると、ログオンタイプ3のイベントID 540が表示されます。 Microsoftが提供するこのイベントIDのログオンタイプは次のとおりです。
2インタラクティブユーザーがコンソールでこのコンピュータにログオンしました。
3ネットワークユーザーまたはコンピューターがネットワークからこのコンピューターにログオンしています。
4バッチバッチログオンタイプはバッチサーバーによって使用され、ユーザーの直接的な介入なしにユーザーの代わりにプロセスが実行される可能性があります。
5サービスサービスはサービスコントロールマネージャーによって開始されました。
7ロック解除このワークステーションはロック解除されました。
8 NetworkCleartextユーザーがネットワークにログオンしました。ユーザーのパスワードは、ハッシュされていない形式で認証パッケージに渡されました。組み込み認証は、すべてのハッシュ資格情報をパッケージ化してから、ネットワーク経由で送信します。資格情報は、プレーンテキスト(クリアテキストとも呼ばれます)でネットワークを通過しません。
9 NewCredentials呼び出し元は、現在のトークンを複製し、発信接続の新しい資格情報を指定しました。新しいログオンセッションのローカルIDは同じですが、他のネットワーク接続では異なる資格情報を使用します。
10 RemoteInteractiveターミナルサービスまたはリモートデスクトップ接続を使用して、このコンピューターにリモートでログオンしたユーザー。
11 CachedInteractiveユーザーは、コンピューターにローカルに保存されたネットワーク資格情報を使用してこのコンピューターにログオンしました。資格情報を確認するためにドメインコントローラーに接続していません。
ハッピーハンティング。
ログオンスクリプトで、タイムスタンプをファイルのどこかに書き込む行を作成できますか?
何かのようなもの?
正味時間>>\server\logonlogs \%username%.txt
長い投稿の謝罪ですが、これは私が使用するものです。あなたはおそらくこれを少し合理化することができます:
' **********************************************************************
' AuditUsers
' ==========
'
' UserAccountControl
' SCRIPT 0x0001 1
' ACCOUNTDISABLE 0x0002 2
' HOMEDIR_REQUIRED 0x0008 8
' LOCKOUT 0x0010 16
' PASSWD_NOTREQD 0x0020 32
' PASSWD_CANT_CHANGE 0x0040 64
' ENCRYPTED_TEXT_PWD_ALLOWED 0x0080 128
' TEMP_DUPLICATE_ACCOUNT 0x0100 256
' NORMAL_ACCOUNT 0x0200 512
' INTERDOMAIN_TRUST_ACCOUNT 0x0800 2048
' WORKSTATION_TRUST_ACCOUNT 0x1000 4096
' SERVER_TRUST_ACCOUNT 0x2000 8192
' DONT_EXPIRE_PASSWORD 0x10000 65536
' MNS_LOGON_ACCOUNT 0x20000 131072
' SMARTCARD_REQUIRED 0x40000 262144
' TRUSTED_FOR_DELEGATION 0x80000 524288
' NOT_DELEGATED 0x100000 1048576
' USE_DES_KEY_ONLY 0x200000 2097152
' DONT_REQ_PREAUTH 0x400000 4194304
' PASSWORD_EXPIRED 0x800000 8388608
' TRUSTED_TO_AUTH_FOR_DELEGATION 0x1000000 16777216
'
' objUser.get("userAccountControl")
' **********************************************************************
option explicit
' *** Global constants
const HKEY_CLASSES_ROOT = &H80000000
const HKEY_CURRENT_USER = &H80000001
const HKEY_LOCAL_MACHINE = &H80000002
const HKEY_USERS = &H80000003
const HKEY_CURRENT_CONFIG = &H80000005
const REG_SZ = 1
const REG_EXPAND_SZ = 2
const REG_BINARY = 3
const REG_DWORD = 4
const REG_MULTI_SZ = 7
' *** User account status flags
const SCRIPT = &H0001
const ACCOUNTDISABLE = &H0002
const HOMEDIR_REQUIRED = &H0008
const LOCKOUT = &H0010
const PASSWD_NOTREQD = &H0020
const PASSWD_CANT_CHANGE = &H0040
const ENCRYPTED_TEXT_PWD_ALLOWED = &H0080
const TEMP_DUPLICATE_ACCOUNT = &H0100
const NORMAL_ACCOUNT = &H0200
const INTERDOMAIN_TRUST_ACCOUNT = &H0800
const WORKSTATION_TRUST_ACCOUNT = &H1000
const SERVER_TRUST_ACCOUNT = &H2000
const DONT_EXPIRE_PASSWORD = &H10000
const MNS_LOGON_ACCOUNT = &H20000
const SMARTCARD_REQUIRED = &H40000
const TRUSTED_FOR_DELEGATION = &H80000
const NOT_DELEGATED = &H100000
const USE_DES_KEY_ONLY = &H200000
const DONT_REQ_PREAUTH = &H400000
const PASSWORD_EXPIRED = &H800000
const TRUSTED_TO_AUTH_FOR_DELEGATION = &H1000000
dim wsh_Shell, wsh_env, domain_name, server_name
dim initial_ou, computer, last_logon, i
dim users(4, 1000) ' 0 = username, 1 = display_name, 2 = is_disabled, 3 = lastlogon_date, 4 = group membership
dim num_users
const MAX_USERS = 1000
wscript.echo "Audit users started at " & formatdatetime(now(), 0)
' *** Get the domain name
set wsh_Shell = Wscript.CreateObject("Wscript.Shell")
set wsh_env = wsh_Shell.Environment("PROCESS")
domain_name = wsh_env("USERDNSDOMAIN")
server_name = wsh_env("COMPUTERNAME")
set wsh_env = nothing
set wsh_Shell = nothing
' *** Open the Computers container
domain_name = split(domain_name, ".")
initial_ou = "LDAP://DC=" & domain_name(0)
for i = 1 to ubound(domain_name)
initial_ou = initial_ou & ",DC=" & domain_name(i)
next
wscript.echo "Checking domain " & initial_ou
' *** Find all users
set initial_ou = GetObject(initial_ou)
num_users = 0
FindAllUsers initial_ou
' *** Post the data
for i = 0 to num_users-1
wscript.echo users(0, i) & "," & users(1, i) & "," & users(2, i) & "," & users(3, i) & "," & users(4, i)
next
' *** All done
wscript.echo "Audit users finished at " & formatdatetime(now(), 0)
set initial_ou = nothing
wscript.quit 0
' **********************************************************************
' FindAllUsers
' ------------
' **********************************************************************
sub FindAllUsers(fau_OU)
dim ou_name, user, user_dn, display_name, lastlogon_date
dim ldap_user, group_array, i
ou_name = fau_OU.distinguishedName
' *** First list users in this OU
for each user in fau_OU
if lcase(user.class) = "user" then
user_dn = "LDAP://CN=" & user.displayName & "," & ou_name
' *** Check we haven't found too many users
if num_users >= MAX_USERS then
wscript.echo "WARNING: exceeded maximum number of users - " & cstr(MAX_USERS)
exit for
end if
' *** New user
users(0, num_users) = lcase(user.samAccountName)
' *** Get the display name; error trap this because it can fail
users(1, num_users) = ""
on error resume next
err = 0
display_name = user.get("displayName")
if err = 0 then users(1, num_users) = display_name
on error goto 0
' *** Get the enabled/disabled status
users(2, num_users) = user.get("UserAccountControl") and ACCOUNTDISABLE
if users(2, num_users) = 0 then
users(2, num_users) = "0"
else
users(2, num_users) = "1"
end if
' *** Get the last logon date; this may fail so trap errors
lastlogon_date = 0
on error resume next
set lastlogon_date = user.get("lastLogon")
if err = 0 then
if not isempty(lastlogon_date) then
lastlogon_date = LongTimeToDate(lastlogon_date)
if lastlogon_date < 0 then lastlogon_date = 0
end if
end if
on error goto 0
users(3, num_users) = formatdatetime(lastlogon_date, 0)
' *** Get the group membership
users(4, num_users) = ""
on error resume next
err = 0
set ldap_user = GetObject(user_dn)
if err = 0 then
on error goto 0
group_array = ldap_user.MemberOf
if not isempty(group_array) then
if TypeName(group_array) = "String" then
users(4, num_users) = group_array
else
for i = lbound(group_array) to ubound(group_array)
if users(4, num_users) <> "" then users(4, num_users) = users(4, num_users) & ";"
users(4, num_users) = users(4, num_users) & TrimGroupName(group_array(i))
next
end if
end if
set ldap_user = nothing
end if
on error goto 0
' *** Finished with this user
num_users = num_users + 1
end if
next
' *** Now recurse into subcontainers
for each user in fau_OU
if lcase(user.class) = "organizationalunit" or lcase(user.class) = "container" then
FindAllUsers user
end if
next
' *** All done
end sub
' **********************************************************************
' TrimGroupName
' -------------
' Turn the distinguished name into a simply group name
' **********************************************************************
function TrimGroupName(tgn_FullName)
dim group_name, len_group, c
TrimGroupName = ""
group_name = ""
len_group = len(tgn_FullName)
if len_group < 4 then exit function
for i = 4 to len_group
c = mid(tgn_FullName, i, 1)
if c = "," then exit for
group_name = group_name + c
next
group_name = lcase(group_name)
TrimGroupName = group_name
end function
' **********************************************************************
' LongTimeToDate
' --------------
' Convert the ADSI longint timestamp to a VBScript format date
' **********************************************************************
function LongTimeToDate(lt_Time)
dim ltdate
ltdate = lt_Time.HighPart * (2^32) + lt_Time.LowPart
ltdate = ltdate / (60 * 10000000)
ltdate = ltdate / 1440
ltdate = ltdate + #1/1/1601#
LongTimeToDate = ltdate
end function
JR
セキュリティログを確認する必要がない場合は、アカウントロックアウトおよび管理ツール (link) を試すこともできます。これにより、「最終ログオン時間」を含むADUCのアカウント詳細に追加のプロパティページが追加されます。
あなたの質問とは関係ありませんが、それらのイベントを除外しないのはなぜですか。これらのレベルのイベントが返された場合は気にしないでください。重大度が3以上のエラーは、時間を無駄にしないでください。