测量Windows 7用户login时间

我已经被客户要求计算机器和用户的平均login时间。 到目前为止,我发现事件logging了一些需要比在以下位置find的密钥设置的阈值更长的引导:

HKLM\Software\Microsoft\Windows\CurrentVersion\Diagnostics\Performance\Boot

但键似乎被locking,所以我不能编辑它们来降低阈值以确保每次启动的logging。 有什么方法可以find每个日志的login时间,这足以告诉用户正在login并可能获得更详细的信息,这还需要足够轻以便在每次login时运行并且不会对用户造成明显的影响。

最近我被要求做一个非常类似的事情,但包括启动和login时间,并允许历史参考。 所以下面的powershell脚本会做到以下几点:

  1. 抓住一些环境variables
  2. 获取4个不同事件日志条目的时间\date戳记。 第二和第四是不准确的测量,但经过相当广泛的研究,故障排除和testing,他们是非常接近,从我所看到的,最好的select。
  3. 计算这4个事件之间的差异
  4. 将所有数字填充到一个简单的SQL表中[你可以适应将数字转换成任何你想要的东西]

因此,如果您有SCCM(不在login期间以便根本不改变login),脚本可以通过计划任务运行,也可以按照某个时间表运行。 好的是,你可以改变PC的名称来运行它从你自己的PC,并从远程计算机(尽pipe用户名将显示为您自己的)数据进行故障排除和validation数据。

我又走了一步,使用SharePoint创build了一个外部数据列表(使用BCS),以便他们拥有一个很好的前端GUI。 下面的脚本中,我写了大部分注释行:

 $USER = $env:username.ToUpper() $COMPUTER = $env:computername.ToUpper() $Current_Time = Get-Date $PCname = '' $addedtime = 0 #1. get event time of last OS load $filterXML = @' <QueryList> <Query Id="0" Path="System"> <Select Path="System">*[System[Provider[@Name='Microsoft-Windows-Kernel-General'] and (Level=4 or Level=0) and (EventID=12)]]</Select> </Query> </QueryList> '@ $OSLoadTime=(Get-WinEvent -ComputerName $PCname -MaxEvents 1 -FilterXml $filterXML).timecreated #Write-Host $PCname #Write-Host "1. Last System Boot @ " $OSLoadTime #2. Get event time of Time-Service [pre-Ctrl+Alt-Del] after latest OS load $filterXML = @' <QueryList> <Query Id="0" Path="System"> <Select Path="System">*[System[Provider[@Name='Microsoft-Windows-Time-Service'] and (Level=4 or Level=0) and (EventID=35)]]</Select> </Query> </QueryList> '@ $CtrlAltDelTime=(Get-WinEvent -ComputerName $PCname -MaxEvents 1 -FilterXml $filterXML).timecreated #Write-Host "2. Time-sync after Boot @ " $CtrlAltDelTime #get minutes (rounded to 1 decimal) between OS load time and 1st load of GPOs $BootDuration = "{0:N1}" -f ((($CtrlAltDelTime - $OSLoadTime).TotalSeconds + $addedtime)/60) #3. get event time of 1st successful logon $filterXML = @' <QueryList> <Query Id="0" Path="System"> <Select Path="System">*[System[Provider[@Name='Microsoft-Windows-Winlogon'] and (Level=4 or Level=0) and (EventID=7001)]]</Select> </Query> </QueryList> '@ $LogonDateTime=(Get-WinEvent -ComputerName $PCname -MaxEvents 1 -FilterXml $filterXML -ErrorAction SilentlyContinue).timecreated If ($LogonDateTime) { #Write-Host "3. Successful Logon @ " $LogonDateTime } Else { #Write-Host "Duration of Bootup = " $BootDuration "minutes" -foregroundcolor blue -BackgroundColor white #Write-Host $PCname "has not logged back in." -foregroundcolor red -BackgroundColor white Exit } #Write-Host "Duration of Bootup = " $BootDuration "minutes" -foregroundcolor blue -BackgroundColor white #4. Get Win License validated after logon (about same time as explorer loads) $filterXML = @' <QueryList> <Query Id="0" Path="Application"> <Select Path="Application">*[System[Provider[@Name='Microsoft-Windows-Winlogon'] and (Level=4 or Level=0) and (EventID=4101)]]</Select> </Query> </QueryList> '@ $DesktopTime=(Get-WinEvent -ComputerName $PCname -MaxEvents 1 -FilterXml $filterXML).timecreated $LogonDuration = "{0:N1}" -f ((($DesktopTime - $LogonDateTime).TotalSeconds + $addedtime)/60) #Write-Host "4. WinLicVal after Logon @ " $DesktopTime #Write-Host "Duration of Logon = " $LogonDuration "minutes" -foregroundcolor blue -BackgroundColor white #START SQL Injection Section [void][reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") $sqlServer = "SQLserver01" $dbName = "BootUpTimes" $tbl = "tblBootUpTimes" #$srv = New-Object Microsoft.SqlServer.Management.Smo.Server $sqlServer #$db = $srv.databases[$dbName] #$conn = New-Object System.Data.SqlClient.SqlConnection("Data Source=$sqlServer;Initial Catalog=$dbName; Integrated Security=SSPI") $conn = New-Object System.Data.SqlClient.SqlConnection("server=$sqlServer;database=$dbName;Password=plaintext;User Id=BootUpTimes") $conn.Open() $cmd = $conn.CreateCommand() $cmd.CommandText = "INSERT INTO $tbl VALUES ('$Current_Time','$USER','$COMPUTER','$OSLoadTime','$CtrlAltDelTime','$BootDuration','$LogonDateTime','$DesktopTime','$LogonDuration')" Try { $null = $cmd.ExecuteNonQuery() } Catch { } $conn.Close() 

