Monthly Archives: March 2013

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

Filling the Disk

I’m trying to test one my applications that installs various things onto the system. As such, there is a minimum required disk space for it to work correctly. In order to determine this threshold, I wished to simulate various low disk-space scenarios. I used the below command to create a large sparse file (i.e. not suitable as an actual data source) to fill the disk.

fsutil file createnew c:\temp\bigfile.dat <size_in_bytes>

via windows-commandline.com