Getting Last User Logons for a Host

Where I work, we have a lab full of servers, both virtual and physical. There used to be a “booking system”, but it fell into disrepair and the information is very out-of-date. Rather than a free-for-all, I like to check who’s recently logged onto a box before using it myself. If I get a name back, I can ask them for permission. Alternatively, if I can see that it hasn’t been touched for three months, then I’m more confident that it isn’t in use.

Here’s some PowerShell I put together for scanning the security event log for logon events and displaying them. Server 2008 R2 has the very useful Get-WinEvent commandlet lacking in earlier versions. This supports native filtering; on earlier systems we have to pull all events back and then filter them (hence the much larger default maxEvents).

Windows Server 2008 R2

function Get-LastLogons([int]$maxEvents=100) {
  # We need to flip the culture thanks to a bug introduced in PowerShell 3
  # that fails to populate localisable fields in certain locales, e.g. en-GB.
  $orgCulture = Get-Culture
  [System.Threading.Thread]::CurrentThread.CurrentCulture =
    New-Object "System.Globalization.CultureInfo" "en-US"

  $events = Get-WinEvent -MaxEvents $maxEvents
                         -FilterHashtable @{logname='security'; id=4624}

  [System.Threading.Thread]::CurrentThread.CurrentCulture = $orgCulture

  $logons = @()
  foreach ($e in $events) {
    $accNamePos = $e.Message.IndexOf("Account Name:")
    $accNamePos = $e.Message.IndexOf("Account Name:", $accNamePos + 1)
    $accDomPos = $e.Message.IndexOf("Account Domain:", $accNamePos)
    $logonIdPos = $e.Message.IndexOf("Logon ID:", $accDomPos)
    $accName = $e.Message.Substring($accNamePos + 13,
                                    $accDomPos - $accNamePos - 13).Trim()
    $accDom = $e.Message.Substring($accDomPos + 15,
                                   $logonIdPos - $accDomPos - 15).Trim()
    $logon = New-Object PsObject
    $logon | Add-Member -MemberType NoteProperty
                        -Name Name -Value $accName -PassThru |
             Add-Member -MemberType NoteProperty
                        -Name Domain -Value $accDom -PassThru |
             Add-Member -MemberType NoteProperty
                        -Name Time -Value $e.TimeCreated
    $logons = $logons + $logon
  }

  $logons
}

Windows Server 2003 and Server 2008

function Get-LastLogons([int]$maxEvents=10000) {
  $events = Get-EventLog -LogName Security -Newest $maxEvents |
              Where {$_.InstanceID -eq 540 -or $_.InstanceID -eq 4624}

  $logons = @()
  foreach ($e in $events) {
    $accNamePos = $e.Message.IndexOf("Account Name:")
    $accNamePos = $e.Message.IndexOf("Account Name:", $accNamePos + 1)
    $accDomPos = $e.Message.IndexOf("Account Domain:", $accNamePos)
    $logonIdPos = $e.Message.IndexOf("Logon ID:", $accDomPos)
    $accName = $e.Message.Substring($accNamePos + 13,
                                    $accDomPos - $accNamePos - 13).Trim()
    $accDom = $e.Message.Substring($accDomPos + 15,
                                   $logonIdPos - $accDomPos - 15).Trim()
    $logon = New-Object PsObject
    $logon | Add-Member -MemberType NoteProperty
                        -Name Name -Value $accName -PassThru |
             Add-Member -MemberType NoteProperty
                        -Name Domain -Value $accDom -PassThru |
             Add-Member -MemberType NoteProperty
                        -Name Time -Value $e.TimeGenerated
    $logons = $logons + $logon
  }

  $logons
}

Calling

You can just call the relevant Get-LastLogons commandlet on your system, but this call will remove local and SYSTEM logons. For my use case, this is what I needed.

Get-LastLogons |
  where { $_.Name -ne "$($env:computername)`$" -and
          $_.Name -ne "SYSTEM" }

Download Script 

References

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>