如何在所有域控制器上优化查询以查找最新的登录日期? [英] How to optimize query across all domain controllers to find the latest logon date?

查看:54
本文介绍了如何在所有域控制器上优化查询以查找最新的登录日期?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我当前正在尝试查询域控制器以查找用户的最新登录日期.我知道我可以使用lastlogondate,但是不会像我想的那样被复制,我对此也无能为力.我尝试制作一个脚本来查询每个域控制器,并对照用户的哈希表对其进行检查,但是事实证明,查询一个DC确实很慢.我知道我可以为每个DC运行后台作业,但仍然只花一个域控制器的所有最新登录时间即可.有什么建议吗?

I'm currently trying to query the domain controllers to find the latest logon date for users. I know I can use the lastlogondate but that doesn't get replicated as often as I'd like and I have no control over the that. I tried making a script to query each domain controller and check it against a hashtable of users but this is proving to be really slow to even query one DC. I know I could run background jobs for each DC but still just going all the latest logon times for one domain controller is taking a long time. Any advice?

$dcs = Get-ADDomainController -Filter {Name -like "*"}
$users = Get-ADUser -filter * -SearchBase "OU=users,DC=com"
$outfile = "c:users.csv"
$usertable = @{}

# creating table for all users
foreach($user in $users) {
    $userobject = New-Object PSObject
    $userobject | Add-Member -MemberType NoteProperty -Name DomainController -Value "0"
    $userobject | Add-Member -MemberType NoteProperty -Name LastLogon -Value "0"

    $usertable.Add($user.SamAccountName ,$userObject)
}    # end foreach

# Method for looping through domain controllers to find last logon

foreach($dc in $dcs) {
    $hostname = $dc.HostName

    $logons = Get-ADUser -Filter * -SearchBase "OU=users,DC=com" -Property LastLogon -Server $hostname

    foreach($u in $logons) {
        $sam = $u.SamAccountName

        if($u.LastLogon -gt $usertable.$sam.LastLogon) {
            $usertable.$sam.LastLogon = $u.LastLogon
            $usertable.$sam.DomainController = $dc.HostName
            Write-Host "$sam has the latest date"
            $usertable.$sam.DomainController
        }
    }    #end inner foreach
}        #end outer domain foreach

foreach($h in $usertable.GetEnumerator()) {
    $sam = $($h.Name)
    $newdate = $($h.Value).LastLogon

    $append = "$sam,$newdate"
    $append | out-file $outfile -Encoding ascii -Force -Append
}

推荐答案

我想我已经知道了.通过测试并与我自己的类似程序进行比较,很明显,延迟处于以下循环中:

I think I've figured this out. It's very clear from testing and comparing with my own similar program that the delay is in the following loop:

foreach($u in $logons) {
    $sam = $u.SamAccountName

    if($u.LastLogon -gt $usertable.$sam.LastLogon) {
        $usertable.$sam.LastLogon = $u.LastLogon
        $usertable.$sam.DomainController = $dc.HostName
        Write-Host "$sam has the latest date"
        $usertable.$sam.DomainController
    }
} # end inner foreach

现在我的程序与您的程序不完全相同.可以对此进行清理,但是出于所有意图和目的,以下部分与上述摘录具有相同的功能:

Now my program is not exactly the same as yours. One could sanitize this, but for all intents and purposes the below segment serves the same function as the above excerpt:

# Note: the re-use of $DC...
ForEach($DC in $RDCs )
{   # Should you add any measurements here??
    Write-Host "Working on $DC : $(Get-Date -Format G) ..."
    Get-ADUser -Filter $Filter -SearchBase $SearchBase -Server $DC -Properties $AD_Props |
    ForEach-Object{
        If ( $Users.Contains( $_.samAccountName ) )
        {   # So you don't attemp when it wasn't in the root set.
            If( $_.lastlogon -gt $Users[$_.samAccountName].LastLogon )
            {
                $Users[$_.samAccountName].LastLogon = $_.lastlogon
                $Users[$_.samAccountName].DC = $DC
            }
        }
    }
}

您可以看到我使用的是 ForEach-Object 循环,而不是 ForEach 构造.但是,这还不够充分,特别是因为后者通常更快.

You can see that I'm using a ForEach-Object loop instead of the ForEach construct. However, this isn't a sufficient explanation, especially seeing as the latter is often faster.

注意:我用几种不同的方式为循环计时,并在脚本的前面解释了代码.例如,我不是以相同的方式创建对象,但是我将其排除在外.

Note: I timed your loop in several different ways and accounted for code earlier in the script. For example, I'm not creating the objects the same way, but I ruled that out as a factor.

无法弄清楚为什么您的循环会剧烈地"出现在屏幕上.慢一点,我很不情愿地将其重写为:

Not able to figure out why your loop would be "dramatically" slower I relucantly rewrote it to:

$logons |
ForEach-Object{
    If( $_.LastLogon -gt $usertable[$_.samAccountName].LastLogon )
    {
        $usertable[$_.samAccountName].LastLogon = $_.LastLogon
        $usertable[$_.samAccountName].DomainController = $hostname

但是,这似乎并没有快得多.因此,我更不情愿地尝试了此操作:

However, this didn't seem much faster if at all. So, even more reluctantly I tried it like:

Get-ADUser -Filter * -SearchBase $UsersOU -Property LastLogon -Server $hostname |    
ForEach-Object{
    If( $_.LastLogon -gt $usertable[$_.samAccountName].LastLogon )
    {
        $usertable[$_.samAccountName].LastLogon = $_.LastLogon
        $usertable[$_.samAccountName].DomainController = $hostname

    }
}

现在,我开始看到与自己的程序相似的性能.实际上,它似乎更快一些,可能是由于未检查Hash.

Now I started seeing performance similar to my own program. In fact, it seemed a little faster, probably due to not checking the Hash.

根据经验,我只能假设对象是活动的,并保持某种与源DC的连接.我以前在PowerShell社区扩展(PSCX)中曾经见过这种类型的事情,从 Get-TerminalSession 返回的对象表现出相似的行为.我可能疯了,很高兴得到纠正,并坦率地希望有人能提供更好的解释.

Based on experience I can only hypothesize that the objects are live and maintaining some kind of connection back to the source DC. I've seen this type of thing once before in the PowerShell Community Extensions (PSCX) the objects returned from Get-TerminalSession exibited similar behavior. I could be crazy, I'm happy to be corrected and frankly hoping someone has a better explanation.

我在这里还可以建议其他一些事情,但没有什么比上面的有影响力了.另请注意,我没有测试到最后,所以不能保证没有其他问题.

There are a few other things I can advise here, none as impactful as above. Please also note, I didn't test through to the end, and so can't guarantee there aren't other issues.

这篇关于如何在所有域控制器上优化查询以查找最新的登录日期?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