3

hopefully somebody can troubleshoot a simple piece of code that I've been messing around with. I'll open by stating I am NOT a coder and never really done much powershell.

The issue is that at first, this was working, returning the LastLogonTimeStamp as expected.

Now when I run it I get no output in this column at all.

I'm pretty sure it's something stupid I'm overlooking but I cant figure it out.

Like I said - I've literally no experience at this - I don't know what half the code means.

Could anybody please help me out?

    # Script to list member of VDI Desktop Users Group
    # and export details to c:\VDIlastlogon.csv file
    # Rob@x.com 24/11/14'

    # Function get-NestedMembers
    # List the members of a group including all nested members of subgroups

    Import-Module ActiveDirectory

    function get-NestedMembers ($group){
      if ($group.objectclass[1] -eq 'group') {
    write-verbose "Group $($group.cn)"
        $Group.member |% {
          $de = new-object directoryservices.directoryentry("LDAP://$_")
          if ($de.objectclass[1] -eq 'group') {
    get-NestedMembers $de
  }
  Else {
    $de
          }
        }
      }
      Else {
        Throw "$group is not a group"
      }
    }

    # get a group

    $group = new-object directoryservices.directoryentry("LDAP://CN=VDI Desktop Users,ou=Groups,ou=x,ou=uk,dc=uk,dc=x,dc=com")

    # Get all nested members and send to CSV file

    get-NestedMembers $group|FT @{l="First Name";e={$_.givenName}},@{l="Last Name";e={$_.sn}},@{l="Last Logon";e={[datetime]::FromFileTime($_.ConvertLargeItegerToInt64($_.lastLogonTimestamp[0]))}},sAMAccountName | tee c:\VDILastLogon.csv

    #Send CSV file to mail recipient

    $PSEmailServer = "mail.x.net"
    $smtpServer = "mail.x.net"
    $file = "c:\VDILastLogon.csv"
    $att = new-object Net.Mail.Attachment($file)
    $msg = new-object Net.Mail.MailMessage
    $smtp = new-object Net.Mail.SmtpClient ($smtpServer)
    $msg.From = "x@x.com"
    $msg.To.Add("x@x.com")
    $msg.Subject = "User logon report from VDI Solution"
    $msg.Body = "Please find attached the most recent user logon report"
    $msg.Attachments.Add($att)
    $smtp.Send($msg)
    $att.Dispose()
  • 1
    Just as an aside, if you "don't know what half the code means" then I'd presume you got the code from someone else's script online, and as such it would be kind to at least cite them as a co-author on the script. It's no law, but nice to be recognized for your efforts. – TheCleaner Nov 24 '14 at 15:23
  • Absolutely it was taken from online but I've been through that many scripts this morning to get this far I couldn't tell you which one it was from - It's a few different scripts and articles cobbled together with minimal knowledge. – Rob B Nov 24 '14 at 15:40
  • 1
    ...just found the script - there appears to be no author to give credit to so it is not possible to do so. Apologies. – Rob B Nov 24 '14 at 16:04
  • No worries here...it was more for the community at large to see, wasn't trying to call you out specifically on this. – TheCleaner Nov 24 '14 at 16:11
  • Now when I run it I get no output in this column at all. - Are you running it in the same security context? Did you perhaps forget to start your powershell session as a Domain Admin or something? – Zoredache Nov 24 '14 at 20:41
2

If you import the AD powershell module you shouldn't need to use extra directoryservices objects (at least not on this occasion). You can use the Get-ADGroupMember cmdlet with -Resursive and it should find your nested users also.

Edit: I added -Server arguments to the AD cmdlets so you can specify particular DCs. Timestamp attributes may differ (they do across my 12 DCs as well). Check this blog for a decent writeup.

This gets the last logon time and is a bit easier to read:

$groupname = "name_of_AD_group"

Import-Module ActiveDirectory