在最后一个SQL部分中,有几行提供了另外一个方法(基于安全性),可以input到SQL,而不需要明文密码。

我不知道为什么有人会认为一个脚本会帮助你确定login时间(毕竟你不能运行脚本,直到有人login,拉时间不会有帮助,因为时间漂移肯定会导致误报 – 这也是在开始处理之前不会被修复,我build议你使用的工具是性能工具包中的xperf工具,你需要查看总login时间的explorerinit时间,参见Windows On / Off Transition Performance Analysis从启动到桌面会发生什么,请参阅Windows性能分析工具以从适当位置获取xperf和xbootmgr。

https://superuser.com/questions/250267/how-to-diagnose-slow-booting-or-logon-in-windows-7

此线程使用Windows性能分析工具显示“Microsoft”启动诊断方式

有关“开/关转换性能”(又称打开或closuresWindows)的非常好的文档化程序: http : //msdn.microsoft.com/en-us/windows/hardware/gg463386.aspx

使用这些官方工具,您可以为您的客户提供一个权威的答案。 在我看来,远远优于尝试使用脚本。 如果您的需求是基本的,可能会稍微矫枉过正。

也从这个线索不要错过Soluto的网站,如果你的需求是非常基本的:)

下面的batch file作为login脚本执行会告诉你从authentication到准备好的shell需要多长时间。

 set logfile=\\server\share\%computername%-%username%.log net user /domain %username% | find /I "Last logon" > %logfile% net time %logonserver% >> %logfile% 

我没有testing过这个,我做了一些假设。

  1. net user返回的login时间是DC执行authentication的时间。 我相信是这样的,但是找不到具体的东西来支撑起来。
  2. login脚本在用户shell加载时运行。 当然,如果您使用旧的NT4login脚本,而不是由组策略定义的login脚本,但是由于GPOlogin脚本对用户隐藏(默认情况下),所以我从来没有见过什么时候他们被执行。
  3. 您的用户名不包含空格,如果是这种情况,您可能需要将%username%放在引号中。
  4. 你有一个世界可写共享的数据将被logging( \\server\share在上面的例子中)。 您可以在个别机器上本地login,但是这会使得难以检查结果。

编辑:

我已经更新了脚本来处理Jim所关心的时间漂移​​。 net use命令的login开始时间取自authentication域控制器的时钟。 net time命令现在也需要从同一台服务器的时间。