Add Domain Controller to this last logon time script

Welcome Forums General PowerShell Q&A Add Domain Controller to this last logon time script

This topic contains 9 replies, has 3 voices, and was last updated by

 
Participant
1 week, 3 days ago.

  • Author
    Posts
  • #113579

    Participant
    Points: 11
    Rank: Member

    This script works and displays the name and lastlogon time,  I just need to add the domain controller to the output. The User.values does not contain the DC so I'm not sure how to add that to the output.

    
    $DCs = Get-ADDomainController -filter * | select -ExpandProperty Name
    
    $ALLUsers = ForEach ($DC in $DCs)
    
    { Get-ADUser -Filter * -properties * -Server $DC
    
    }
    
    $DCs = Get-ADDomainController -filter * | select -ExpandProperty Name
    
    $ALLUsers = ForEach ($DC in $DCs)
    
    { Get-ADUser -Filter * -properties * -Server $DC
    
    }
    
    $Users = @{}
    
    ForEach ($User in $AllUsers)
    
    {IF ($Users.ContainsKey($User.SamAccountName))
    
    {If ($Users[$User.SamAccountName].lastLogon -lt $User.lastLogon)
    
    {$Users[$User.SamAccountName].lastLogon = $User.lastLogon
    
    }
    
    }
    
    Else
    
    {$Users.Add($User.SamAccountName,($User | Select SamAccountName,Name,LastLogon))
    
    }
    
    }
    
    $Users.Values | select Name,@{Name="Last Logon Date";Expression={ If ($_.lastLogon) { [datetime]::FromFileTime($_.lastLogon) } Else { "None" }}} 
  • #113606

    Participant
    Points: 65
    Published
    Rank: Member

    Having difficulty in understanding your question, what do you mean by

    User.values does not contain the DC ?

    You can always add entries to a hashtable using .Add method or $User.NewKey = 'NewValue' and you are already doing the same here.

    • #113612

      Participant
      Points: 11
      Rank: Member

      If I look at the get members on $users.values or $AllUsers there is no DC information.

      So in the script when I select name and lastlogon and I'd like to display the domain controller that goes with the lastlogon value. Not sure how to do that.

  • #113650

    Participant
    Points: 5
    Rank: Member

    Well you go through each DC and look at each user and then store the values you want.
    So basically you will need nested foreach.

    Don't have a DC to test with but something like this should work.

    $DCs = Get-ADDomainController -filter * | select -ExpandProperty Name
    $allUsers = Get-ADUser -filter * | select SamAccountName
    
    $data = @()
    
    foreach($a in $allUsers)
    {
      foreach($d in $DCs)
      {
        $userValues = Get-ADUser $a -Server $d -properties LastLogon | select LastLogon,Name,SamAccountName
        $data += [PSCustomObject]@{Name = $userValues.Name
                                   SamAccountName = $userValues.SamAccountName
                                   LastLogon = $userValues.LastLogon
                                   DC = $d
                                  }  
      }
    }
    

    Then you can sort, extract etc. from the $data array.
    If you want you can add check during loops if the $data array already contains the user and if the LastLogon value is lower than the one you found.
    Then you don't have store everything in the $data array and sort it out later but this just a concept on how to do it.

    Note:
    If you can avoid it you shouldn't really do it because depending on the size of the domain and the number of users in the domain this is a pretty large job.
    Going through each DC and each user for each DC is to say the least costly in terms of load on the DC's. If it's a large domain I would make sure you got some approval and do it off hours.

    If you don't need a precise LastLogon time and can accept some discrepency you should use LastLogonTimeStamp.
    That attribute is replicated across the DC's and should be accurate to within a 14 day range (by default).
    E.g. if you're going to use this for e.g. "who has not logged on the last month" scenario then LastLogonTimeStamp should be enough.
    Then you only need to query one DC for all the users and grab that attribute.
    So no need to itterate through all DCs and all users.

    Edit
    If you happened to see the earlier code I noticed that it was better to switch the order of the foreach loops. To go through each user once for every DC, rather than going through each DC and then run through every user for that DC.
    Should be a bit less work but still not recommended.

  • #113656

    Participant
    Points: 5
    Rank: Member

    In terms of load on the DCs this is probably a better idea.
    But again depending on size it will require enough memory and possibly CPU on the machine the script is running on.

    $DCs = Get-ADDomainController -filter * | select -ExpandProperty Name
    
    $data = @()
    
    foreach($d in $DCs)
    {
      $allUsers = Get-ADUser -filter * -properties LastLogon -Server $d | select Name,SamAccountName,LastLogon
    
      foreach($a in $allUsers)
      {
        $data += [PSCustomObject]@{Name = $a.Name
                                   SamAccountName = $a.SamAccountName
                                   LastLogon = $a.LastLogon
                                   DC = $d
                                  }  
      }
    }
    

    This way the machine running the script will go through the list of users.
    You're still grabbing all users once for each DC but you won't be continously quering the DCs.
    It's still not the recommended way if you can avoid it 🙂

  • #113809

    Participant
    Points: 11
    Rank: Member

    Thanks. This will create duplicate users, how can I compare and keep the one with the latest login? Would I create another foreach loop on the $data table and do an if statement?

  • #113887

    Participant
    Points: 5
    Rank: Member

    Yes as I mentioned earlier you need to either run through $data again and just pick the highest version or you add it during the first run.

    E.g.

    $DCs = Get-ADDomainController -filter * | select -ExpandProperty Name
    
    $data = @()
    
    foreach($d in $DCs)
    {
      $allUsers = Get-ADUser -filter * -properties LastLogon -Server $d | select Name,SamAccountName,LastLogon
    
      foreach($a in $allUsers)
      {
        if($data.SamAccountName -contains $a.SamAccountName)
        {
          $index = $data.SamAccountName.IndexOf($a.SamAccountName)
          
          if($data[$index].LastLogon -lt $a.LastLogon)
          {
             $data[$index].LastLogon = $a.LastLogon
             $data[$index].DC = $d
          }
        }
        else
        {
          $data += [PSCustomObject]@{Name = $a.Name
                                   SamAccountName = $a.SamAccountName
                                   LastLogon = $a.LastLogon
                                   DC = $d
                                  }  
        }
      }
    }
    
  • #113914

    Participant
    Points: 11
    Rank: Member

    Thanks. I'm a beginner and I think I understand all the pieces of this except this line

    $index = $data.SamAccountName.IndexOf($a.SamAccountName)

    What is this doing?

  • #113936

    Participant
    Points: 5
    Rank: Member

    No problem, we all start somewhere.

    What it does is check which index-number in the $data array where the object with the SamAccountName matches the current SamAccountName from the foreach loop.

    In simpler terms, see the $data array as a table and you want to find the row number which contain the same SamAccountName as the current SamAccountName from the $allUsers foreach loop.

    So lets say you have an array with:

    $array = 'bob','julie','sam'

    If you then do
    $index = $array.IndexOf('julie') you will get the number 1 as the result (since arrays are 0-based).

    So later on if we want to edit 'julie' we can reference that with the number.
    So, $array[$index] = 'john' would replace 'julie' with 'john'.
    It would also be the same if we did $array[1] = 'john'

    And the reason for that "search" is because you don't know which number in the $data array the record for that user has.

  • #113965

    Participant
    Points: 5
    Rank: Member

    Just noticed an error in the last piece of code.
    The DC variable in the if-statement should be $d and not $a.DC since it doesn't exist in the $allUsers list.

    Have corrected it now.

You must be logged in to reply to this topic.