Get-ADDomainController -Filter * | % {
   $DC = $_
   $group = Get-ADGroup -Identity $groupname -Server $DC.Name -ErrorAction SilentlyContinue
   If ($group) {
      $members = Get-ADGroupMember -Identity $group.Name -Recursive -Server $DC.Name -ErrorAction SilentlyContinue
      ForEach ($member In $members) {
         If (-not $member.objectClass -ieq "user") { Continue }
         $user = Get-ADUser $member.SamAccountName -Server $DC.Name -ErrorAction SilentlyContinue
         If ($user) {
            $lastlogon = ($user | Get-ADObject -Properties lastLogon).LastLogon
            New-Object PSObject -Property @{
               "First Name" = $user.GivenName
               "Last Name"  = $user.Surname
               "DC"         = $DC.Name
               "Last Logon" = [DateTime]::FromFileTime($lastlogon)
               "SamAccountName" = $user.SamAccountName
            }
         } Else {
            # $user not found on $DC
         }
      }
   } Else {
      # $groupname not found on $DC
   }
} | ft -auto
| improve this answer | |
  • This script works well also - however the results are somewhat erronious. Is this searching just one DC? I have literally just logged on to the domain with my user account and this report still states that my last logon was some months ago. This report is going externally to a customer and as such it needs to be accurate. Any assistance gladly appreciated. Rob. – Rob B Nov 25 '14 at 15:00
  • Hi there - still having issues with this. Whilst the screen output is great now the CSV output is garbled. At the end of the |ft -auto I simply added | export-csv c:\lastlogon.csv I'm aware of convertTo-csv but I'm not sure how to use it to get the excellent results displayed on screen to a CSV file. Any assistance? Many thanks, Rob. – Rob B Nov 27 '14 at 11:12
  • Hi Rob, export-csv c:\lastlogon.csv is correct. However you should replace ft -auto instead of adding after it. – xXhRQ8sD2L7Z Nov 27 '14 at 22:04
  • That, my friend is absolutely fantastic. I cannot thank you enough for your assistance. Now I just need to work on a way to filter all of that data to just give me the most recent logon but I figure there will be a simpler way in Excel to do so unless you know otherwise! Really, really grateful for you spending your time to help me. Cheers. Rob. – Rob B Nov 28 '14 at 9:44
1

This is a hack but it works. Grabbed the Get-ADUserLastLogon from a Microsoft Article (http://technet.microsoft.com/en-us/library/dd378867%28v=ws.10%29.aspx)

Import-Module ActiveDirectory
function Get-ADUserLastLogon([string]$userName)
{
  $dcs = Get-ADDomainController -Filter {Name -like "*"}
  $time = 0
  foreach($dc in $dcs)
  { 
    $hostname = $dc.HostName
    $user = Get-ADUser $userName | Get-ADObject -Properties lastLogon 
    if($user.LastLogon -gt $time) 
    {
      $time = $user.LastLogon
    }
  }
  $dt = [DateTime]::FromFileTime($time)
  return $dt 
}

function get-NestedMembers ($group){
  if ($group.objectclass[1] -eq 'group') {
write-verbose "Group $($group.cn)"
    $Group.member |% {
      $de = new-object directoryservices.directoryentry("LDAP://$_")
      if ($de.objectclass[1] -eq 'group') {
get-NestedMembers $de
  }
  Else {
$de
      }
    }
  }
  Else {
    Throw "$group is not a group"
  }
}

# get a group

$group = new-object directoryservices.directoryentry("LDAP://CN=Domain Users,CN=Users,DC=yourdomain,DC=com")
# Get all nested members and send to CSV file
get-NestedMembers $group|FT @{l="First Name";e={$_.givenName}},@{l="Last Name";e={$_.sn}},@{l="Last Logon";e={Get-ADUserLastLogon($_.sAMAccountName)}},sAMAccountName | tee c:\VDILastLogon.csv
| improve this answer | |
  • This worked brilliantly thank you. I'm currently teeing the output to csv but not getting the output in a CSV format (I could do with the output being in CSV). Currently it all resides in one column. Is there a simple way to do so? Many thanks. Rob. – Rob B Nov 25 '14 at 10:34
  • One thing that I don't understand about the Get-ADUserLastLogon function... (and I looked at the original page and have the same issue) I see where it sets $hostname, but it's never used, so I think the Get-ADObject doesn't necessarily connect to all of the DCs... I think it (Get-ADObject) needs -Server $hostname as a parameter – Hunter Eidson Nov 25 '14 at 21:32
  • Take a look at either ConvertTo-Csv to insert in the pipe before tee, or Export-Csv to replace the tee and just write the CSV file. – Hunter Eidson Nov 25 '14 at 21:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.